Easier to read now, thanks! For the mode I was asking about, regular p-lists are fine. But I'm planning to do another mode. In this mode I will have a general class and one subclass for each programming language, where each subclass defines what should be done in that particular language. After your description I think defclass will work best since there's inheritance involved. On Thu, Feb 5, 2009 at 3:28 AM, Pascal J. Bourguignon wrote: > > And now, translated in English: > > pjb@informatimago.com (Pascal J. Bourguignon) writes: > > > Tassilo Horn writes: > > > >> Johan Andersson writes: > >> > >> Hi Johan, > >> > >>> Then I could easy update attributes on the objects, remove and add > >>> people and then update the file. > >>> > >>> I tried with a couple of solutions for this in Lisp: > >>> > >>> 1) One list named people: > >>> ( > >>> (name age married sex) > >>> ... > >>> ) > >> > >> I think a list of plists would be quite intuitive to someone with an OO > >> background. Here's a quick and dirty snippet which should get you > >> started: > >> > >> --8<---------------cut here---------------start------------->8--- > >> (defvar persons > >> '((:name "Klaus" :age 36 :sex male) > >> (:name "Claudia" :age 31 :sex female))) > >> [...] > >> ;; Adjust the ages > >> (set-property "Klaus" :age 37) > >> (set-property "Claudia" :age 32) > > > Why not. The choice of internal representation doesn't matter. You > must be able to change the internal representation at will, depending > on the algorithms and specified performance. > > On the other hand, whether you use defstruct, defclass, a-lists, > p-lists (note that defstruct can also generate flat lists and vectors, > and in emacs lisp, eieio implements classes as vectors), you must hide > this choice behind a functional abstraction. > > The accessors generated by defstruct or defclass make up this > functional abstraction. If you choose another representation, you > will have to define yourself the needed functions. > > > There's a little difference between the accessors defined by defstruct > and defclass: the formers are normal functions, while the later are > methods on generic functions, which allows to apply them on objects of > various classes and subclasses. But if you consider only one class, > and use the same names in both cases, they'll be exchangeable. > > In your example, set-property defines a "dynamical" interface on the > slots of the object (thep-list) (and in addition encapsulate the > person "database"). In some cases it may be a good way to do it; CLOS > (and eieio) do define a similar accessor: (slot-value object field). > But this is useful more in the case of metaprogramming (eg. a > serializer/deserializer) or if there are uniform processings on > all the slots. > > In other cases, I think it's more practical to define specific > accessors, as defstruct and defclass do. Of course, if you have a lot > of slots (or "classes" of p-lists), it's worthwhile to write a macro > to generate them automatically: > > (require 'cl) > > (defun make-keyword (name) (intern (format ":%s" name))) > > > > (defmacro define-structure (name &rest fields) > `(progn > (defun* ,(intern (format "make-%s" name)) > (&key ,@fields) > (list ',name ,@(mapcan (lambda (field) > (list (make-keyword (symbol-name field)) > field)) fields))) > ;; readers > ,@(mapcar (lambda (field) > `(defun ,(intern (format "%s-%s" name field)) ; defstruct > like naming. > (object) > (getf (cdr object) ,(make-keyword (symbol-name > field))))) fields) > ;; writers: > ,@(mapcar (lambda (field) > `(defun ,(intern (format "set-%s-%s" name field)) (object > value) > (assert (not (null object))) > (setf (getf (cdr object) ,(make-keyword > (symbol-name field))) value))) > fields) > ,@(mapcar (lambda (field) > `(defsetf ,(intern (format "%s-%s" name field)) > ,(intern (format "set-%s-%s" name field)))) > fields) > ',name)) > > > (progn (pprint (macroexpand '(define-structure person name birthdate job))) > nil) > --> > (progn > (defun* make-person (&key name birthdate job) > (list 'person :name name :birthdate birthdate :job job)) > (defun person-name (object) (getf (cdr object) :name)) > (defun person-birthdate (object) (getf (cdr object) :birthdate)) > (defun person-job (object) (getf (cdr object) :job)) > (defun set-person-name (object value) > (assert (not (null object))) > (setf (getf (cdr object) :name) value)) > (defun set-person-birthdate (object value) > (assert (not (null object))) > (setf (getf (cdr object) :birthdate) value)) > (defun set-person-job (object value) > (assert (not (null object))) > (setf (getf (cdr object) :job) value)) > (defsetf person-name set-person-name) > (defsetf person-birthdate set-person-birthdate) > (defsetf person-job set-person-job) > 'person) > > (define-structure person name birthdate job) > --> person > > (make-person :name "Tintin" :birthdate 1918 :job "Reporter") > --> (person :name "Tintin" :birthdate 1918 :job "Reporter") > > (let ((tintin (make-person :name "Tintin" :birthdate 1918 :job > "Reporter"))) > (setf (person-birthdate tintin) 1920) > tintin) > --> (person :name "Tintin" :birthdate 1920 :job "Reporter") > > (let ((tintin (make-person :name "Tintin" :birthdate 1918 :job > "Reporter"))) > (insert (format "%s is a %s\n" (person-name tintin) (person-job tintin)))) > Tintin is a Reporter > > > > Then, if you notice that p-list are too slow, or that you need > subclasses, you can easily substitute defstruct for define-structure, > and get structures with direct access slots, or if you notice that you > need multiple inheriting, you can substitute a defclass for the > define-structure, all with the rest of the program unchanged, since > using the functional abstraction defined by these accessors. > > > -- > __Pascal Bourguignon__ >