From: ··············@gmail.com
Subject: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <1128105567.638222.300290@g14g2000cwa.googlegroups.com>
Hi.
I'm trying to create a simple alternative object system for common
lisp. Whilst I admire the power and generality of clos, it's a little
unwieldy for some little things. What I'm looking for is something more
in the model of ruby/javascript/python, where an object is basically a
hash table of properties with very simple accessing syntax. A very
important requirement for me is that setfing an undefined property
defines it, so assignment and property initialisation look the same.
So here's an example of what I would like to be able to do.

>(setf obj (make-object))

>(setf (obj name) "Chuck")

>(obj name)
-> "Chuck"

>(defun make-person (name age)
     (let ((obj (make-object)))
        (setf (obj name) name)
        (setf (obj age) age)
        obj))

>(setf jimmy (make-person "jimmy" 74))

>(jimmy age)
-> 74

>(setf (jimmy age) 2)
-> 2

>(jimmy age)
-> 2

Now at this point I'm not even thinking about methods on the object
(that can come later but is not so important, so maybe object is the
wrong word and I should be talking about structures)
My first thought was to have make-object return a closure over a hash
table, which would mean you would have to quote all the accessors
(jimmy 'age). Now this is bearable but not ideal. However there is a
more serious problem, which is the namespace issue. I'd either have to
pass all my objects using the eye-jarring #' macro, or (funcall jimmy
'age).  (and oops, this scheme doesn't  deal with setfing properties,
just spotted that).
Now, if there were a single namespace and macros were first class
objects (hint hint Paul Graham) I think make-object could return a
macro, that was closed over a hash table, and that returned the
accessor form for the hash table. (or is it impossible to close a macro
over a variable? this hurts my head)
Anyway, I'm stumped. I've reached the limit of my knowledge of lisp,
but I'm sure it's possible (probably using read-macros or generalized
variables or some such esoterica).
If anyone has any ideas I'd be very interested (and if you don't have
any ideas I'm sorry you had to read this torturously long post).

oo oo, ps, avoiding a meta-circular interpreter type solution would be
a bonus :)

Thanks in advance

Robbie

From: Wade Humeniuk
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <0Eg%e.196532$wr.119362@clgrps12>
Though not particularly recommended, CLOS is much better...


