Make classes this way?
Posted: Tue Apr 07, 2009 7:00 am
Often i use a a method of programming where i do the 'main object' in the first argument. Since i did this so regularly, it seemed silly. A related problem seemed to be that Lisp programs themselves didn't seem like objects.
So i tried to fix this by making a macro, i named program-to-class that (with macro hooks)recognized defvars, defparameters, and made them
into slots of a class. Recognizing defun, defmethod, defgeneric, and adding the argument that is the class (and
type declare for defun) at the start. It also recognizes defclass and defstruct. defmacro is still todo. (Except i am not going to do it anymore)
But then i noticed how defvar and defparameter work a little perculiarly; LET takes them over even when they're used in a function.
So i can do better, just by taking over global variables:An example of use:Using this would save a lot of first arguments when defining functions, but on the other hand you'll have to use class-being-vars when using it.(Hmm need shorter name) Or make something wrapping it. Another disadvantage is the overhead, of setting the slots afterwards, i am not sure how bad that is. (You can't use with-slots; it uses symbol-macrolet)
I couldn't find any library that does this. Btw cliki should have an application domain called 'macros' or something, where stuff like this, iterate, series, alexandria etc. goes. Edit: a start
So i tried to fix this by making a macro, i named program-to-class that (with macro hooks)recognized defvars, defparameters, and made them
into slots of a class. Recognizing defun, defmethod, defgeneric, and adding the argument that is the class (and
type declare for defun) at the start. It also recognizes defclass and defstruct. defmacro is still todo. (Except i am not going to do it anymore)
But then i noticed how defvar and defparameter work a little perculiarly; LET takes them over even when they're used in a function.
Code: Select all
(defparameter *meh* -1)
(defun mah ()
(print (setf- + *mah* 1)))
(let ((*mah* -5))
(mah))
Code: Select all
(defpackage #:class-var
(:use #:common-lisp #:iterate)
(:documentation "Puts all variables in a class, makes all functions have\
this class as first argument.")
(:export class-using-vars class-being-vars))
(in-package #:class-var)
(defmacro if-with (var cond true else)
`(let ((,var ,cond))
(if ,cond ,true ,else)))
(defmacro if-use (&rest conds)
(let ((var (gensym)))
`(if-with ,var ,(car conds)
,var ,(if (null (cdr conds))
(car conds)
`(if-use ,@(cdr conds))))))
;;The simple way.
(defmacro class-using-var (class-name vars &key types options)
"Makes a class with given variables."
`(defclass ,class-name ()
(,@(iter
(for v in vars)
(for tp in (if-use types types (iter (repeat (length vars))
(collect nil))))
(collect
`(,v :initform ,v :initarg ,(intern (symbol-name v) :keyword)
,@(when tp `(:type ,tp)))))
,@options)))
(defmacro class-being-vars ((instance &rest vars) &rest body)
"Lets a class take over the variables. (from defvar/defparameter)
Note that all the vars must be available as slots."
(let ((inst (gensym)))
`(let ((,inst ,instance))
(let (,@(iter (for v in vars) ;Override variables.
(collect `(,v (slot-value ,inst ',v)))))
,@body ;Do the body.
,@(iter (for v in vars) ;Write back.
(collect `(setf (slot-value ,inst ',v) ,v)))))))
Code: Select all
(use-package :class-var)
(defparameter *meh* -1)
(defparameter *mah* 1)
(class-using-var moeh (*mah* *meh*))
(defvar *inst* (make-instance 'moeh))
(defvar *inst2* (make-instance 'moeh))
(defun meh () (print (setf *meh* (+ *meh* 1))))
(defun mah () (print (setf *mah* (+ *mah* 1))))
(class-being-vars (*inst2* *mah* *meh*)
(meh) (mah))
I couldn't find any library that does this. Btw cliki should have an application domain called 'macros' or something, where stuff like this, iterate, series, alexandria etc. goes. Edit: a start