After a class has been defined (and finalized) using the defclass macro,
I want to add a slot to it. How can I do it using MOP?
I'm on Allegro CL so code specific of ACL will be okay too.
Thanks,
Saurabh.
Saurabh Nanda wrote:
> After a class has been defined (and finalized) using the defclass macro,
> I want to add a slot to it. How can I do it using MOP?
>
> I'm on Allegro CL so code specific of ACL will be okay too.
It can be done using ContextL:
(define-layered-class c ()
(a b c))
(deflayer more-slots)
(define-layered-class c :in-layer more-slots ()
(d))
(ensure-active-layer 'more-slots)
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> It can be done using ContextL:
Thanks for the pointer Pascal. Two reasons why I wouldn't particularly
like to use this solutions:
a) I want to know how to exactly do this in MOP. A learning exercise.
b) I don't want to depend on ContextL for just one teeny little thing.
Please could you tell me how to exactly do this in MOP. Which functions
should I be looking up?
Saurabh.
Saurabh Nanda wrote:
>> It can be done using ContextL:
>
> Thanks for the pointer Pascal. Two reasons why I wouldn't particularly
> like to use this solutions:
>
> a) I want to know how to exactly do this in MOP. A learning exercise.
> b) I don't want to depend on ContextL for just one teeny little thing.
>
> Please could you tell me how to exactly do this in MOP. Which functions
> should I be looking up?
You can find a brute force way to do this in AspectL. It has a concept
of "destructive mixins" - basically commands to manipulate class
objects. The general idea is to use the metaobject readers
(class-direct-slots, slot-definition-name, etc. pp.) to determine the
current definition of a class, and then to use reinitialize-instance on
the same class object to redefine it destructively.
That is a pretty gross and unreliable way to change class definitions.
If you get a parameter to one of the AspectL functions wrong, it is
quite likely that your system becomes unusable. That's the main reason
why I discontinued AspectL. I could have added some parameter checking,
but that would have been a lot of work, and I am convinced that ContextL
gives you much cleaner abstractions to essentially achieve the same.
Nevertheless, taking a look at the AspectL code may give you some ideas
how to do what you want (although, to stress it again, I don't recommend
to do it that way).
In ContextL, the idea is different: Here a layered class always consists
of a stub class with a list of multiple direct superclasses which
contain the actual (layered) definitions. Whenever a
define-layered-class form is evaluated for a new layer, you actually get
a new direct superclass for the given class that corresponds to the
definitions for that layer. Mixing the different definitions from the
different layers is then straightforward - I just rely on standard CLOS
inheritance (which also gives me very efficient effective classes and
slots).
You could do the same in your code: For each view-class, actually create
a stub class that inherits from a view-class and an assocation-class. A
def-view-class then manipulates the view-class part, and a
defassociation manipulates the association part.
Or you use ContextL. ;)
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> The general idea is to use the metaobject readers
> (class-direct-slots, slot-definition-name, etc. pp.) to determine the
> current definition of a class, and then to use reinitialize-instance on
> the same class object to redefine it destructively.
I'm giving this method a shot for starters. I've hit a roadblock rather
prematurely. Why is the third form giving me a nil?
(defclass test-class ()
((name
:initarg :name
:initform "test name"
:accessor name)))
(finalize-inheritance (find-class 'test-class))
(class-default-initargs (find-class 'test-class))
Saurabh.
On Aug 29, 3:51 pm, Saurabh Nanda <············@gmail.com> wrote:
> Why is the third form giving me a nil?
>
> (defclass test-class ()
> ((name
> :initarg :name
> :initform "test name"
> :accessor name)))
> (finalize-inheritance (find-class 'test-class))
> (class-default-initargs (find-class 'test-class))
>
:DEFAULT-INITARGS are not the same as the :INITARG forms passed to
slots in DEFCLASS. See section 7.1 in the HyperSpec for a
clarification.
> :DEFAULT-INITARGS are not the same as the :INITARG forms passed to
> slots in DEFCLASS. See section 7.1 in the HyperSpec for a
> clarification.
Sorry my goof up. So I guess I'll have to use class-slots to get all the
slots of the class. For each slot I will have to use
slot-definition-initargs, slot-definition-readers,
slot-definition-writers, etc. to get the various slot options. Using all
this info I'll have to construct the lambda list for
reinitialize-instance and call it for the class in question.
Wow! Why isn't there a simple macro for this already!
Saurabh.
Saurabh Nanda wrote:
>> :DEFAULT-INITARGS are not the same as the :INITARG forms passed to
>> slots in DEFCLASS. See section 7.1 in the HyperSpec for a
>> clarification.
>
> Sorry my goof up. So I guess I'll have to use class-slots to get all the
> slots of the class. For each slot I will have to use
> slot-definition-initargs, slot-definition-readers,
> slot-definition-writers, etc. to get the various slot options. Using all
> this info I'll have to construct the lambda list for
> reinitialize-instance and call it for the class in question.
>
> Wow! Why isn't there a simple macro for this already!
I had to learn this the hard way - this is exactly what I originally did
in AspectL, and it's wrong (to give the executive summary here ;).
You're walking on very thin ice here, and you seem to be using a
try-and-error approach. You should, at least, first read the Concepts
chapter of the CLOS MOP specification and understand the essentials of
MOP programing before proceeding. (No, you don't use the class-slots
here, but the class-direct-slots, and by reading the Concepts chapter,
such things, and others, should become clear to you.)
It would be even better to get a copy of AMOP and read it. It's an
excellent and very insightful book (one of the best computer science
books according to Alan Kay). There is a reason why the CLOS MOP doesn't
support class definition by way of setter functions or
reinitialize-instance that well, and the reason is given there.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> Thanks for the pointer Pascal. Two reasons why I wouldn't particularly
> like to use this solutions:
>
> a) I want to know how to exactly do this in MOP. A learning exercise.
> b) I don't want to depend on ContextL for just one teeny little thing.
I'm reading through your ContextL paper right now
(http://p-cos.net/documents/contextl-overview.pdf). I won't be able to
use this solution because, along with standard-db-class, it will
introduce another metaclass, layered-class, to deal with.
Saurabh.
Saurabh Nanda wrote:
>> Thanks for the pointer Pascal. Two reasons why I wouldn't particularly
>> like to use this solutions:
>>
>> a) I want to know how to exactly do this in MOP. A learning exercise.
>> b) I don't want to depend on ContextL for just one teeny little thing.
>
> I'm reading through your ContextL paper right now
> (http://p-cos.net/documents/contextl-overview.pdf). I won't be able to
> use this solution because, along with standard-db-class, it will
> introduce another metaclass, layered-class, to deal with.
OK, that could indeed be a problem. I have discussed this some time ago
with someone else, and in principle I think it should be possible to
compose the two metaclasses, but since nobody has actually done that
yet, I am not sure whether this may yield unexpected problems.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> Any reason why re-evaluating the defclass form (edited to include the
> new slot definition) won't work for you?
I'm writing a "defassociation" macro for CLSQL to make defining class
associations more easier. So, after defining various view-classes
(classes mapped to a tables) one can use the defassociation macro to
define associations (has-one, has-many, has-and-belongs-to-many) between
them. This macro will have to add new slots to hold the
associated/joined objects in the classes participating in the association.
This is why I can't re-evaluate the defclass form (or def-view-class
form to be more specific) to include the new slot definitions.
Saurabh.
* Saurabh Nanda <···········@registered.motzarella.org> :
|> Any reason why re-evaluating the defclass form (edited to include the
|> new slot definition) won't work for you?
|
| I'm writing a "defassociation" macro for CLSQL to make defining class
| associations more easier. So, after defining various view-classes
| (classes mapped to a tables) one can use the defassociation macro to
| define associations (has-one, has-many, has-and-belongs-to-many)
| between them. This macro will have to add new slots to hold the
| associated/joined objects in the classes participating in the
| association.
|
| This is why I can't re-evaluate the defclass form (or def-view-class
| form to be more specific) to include the new slot definitions.
That would explain it :) I found the CL-SQL view-class abstraction has
limitations, (as you may have also found), I tried unsuccessfully to use
it for a database-table-designer application. I ended up modelling the
database relationships and tables in my own CLOS objects, and then had
methods for generating the def-view-class form. (I haven't finished this
to my satisfaction -- still separatating a table class from a sub-class
with the join slots)
Another thing I wanted to do was: given a view-class object, introspect
the join slots and figure out the relations. The key thing is to have a
representation for the relations that your program (not just CL-SQL) can
access and use at runtime. This could not be done with view-class
across sql + lisp implementation combinations. (I use clsql and ysql,
and would like to use commonsql too). Also I couldn't mixin objects of
other other types with any ease which would make sense.
I'd be interested in knowing how end up solving this, or if I'm
incorrect in any of my assessments above
--
Madhu
> That would explain it :) I found the CL-SQL view-class abstraction has
> limitations, (as you may have also found), I tried unsuccessfully to use
> it for a database-table-designer application. I ended up modelling the
> database relationships and tables in my own CLOS objects, and then had
> methods for generating the def-view-class form. (I haven't finished this
> to my satisfaction -- still separatating a table class from a sub-class
> with the join slots)
Apart from the limitations in def-view-class, I've found that CLSQL
lacks lots of features. For example, the limit and offset arguments to
the select function do not work for Oracle (Oracle has a weird way to
get this done, which requires some obtuse subselects). Another one is
that, pre-fetching immediate join slots is broken (I've fixed this one,
and am about to release a patch).
> Another thing I wanted to do was: given a view-class object, introspect
> the join slots and figure out the relations. The key thing is to have a
> representation for the relations that your program (not just CL-SQL) can
> access and use at runtime. This could not be done with view-class
> across sql + lisp implementation combinations. (I use clsql and ysql,
> and would like to use commonsql too).
I'm not sure I understood what you're trying to do here. Can you
elaborate a bit?
> Also I couldn't mixin objects of
> other other types with any ease which would make sense.
I've tried mixing Allegro's persistent metaclass and CLSQL's
standard-db-class to be able to store an object either in the DB or the
acache. I failed miserably.
Saurabh.
* Saurabh Nanda <············@registered.motzarella.org> :
|> Another thing I wanted to do was: given a view-class object, introspect
|> the join slots and figure out the relations. The key thing is to have a
|> representation for the relations that your program (not just CL-SQL) can
|> access and use at runtime. This could not be done with view-class
|> across sql + lisp implementation combinations. (I use clsql and ysql,
|> and would like to use commonsql too).
|
| I'm not sure I understood what you're trying to do here. Can you
| elaborate a bit?
Just that. Imagine you don't know the columns (slot names) upfront.
Now the descriptions of relations are specified by the db-kind and
db-info arguments to def-view-class. I was making the case for this
information to be available at runtime, given just a view-class object.
One application, if this were possible, is to say, write "generic" code
for presentation and input methods for database objects for a specific
application, which can be called at runtime, and which takes advantage
of standard clos modeling. A lot of this would otherwise be just boiler
plate db access and presentation code which needs to be filled in with
correct slot names, and which cannot use OO (to capture the common
behaviour.) Maybe this is clearer?
--
Madhu