(defmacro defobject (name)
   `(let ((slots nil))
      (defun ,name (slot-name)
        (getf slots slot-name))
      (defun (setf ,name) (value slot-name)
        (setf (getf slots slot-name) value))))

CL-USER 1 > (defobject jimmy)
(SETF JIMMY)

CL-USER 2 > (setf (jimmy 'name) "jimmy")
"jimmy"

CL-USER 3 > (setf (jimmy 'age) 74)
74

CL-USER 4 > (jimmy 'name)
"jimmy"

CL-USER 5 > (jimmy 'age)
74

CL-USER 6 > (jimmy 'height)
NIL

CL-USER 7 >

Wade
From: Peter Seibel
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <m2u0g22u83.fsf@gigamonkeys.com>
Wade Humeniuk <··················@telus.net> writes:

> Though not particularly recommended, CLOS is much better...
>
>
> (defmacro defobject (name)
>    `(let ((slots nil))
>       (defun ,name (slot-name)
>         (getf slots slot-name))
>       (defun (setf ,name) (value slot-name)
>         (setf (getf slots slot-name) value))))
>
> CL-USER 1 > (defobject jimmy)
> (SETF JIMMY)
>
> CL-USER 2 > (setf (jimmy 'name) "jimmy")
> "jimmy"
>
> CL-USER 3 > (setf (jimmy 'age) 74)
> 74
>
> CL-USER 4 > (jimmy 'name)
> "jimmy"
>
> CL-USER 5 > (jimmy 'age)
> 74
>
> CL-USER 6 > (jimmy 'height)
> NIL

However I suspect the OP may also want to be able to say:

  > (defun foo (obj) (obj 'name))
  FOO

  > (foo jimmy)
  "jimmy"

I think the OP has no choice but to write his own interpreter or
compiler since his desired language (as far as I cen tell, reading
between the lines of his original post) has a fundamentally different
evaluation rule for cons forms than Common Lisp does. But, as we've
been trying to explain to Dr. Flying Frog, that's one of Lisp's
strengths so the OP shouldn't be deterred, assuming for the sake of
argument, that having such a language would actually solve some real
problem for him.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Pascal Costanza
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <3q5i3dFdb9cfU1@individual.net>
··············@gmail.com wrote:
> Hi.
> I'm trying to create a simple alternative object system for common
> lisp. Whilst I admire the power and generality of clos, it's a little
> unwieldy for some little things. What I'm looking for is something more
> in the model of ruby/javascript/python, where an object is basically a
> hash table of properties with very simple accessing syntax. A very
> important requirement for me is that setfing an undefined property
> defines it, so assignment and property initialisation look the same.

CLOS is so general that it can even give you the simple approaches. 
Whenever a slot is not defined for a class, an access to such a slot 
issues a "slot is missing" error. However, there is a defined way to 
intercept that error message and something useful instead, like doing a 
lookup in a hashtable.

Here is the implementation:

(defclass hash-slots-object ()
   ((hash-slots
     :accessor hash-slots
     :initform (make-hash-table :test #'eq))))

(defmethod slot-missing
            ((class t)
             (object hash-slots-object)
             slot-name operation &optional new-value)
   (ecase operation
     (slot-value
      (multiple-value-bind (value present-p)
			  (gethash slot-name (hash-slots object))
        (if present-p value
            (slot-unbound class object slot-name))))

     (setf
      (setf (gethash slot-name (hash-slots object))
            new-value))

     (slot-boundp
      (nth-value 1 (gethash slot-name (hash-slots object))))

     (slot-makunbound
      (remhash slot-name (hash-slots object)))))

Just use hash-slots-object as a mixin, and you can do what you want.


Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
From: Peter Seibel
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <m2y85e2v3p.fsf@gigamonkeys.com>
Pascal Costanza <··@p-cos.net> writes:

> ··············@gmail.com wrote:
>> Hi.
>> I'm trying to create a simple alternative object system for common
>> lisp. Whilst I admire the power and generality of clos, it's a little
>> unwieldy for some little things. What I'm looking for is something more
>> in the model of ruby/javascript/python, where an object is basically a
>> hash table of properties with very simple accessing syntax. A very
>> important requirement for me is that setfing an undefined property
>> defines it, so assignment and property initialisation look the same.
>
> CLOS is so general that it can even give you the simple
> approaches. Whenever a slot is not defined for a class, an access to
> such a slot issues a "slot is missing" error. However, there is a
> defined way to intercept that error message and something useful
> instead, like doing a lookup in a hashtable.
>
> Here is the implementation:
>
> (defclass hash-slots-object ()
>    ((hash-slots
>      :accessor hash-slots
>      :initform (make-hash-table :test #'eq))))
>
> (defmethod slot-missing
>             ((class t)
>              (object hash-slots-object)
>              slot-name operation &optional new-value)
>    (ecase operation
>      (slot-value
>       (multiple-value-bind (value present-p)
> 			  (gethash slot-name (hash-slots object))
>         (if present-p value
>             (slot-unbound class object slot-name))))
>
>      (setf
>       (setf (gethash slot-name (hash-slots object))
>             new-value))
>
>      (slot-boundp
>       (nth-value 1 (gethash slot-name (hash-slots object))))
>
>      (slot-makunbound
>       (remhash slot-name (hash-slots object)))))
>
> Just use hash-slots-object as a mixin, and you can do what you want.

Though he will have to use SLOT-VALUE, i.e.

  (setf (slot-value obj 'name) "Barney")

rather than:

  (setf (name obj) "Barney")

or (what he actually said he wanted):

  (setf (obj name) "Barney")

I don't think there's anything that's going to let SETF do what he
wants in the latter case. However perhaps with Allegro's compile-time
environments one could implement one's own assignment macro:

  (defmacro my-set (place value)
    (if (and (consp place) (= (length place) 2) (env:variable-p (first place)))
      `(setf (gethash ',(second place) ,(first place)) ,value)
      `(setf ,place ,value)))

where ENV:VARIABLE-P is a made up function that tells you whether a
symbol is the name of a variable in the current scope. (I'm assuming
that if it is, that it is the name of an object--one might want to
check first that it's not the name of a SETF'able function, another
thing that I'm assuming there'd be some way to determine that with the
environment access foo.)

Perhaps Duanne can chime in as to whether this is actually possible in
Allegro.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Duane Rettig
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <4ek766zl4.fsf@franz.com>
[I haven't been following this thread, so sorry in advance for
any responses that make it seem like I'm in a fog]

Peter Seibel <·····@gigamonkeys.com> writes:

 [slot-missing example elided ...]

> Though he will have to use SLOT-VALUE, i.e.
>
>   (setf (slot-value obj 'name) "Barney")
>
> rather than:
>
>   (setf (name obj) "Barney")
>
> or (what he actually said he wanted):
>
>   (setf (obj name) "Barney")
>
> I don't think there's anything that's going to let SETF do what he
> wants in the latter case.

I'm not sure why you say this.  Perhaps I missed it earlier in
the thread, but I'm surprised that the existence of the slot is
being routed around a slot-missing method, rather than circumventing
the whole error mode by defining slot-value-using-class and
slot-exists-p-using-class methods using the MOP.  Also, a
(setf slot-value-using-class) method could be defined, which
would take care of the situation you describe.

> However perhaps with Allegro's compile-time
> environments one could implement one's own assignment macro:
>
>   (defmacro my-set (place value)
>     (if (and (consp place) (= (length place) 2) (env:variable-p (first place)))
>       `(setf (gethash ',(second place) ,(first place)) ,value)
>       `(setf ,place ,value)))

This might work as an optimization (I haven't analyzed whether it
would actually be faster, but my gut tells me that it would).  The
disadvantage is that you're now "specializing" on the accessor rather
than the class; you are forcing a call to my-set to set a slot rather
than using the CLOS/MOP mechanisms to enable a simple Lisp-y setf.

> where ENV:VARIABLE-P is a made up function that tells you whether a
> symbol is the name of a variable in the current scope. (I'm assuming
> that if it is, that it is the name of an object--one might want to
> check first that it's not the name of a SETF'able function, another
> thing that I'm assuming there'd be some way to determine that with the
> environment access foo.)
>
> Perhaps Duanne can chime in as to whether this is actually possible in
> Allegro.

Abslolutely.  One "n" in my name, though - I almost missed it :-)

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Pascal Costanza
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <3q5tklFdfh6qU1@individual.net>
Duane Rettig wrote:
> [I haven't been following this thread, so sorry in advance for
> any responses that make it seem like I'm in a fog]
> 
> Peter Seibel <·····@gigamonkeys.com> writes:
> 
>  [slot-missing example elided ...]
> 
>>Though he will have to use SLOT-VALUE, i.e.
>>
>>  (setf (slot-value obj 'name) "Barney")
>>
>>rather than:
>>
>>  (setf (name obj) "Barney")
>>
>>or (what he actually said he wanted):
>>
>>  (setf (obj name) "Barney")
>>
>>I don't think there's anything that's going to let SETF do what he
>>wants in the latter case.

I was focusing on the functionality, not on the syntax. If it is really 
important to have that syntax, there are ways to achieve the effect.

In Scheme, you could simply define the object as a function, so 
something like this:

(define (make-object)
   (let ((alist '()))
     (lambda (name . new-value)
       (if (null? new-value)
           (let ((cons (assq name alist)))
             (if cons (cdr cons) #f))
           (set! alist (cons (cons name (car new-value))
                             alist))))))

#;> (define obj (make-object))
#;> (obj 'name "Pascal")
((name . "Pascal"))
#;> (obj 'name)
"Pascal"

(Turning the alist into a hashtable and optimizations are left as an 
exercise to the reader. ;)

This works in Scheme somewhat better than in Common Lisp because Scheme 
is a Lisp-1. I have showed some time ago how in principle a Lisp-1 can 
be embedded in Common Lisp. Google for "with-funcalls".

> I'm not sure why you say this.  Perhaps I missed it earlier in
> the thread, but I'm surprised that the existence of the slot is
> being routed around a slot-missing method, rather than circumventing
> the whole error mode by defining slot-value-using-class and
> slot-exists-p-using-class methods using the MOP.  Also, a
> (setf slot-value-using-class) method could be defined, which
> would take care of the situation you describe.

The OP asked for being able to add new slots to an object on the fly, 
without the need to define the slots in the class. The AMOP 
specification doesn't allow you to do this because 
slot-value-using-class, etc., is not specialized on the slot name but on 
the slot definition class. This implies that slot-value-using-class can 
only be called on defined slots, not on arbitrary ones.

To give more detail, slot-value is specificed to roughly do this:

(defun slot-value (object slot-name)
   (slot-value-using-class
     (class-of object) object
     (find slot-name (class-slots (class-of object))
           :key #'slot-definition-name)))

The main reason why you have to resort to the slot-missing protocol is 
that the slot name is looked up in the slots specified for the class 
before you have a chance of intercepting anything.

 From a MOP user's perspective it would be nice if 
slot-value-using-class were specialized on the slot name because this 
would give you more flexibility, but from a CLOS implementor's point of 
view the specialization on the slot definition class gives you more 
opportunities to optimize the slot access protocol. Going through 
slot-missing is probably good enough in most cases.

(This is, btw, a case where Allegro Common Lisp has a bug: The slot 
access protocol allows a CLOS implementation to compute the effective 
method on slot-value-using-class, etc., at class finalization time so 
that the method lookup for slot accesses can be optimized away. However, 
Allegro does this too eagerly - when a class is reinitialized such that 
a slot changes its slot definition class, the precomputed effective 
method is not invalidated. Effectively this means that in Allegro, you 
cannot change the slot definition class for a slot...)


Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
From: ··············@gmail.com
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <1128154735.636937.296730@g43g2000cwa.googlegroups.com>
Thanks for all the responses.

I really like this syntax
#;> (obj 'name "Pascal")
((name . "Pascal"))
#;> (obj 'name)
"Pascal"
"with-funcalls" looks interesting, as I do hate that lisp 2 baggage.

The [solution read-macro] is something I've thought about, but I'm not
sure if I want that big change in appearance. On the other hand it
might be useful as a warning that 'normal evaluation rules don't apply
here'.

"OP shouldn't be deterred, assuming for the sake of
argument, that having such a language would actually solve some real
problem for him. "
I don't particularly have a 'real problem' except 'clos classes are too
static out of the box'. It doesn't add a massive amount of expressive
power, but it does mean less typing, which I like.
I suppose you're right about writing an interpreter, I'm just worried
about a big speed hit.

Thanks again folks
From: Peter Seibel
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <m2mzlt2ary.fsf@gigamonkeys.com>
···············@gmail.com" <··············@gmail.com> writes:

> "OP shouldn't be deterred, assuming for the sake of argument, that
> having such a language would actually solve some real problem for
> him. "

> I don't particularly have a 'real problem' except 'clos classes are
> too static out of the box'. It doesn't add a massive amount of
> expressive power, but it does mean less typing, which I like.  I
> suppose you're right about writing an interpreter, I'm just worried
> about a big speed hit.

Well your "interpreter" can be a "compiler", i.e. macros that
translate your prototype-based language, with whatever syntax you
like, into Common Lisp which will then be compiled by the Common Lisp
compiler. The only (runtime) speed hit I'd imagine you'd run into
would be due necessary overhead of providing the flexibility you
want. But since you control the compiler for your language its just up
to you how clever you want to be in implementing the underlying ideas
in an efficient way.

However, that said, unless you're already a CLOS master, I'd suggest
that you not be too quick to give up on it. While I know what you're
talking about--along this one axis CLOS is arguably less flexible than
prototype-based languages--it is also one of the most dynamic object
systems around and facilities and power that you won't find in those
languages. In other words, unless you really know what you're giving
up by moving to a different object model you should play more with
CLOS and you may find that it has merits that compensate for it's
relative "staticness" in this one regard.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Pascal Costanza
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <3qak3uFds9ipU1@individual.net>
··············@gmail.com wrote:
> Thanks for all the responses.
> 
> I really like this syntax
> #;> (obj 'name "Pascal")
> ((name . "Pascal"))
> #;> (obj 'name)
> "Pascal"
> "with-funcalls" looks interesting, as I do hate that lisp 2 baggage.

...it came to my mind that with-funcalls is maybe too complicated for 
simple cases. Here is a simpler macro:

(defmacro lisp1-let ((&rest bindings) &body body)
   (let ((args (gensym)))
     `(let (,@bindings)
        (flet (,@(loop for binding in bindings
                       collect `(,(car binding)
                                 (&rest ,args)
                                 (apply ,(car binding) ,args)))
          ,@body))))

This is untested...


Pascal

-- 
OOPSLA'05 tutorial on generic functions & the CLOS Metaobject Protocol
++++ see http://p-cos.net/oopsla05-tutorial.html for more details ++++
From: Pascal Costanza
Subject: Slot value stickyness in Allegro, was Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <3sk67jFoo6p1U1@individual.net>
Some time ago, I wrote this:

> To give more detail, slot-value is specificed to roughly do this:
> 
> (defun slot-value (object slot-name)
>   (slot-value-using-class
>     (class-of object) object
>     (find slot-name (class-slots (class-of object))
>           :key #'slot-definition-name)))
[...]

> This is, btw, a case where Allegro Common Lisp has a bug: The slot 
> access protocol allows a CLOS implementation to compute the effective 
> method on slot-value-using-class, etc., at class finalization time so 
> that the method lookup for slot accesses can be optimized away. However, 
> Allegro does this too eagerly - when a class is reinitialized such that 
> a slot changes its slot definition class, the precomputed effective 
> method is not invalidated. Effectively this means that in Allegro, you 
> cannot change the slot definition class for a slot...

Allegro Common Lisp indeed had a bug that led to this effect in a very 
tricky corner case. However, in general the above description is 
incorrect: Allegro always allowed changes of the slot definition class 
for a given slot. I just had a case both in AspectL and ContextL in 
which that other bug was triggered from which I drew a wrong conclusion. 
(The real bug was triggered by calling make-instances-obsolete during 
class finalization which wasn't handled 100% correctly.)

Thanks to the excellent Franz support, we have been able to identify 
this bug and Franz has finally fixed it for Allegro 7.0. New versions of 
AspectL and ContextL will be made available soon that now support 
changing non-special slots to special slots in Allegro. The current 
darcs repositories for ContextL already include the new version.


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Rob Warnock
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <S8ydnSmiT6QhB93eRVn-hQ@speakeasy.net>
Peter Seibel  <·····@gigamonkeys.com> wrote:
+---------------
| Pascal Costanza <··@p-cos.net> writes:
| > (defclass hash-slots-object ()
| >    ((hash-slots
| >      :accessor hash-slots
| >      :initform (make-hash-table :test #'eq))))
| >
| > (defmethod slot-missing ... )
| >
| > Just use hash-slots-object as a mixin, and you can do what you want.
| 
| Though he will have to use SLOT-VALUE, i.e.
|   (setf (slot-value obj 'name) "Barney")
| rather than:
|   (setf (name obj) "Barney")
+---------------

Yes, but he *will* be able to use WITH-SLOTS [which he wouldn't
with some of the other alternatives proposed in this thread]:

    > (setf (slot-value obj 'name) "Barney")

    "Barney"
    > (setf (slot-value obj 'age) 42)

    42
    > (with-slots (name age) obj
	(format t "~a is ~a.~%" name age))
    Barney is 42.
    NIL
    > 

I find that to be neat, for some odd reason...  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <873bnmwbj9.fsf@thalassa.informatimago.com>
···············@gmail.com" <··············@gmail.com> writes:
> I'm trying to create a simple alternative object system for common
> lisp. Whilst I admire the power and generality of clos, it's a little
> unwieldy for some little things. What I'm looking for is something more
> in the model of ruby/javascript/python, where an object is basically a
> hash table of properties with very simple accessing syntax. A very
> important requirement for me is that setfing an undefined property
> defines it, so assignment and property initialisation look the same.
> So here's an example of what I would like to be able to do.
>
>>(setf obj (make-object))
>>(setf (obj name) "Chuck")
>>(obj name)
> -> "Chuck"
> [...]
> However there is a
> more serious problem, which is the namespace issue.
> [...]
> Now, if there were a single namespace and macros were first class
> objects (hint hint Paul Graham)

Macros are first class objects: they are normal functions, only of
type sexp -> sexp instead of type  t -> t.

[48]> (defmacro m (x) `(print (list ',x '= ,x)))
M
[49]> (mapcar (macro-function 'm) '((m (sin (/ pi 3))) (m (+ 1 2))) '(nil nil))
((PRINT (LIST '(SIN (/ PI 3)) '= (SIN (/ PI 3))))
 (PRINT (LIST '(+ 1 2) '= (+ 1 2))))


> I think make-object could return a
> macro, that was closed over a hash table, and that returned the
> accessor form for the hash table. (or is it impossible to close a macro
> over a variable? this hurts my head)

No, you can't do it at macro- expansion time.  See below.

> Anyway, I'm stumped. I've reached the limit of my knowledge of lisp,
> but I'm sure it's possible (probably using read-macros or generalized
> variables or some such esoterica).
> If anyone has any ideas I'd be very interested (and if you don't have
> any ideas I'm sorry you had to read this torturously long post).
>
> oo oo, ps, avoiding a meta-circular interpreter type solution would be
> a bonus :)


(defparameter obj (make-object))
(setf (obj name) value)
(print (obj name))

Your syntax gives a strong constaint on obj.

obj should be a function, but defparameter defvar setf setq don't
assign the function value.

More over even if obj was a CLOS object, there's still no way to
detect the use of a undefined method: no-applicable-method applies to
generic functions, not to objects.


You could handle the assignment part shadowing a number of macro and
special operators such as: defparameter defvar defconstant setq setf
set let, but you wouldn't be able to handle expressions:
(print (obj name))

To be able to write (variable function) instead of (function variable)
indeed you'll have to write your own eval/apply.

An alternative would be to use a reader macro:

(setf  [obj name] value)
(print [obj name])

This reader macro would just exchange the first two items:

(setf  (name obj) value)
(print (name obj))

Or you could accept to write it this way directly.  From there, shadow
defparameter defvar defconstant setq setf set let to be able to create
the functions or generic functions needed to set and get attributes on
first assignment.

Note that if you want to be able to get an attribute before setting it:
(print (age obj))
and get NIL or "", then you're back to the eval/apply.


Also, you have a rather hard problem: you cannot handle this at
macroexpansion time, for example in cases such as:

(defun find-object-id (id) (aref *objects* id))
(setf (name (find-object-id 42)) "forty two")

Since you won't know before run time that (find-object-id 42) is one
of your object (vs. a normal lisp value or a CLOS object), you cannot
know that name is one of your kind of object attribute or something
else:

(defparameter *objects* (make-array 100))
(defun find-object-id (id) (aref *objects* id))
(defun example-1 () (setf (name (find-object-id 42)) "forty two"))
(defun example-2 () (setf (age  (find-object-id 43)) 103))
(defstruct stuff name)
(defmethod name ((self stuff)) (stuff-name self))
(defmethod (setf name) (value (self stuff)) (setf (stuff-name self) value))
(setf (aref *objects* 42) (make-stuff))
(setf (aref *objects* 43) (make-object))
(example-1)
(example-2)





However you can easily implement your own kind of object system with
your own semantics if you are more supple on the syntax side; instead
of:

(defparameter obj (make-object))
(setf (obj name) value)
(print (obj name))

write:

(defparameter obj (make-object))
(setf  (attribute obj 'name) value)
(print (attribute obj 'name))
(defmeth jump obj (height) (print `(Jumping ,height high)))
(send-message obj 'jump 2)

You can then add a reader macro to be able to write:

(defparameter obj (make-object))
(setf  [obj name] value)
(print [obj name])
[obj jump 2]


So you only need:

(defun (setf attribute) (value object attribute &rest indices)
   ...)
(defun attribute (object attribute &rest indices)
   ...)
(defun send-message (object message &rest arguments)
   ...)
(defmacro defmeth (message object arguments &body body)
   `(setf (attribute object ',message) ...))



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
From: Marco Baringer
Subject: Re: The limits of lisps synatactic gymnastics? (i sure hope not)
Date: 
Message-ID: <m2u0g1qyjn.fsf@soma.local>
···············@gmail.com" <··············@gmail.com> writes:

> Hi.
> I'm trying to create a simple alternative object system for common
> lisp. Whilst I admire the power and generality of clos, it's a little
> unwieldy for some little things. What I'm looking for is something more
> in the model of ruby/javascript/python, where an object is basically a
> hash table of properties with very simple accessing syntax. A very
> important requirement for me is that setfing an undefined property
> defines it, so assignment and property initialisation look the same.
> So here's an example of what I would like to be able to do.

this is starting to look a lot like a prototype object system.

http://en.wikipedia.org/wiki/Prototype-based_programming is as good a
starting point as any.

>>(setf obj (make-object))
>
>>(setf (obj name) "Chuck")
>
>>(obj name)
> -> "Chuck"
>
>>(defun make-person (name age)
>      (let ((obj (make-object)))
>         (setf (obj name) name)
>         (setf (obj age) age)
>         obj))
>
>>(setf jimmy (make-person "jimmy" 74))

>>(jimmy age)
> -> 74
>
>>(setf (jimmy age) 2)
> -> 2
>
>>(jimmy age)
> -> 2

making this work would require that every object also define a
function, what happens with objects which don't have names?

> Now at this point I'm not even thinking about methods on the object
> (that can come later but is not so important, so maybe object is the
> wrong word and I should be talking about structures)
> My first thought was to have make-object return a closure over a hash
> table, which would mean you would have to quote all the accessors
> (jimmy 'age). Now this is bearable but not ideal. However there is a
> more serious problem, which is the namespace issue. I'd either have to
> pass all my objects using the eye-jarring #' macro, or (funcall jimmy
> 'age).  (and oops, this scheme doesn't  deal with setfing properties,
> just spotted that).

the lanugages you mentioned (ruby, javascript and python) use syntax
to move method names into their own namespace. with lisp you'll need
to make this slightly more verbose:

(ref object slot-name)

you could use a read macro to get this down to: [object slot-name]
this is a lot like what Objective-C does so you've got a precedent
with this syntax.

> Now, if there were a single namespace and macros were first class
> objects (hint hint Paul Graham) I think make-object could return a
> macro, that was closed over a hash table, and that returned the
> accessor form for the hash table. (or is it impossible to close a macro
> over a variable? this hurts my head)

a macro is a function, so it closes over variables just like any other
function. the difference is that a macro is run at compile time, so it
closes over code and not data.

> Anyway, I'm stumped. I've reached the limit of my knowledge of lisp,
> but I'm sure it's possible (probably using read-macros or generalized
> variables or some such esoterica).
> If anyone has any ideas I'd be very interested (and if you don't have
> any ideas I'm sorry you had to read this torturously long post).
>
> oo oo, ps, avoiding a meta-circular interpreter type solution would be
> a bonus :)
>
> Thanks in advance

i once started writing a simple prototype based object system (i've
forgeten why though). here's what i can remeber:

------------------------------------------------------------------------
;; internals
(defclass object ()
  ((slots :accessor slots :initform (make-hash-table))))

(defvar <Object> (make-instance 'object)
  "The root object for our simple object system.")

(defun access-slot (object slot-name)
  (labels ((find-slot (o)
             (multiple-value-bind (value foundp)
                 (gethash slot-name (slots o))
               (if foundp
                   value
                   (let ((parent (gethash 'parent (slots o))))
                     (if parent
                         (find-slot parent)
                         (error "Slot ~S not found in ~S" slot-name object)))))))
    (find-slot object)))

(defun (setf access-slot) (value object slot-name)
  (setf (gethash slot-name (slots object)) value))

(set-macro-character #\[ (lambda (stream char)
                           (declare (ignore char))
                           (destructuring-bind (object slot-name)
                               (read-delimited-list #\] stream t)
                             `(access-slot ,object ',slot-name))))

(set-syntax-from-char #\] #\))

(set-macro-character #\{ (lambda (stream char)
                           (declare (ignore char))
                           (destructuring-bind (object method-name &rest arguments)
                               (read-delimited-list #\} stream t)
                             (let ((obj (gensym)))
                               `(let ((,obj ,object))
                                  (funcall (access-slot ,obj ',method-name)
                                           ,obj ,@arguments))))))

(set-syntax-from-char #\} #\))

(defmacro defmeth (object method-name lambda-list &body body)
  `(progn
     (setf [,object ,method-name] (lambda (self ,@lambda-list) ,@body))
     ',method-name))

(defun new (object &rest initial-values)
  (let ((o (make-instance 'object)))
    (setf (gethash 'parent (slots o)) object)
    (loop
       for (slot-name value) on initial-values by #'cddr
       do (setf (gethash slot-name (slots o)) value))
    o))

;; examples:

(defvar <Person> (new <Object>))

(defmeth <Person> date-of-birth ()
  (- 2005 [self age]))

(defvar jimmy (new <Person>))

(setf [jimmy age] 74)

[jimmy age]

{jimmy date-of-birth}

(defparameter *people*
  (list (new <Person> 'age 10)
        (new <Person> 'age 20)
        (new <Person> 'age 30)))

(dolist (p *people*)
  (format t "Age: ~D; DoB: ~D~%" [p age] {p date-of-birth}))
------------------------------------------------------------------------

there are many many ways to improve that (this is not an example of
high quality lisp code). i'd be especially cool to make the
access-slot function a method of the objcets itself, then you'd have a
meta-prototype object system. this could also be done using CLOS,
though the code would be a bit longer.

hth.

-- 
-Marco
Ring the bells that still can ring.
Forget the perfect offering.
There is a crack in everything.
That's how the light gets in.
	-Leonard Cohen