| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| I am saving information in an object, and certain slots require a time- consuming calculation. I can leave these slots uninitialized and call the function that calculates them, eg (calculate-summary-statistics model) (slot-value model 'average-productivity) but it would be nicer to have this done 'on demand', eg whenever slot- value is called, somehow checks if the slot is initialized and call calculate-summary-statistics if it is not. Two questions: 1. how do you test that a slot has been assigned a value? or should I just initialize them as nil, and test for that? 2. slot-value is a normal function, not a method, so I can't write a :before method. Is there a way to achieve what I want? Thanks, Tamas |
|
#2
| |||
| |||
| Tamas K Papp <tkpapp@gmail.com> writes: > I am saving information in an object, and certain slots require a time- > consuming calculation. I can leave these slots uninitialized and call > the function that calculates them, eg > > (calculate-summary-statistics model) > (slot-value model 'average-productivity) > > but it would be nicer to have this done 'on demand', eg whenever slot- > value is called, somehow checks if the slot is initialized and call > calculate-summary-statistics if it is not. > > Two questions: > > 1. how do you test that a slot has been assigned a value? or should I > just initialize them as nil, and test for that? SLOT-BOUNDP can be used to test for it. If you use NIL, the SLOT-UNBOUND trick below doesn't work. > 2. slot-value is a normal function, not a method, so I can't write > a :before method. Is there a way to achieve what I want? I use a method on SLOT-UNBOUND for lazy slots all the time. For a slot named A-LAZY-SLOT in class MYCLASS, you could do this: (defmethod slot-unbound (class (instance myclass) (slot (eql 'a-lazy-slot))) (setf (a-lazy-slot instance) (lengthy-calculation instance))) Zach |
|
#3
| |||
| |||
| On Tue, 26 Aug 2008 09:10:30 -0400, Zach Beane wrote: > I use a method on SLOT-UNBOUND for lazy slots all the time. For a slot > named A-LAZY-SLOT in class MYCLASS, you could do this: > > (defmethod slot-unbound (class (instance myclass) > (slot (eql 'a-lazy-slot))) > (setf (a-lazy-slot instance) (lengthy-calculation instance))) Dear Zach, Thank you so much. This has simplified my code a great deal. Again, I am amazed that whenever I think of something, I realize that the designers of CL have already thought of it and made it easy for me. This is what makes CL the best programming language for me... Best, Tamas |
|
#4
| |||
| |||
| In article <6hich7Fln1mlU1@mid.individual.net>, Tamas K Papp <tkpapp@gmail.com> wrote: > I am saving information in an object, and certain slots require a time- > consuming calculation. I can leave these slots uninitialized and call > the function that calculates them, eg > > (calculate-summary-statistics model) > (slot-value model 'average-productivity) > > but it would be nicer to have this done 'on demand', eg whenever slot- > value is called, somehow checks if the slot is initialized and call > calculate-summary-statistics if it is not. > > Two questions: > > 1. how do you test that a slot has been assigned a value? or should I > just initialize them as nil, and test for that? > > 2. slot-value is a normal function, not a method, so I can't write > a :before method. Is there a way to achieve what I want? > > Thanks, > > Tamas Before CLOS this model was very common (!) in Lisp. Slot demons were widely used. Like IF-NEEDED, IF-ADDED, IF-REMOVED, IF-CHANGED, and others. SLOT-UNBOUND has been mentioned already. You can add functionality to ACCESSOR functions. (defclass foo () ((bar :accessor foo-bar))) Now you can write :BEFORE, :AROUND and :AFTER methods. A :BEFORE method can check if the slot is bound, compute a value and store it in the slot. ACCESSORS are extensible, since they are generic functions. SLOT-VALUE is thought as some lower level mechanism to access slots. For example a call to SLOT-VALUE might be compiled inline. So, when you need to extend the functionality of changing and retrieving slot values, use accessors (readers, writers, accessors). For some advanced usage there is also SLOT-VALUE-USING-CLASS in the MOP. An implementation will call SLOT-VALUE-USING-CLASS from SLOT-VALUE (usually that's something to avoid, since it slows down the basic low-level slot access). Here is a LispWorks version (printing the args to SLOT-VALUE-USING-CLASS): CL-USER 49 > (defclass foo () ((bar :accessor foo-bar)) ( ptimize-slot-access nil))#<STANDARD-CLASS FOO 41300BC883> CL-USER 50 > (defmethod clos:slot-value-using-class :before ((class clos:standard-class) (a-foo foo) (slot (eql 'bar))) (print (list class a-foo slot))) #<STANDARD-METHOD CLOS:SLOT-VALUE-USING-CLASS (:BEFORE) (STANDARD-CLASS FOO (EQL BAR)) 402000FBBB> CL-USER 51 > (let ((foo (make-instance 'foo))) (setf (slot-value foo 'bar) 10) (slot-value foo 'bar)) (#<STANDARD-CLASS FOO 41300BC883> #<FOO 40203D0943> BAR) 10 But again, modify accessors - that's the simplest version. But the basic machinery to add all the fancy constructs from frame systems (like multi-valued slots, slot facets, slot demons, ...) is there. -- http://lispm.dyndns.org/ |
|
#5
| |||
| |||
| Tamas K Papp <tkpapp@gmail.com> writes: > I am saving information in an object, and certain slots require a time- > consuming calculation. I can leave these slots uninitialized and call > the function that calculates them, eg .... > 2. slot-value is a normal function, not a method, so I can't write > a :before method. Is there a way to achieve what I want? The simplest solution is to access the slots using accessor functions and not by using SLOT-VALUE. That way you can easily control what happens during slot access, since you have programmatic control of the accesses. You can, as Rainer Joswig mentions, use :BEFORE methods. You can also test slot for values with SLOT-BOUNDP. -- Thomas A. Russ, USC/Information Sciences Institute |
|
#6
| |||
| |||
| On Aug 26, 7:31 am, Rainer Joswig <jos...@lisp.de> wrote: > > CL-USER 49 > (defclass foo () ((bar :accessor foo-bar)) ( ptimize-slot-access nil))> #<STANDARD-CLASS FOO 41300BC883> > > CL-USER 50 > (defmethod clos:slot-value-using-class :before ((class clos:standard-class) (a-foo foo) (slot (eql 'bar))) > (print (list class a-foo slot))) Why the `before' method on `clos:slot-value-using-class' rather than directly on `foo-bar'? -- Scott |
|
#7
| |||
| |||
| In article <9166529b-3d93-4acf-9082-a242416aead5@l33g2000pri.googlegroups.com>, Scott Burson <FSet.SLB@gmail.com> wrote: > On Aug 26, 7:31 am, Rainer Joswig <jos...@lisp.de> wrote: > > > > CL-USER 49 > (defclass foo () ((bar :accessor foo-bar)) ( ptimize-slot-access nil))> > #<STANDARD-CLASS FOO 41300BC883> > > > > CL-USER 50 > (defmethod clos:slot-value-using-class :before ((class clos:standard-class) (a-foo foo) (slot (eql 'bar))) > > (print (list class a-foo slot))) > > Why the `before' method on `clos:slot-value-using-class' rather than > directly on `foo-bar'? > > -- Scott As I said, usually it is better to extend the accessor function with a :before method. But sometimes there are no accessors or you want to make sure that all operations that read/write a slot are extended/changed. Readers and writers are implemented via SLOT-VALUE. So the reader and writer are a higher-level mechanism. SLOT-VALUE-USING-CLASS is the lowest-level (when the MOP is used). Extending SLOT-VALUE-USING-CLASS will the have effect on SLOT-VALUE and the reader/writer methods. For example you can write code using SLOT-VALUE-USING-CLASS to retrieve a slot value from a database/object store/persistent heap/... and then SLOT-VALUE and the reader/writer methods are all using this mechanism. -- http://lispm.dyndns.org/ |
|
#8
| |||
| |||
| On Tue, 26 Aug 2008 09:16:14 -0700, Thomas A. Russ wrote: > Tamas K Papp <tkpapp@gmail.com> writes: > >> I am saving information in an object, and certain slots require a time- >> consuming calculation. I can leave these slots uninitialized and call >> the function that calculates them, eg > ... >> 2. slot-value is a normal function, not a method, so I can't write a >> :before method. Is there a way to achieve what I want? > > The simplest solution is to access the slots using accessor functions > and not by using SLOT-VALUE. That way you can easily control what > happens during slot access, since you have programmatic control of the > accesses. > > You can, as Rainer Joswig mentions, use :BEFORE methods. You can also > test slot for values with SLOT-BOUNDP. Thanks for all the replies. I ended up using Zach's solution (method for slot-unbound), because that always works, even if slot-value is used. But I will keep the solution using accessors in mind when I need something more complex. Anyhow, lazy slots reduced my code about 40% (when measured in lines), and the gains in simplicity are not easily quantifiable but are also amazing. Thanks, Tamas |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.