-
Notifications
You must be signed in to change notification settings - Fork 41
Description
Continuing the discussion from #71 (comment):
I also have some ideas for how to make uLisp object-oriented
Have you seen this?
Yes, but a) it only supports single inheritance because it's prototype-based (can't have multiple parents / "mixins") and b) it doesn't support setf'ing slots ((setf (value obj 'foo) new-value) would kind of make sense but it doesn't work so you have to use update). Also, calling a method on an object is more verbose because you have to do ((value obj 'key) obj arg1 arg2 ...) instead of just (obj :key arg1 arg2 ...). You went to the length of defining a "generic area function" too but that just seems unnecessary. I'm all for reducing the number of required parenthesis especially in a parenthesis-heavy language like Lisp.
Another potential problem with this I can see is having the special key 'parent being used to point to the prototype of the object, seems like it would be prone to collisions if someone did something where it makes sense to point to a parent, such as nested parsers for something (e.g. JSON).
But I do think this is a good starting point: an object can be represented as an assoc list of its slots, and the tail of the assoc list somehow points to the prototype(s).
Okay, my idea here:
First off, generic keyword support needs to be added.
My idea is that a new type (in the type enum) called OBJECT would be defined. The cdr of the actual OBJECT cell would point to a cons pair. The car of that cons pair would point to the slots array, and the cdr would point to an (improper) list of prototypes.
Then two changes need to be made to eval(), right before the not valid here error case:
- If the called value is a keyword, there must be one argument, an object, and the keyword is looked up in the object's slots array and returned.
- If the called value is an object, there must be at least one argument, and the first argument must be a keyword which is looked up in the object's slots array as usual, and the slot must contain a lambda with at least one argument, the first argument will be the object (i.e. a "this" or "self" parameter). Basically,
(obj :foo 1 2 3)desugars into((:foo obj) obj 1 2 3). Of course this longer syntax would still be possible and would also be the only way to get the equivalent of Javascript'sFunction.call.
Hope that helps.