CLOS constructors - lisp

This is a discussion on CLOS constructors - lisp ; I am a newbie to CLOS and I'm wondering if the following is possible: I want to have an initform for a slot which is a function of the value of another slot. For example: I create a class with ...

+ Reply to Thread
Page 1 of 3 1 2 3 LastLast
Results 1 to 10 of 24

CLOS constructors

  1. Default CLOS constructors

    I am a newbie to CLOS and I'm wondering if the following is possible:
    I want to have an initform for a slot which is a function of the value
    of another slot. For example: I create a class with two slots, the
    first one is initialized with a number, and the second slot should be
    initialized with twice the value of the first slot, everytime I call
    make-instance:

    (defclass test ()
    ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
    (slot1 :accessor slot1 :initform (* 2 slot0))))

    (Obviously the above doesn't work)
    How is it possible to do this? How can you refer to slots within the
    same class? AFAIK this is possible with structures, so is CLOS more
    limited?
    TIA

  2. Default Re: CLOS constructors

    On Dec 10, 1:53 pm, proton <leosara...@gmail.com> wrote:
    > I am a newbie to CLOS and I'm wondering if the following is possible:
    > I want to have an initform for a slot which is a function of the value
    > of another slot. For example: I create a class with two slots, the
    > first one is initialized with a number, and the second slot should be
    > initialized with twice the value of the first slot, everytime I call
    > make-instance:
    >
    > (defclass test ()
    > ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
    > (slot1 :accessor slot1 :initform (* 2 slot0))))
    >
    > (Obviously the above doesn't work)
    > How is it possible to do this? How can you refer to slots within the
    > same class? AFAIK this is possible with structures, so is CLOS more
    > limited?
    > TIA


    see defmethod initialize-instance :after

  3. Default Re: CLOS constructors

    On Dec 10, 10:57 pm, Jason <jeme...@gmail.com> wrote:
    > On Dec 10, 1:53 pm, proton <leosara...@gmail.com> wrote:
    >
    >
    >
    > > I am a newbie to CLOS and I'm wondering if the following is possible:
    > > I want to have an initform for a slot which is a function of the value
    > > of another slot. For example: I create a class with two slots, the
    > > first one is initialized with a number, and the second slot should be
    > > initialized with twice the value of the first slot, everytime I call
    > > make-instance:

    >
    > > (defclass test ()
    > > ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
    > > (slot1 :accessor slot1 :initform (* 2 slot0))))

    >
    > > (Obviously the above doesn't work)
    > > How is it possible to do this? How can you refer to slots within the
    > > same class? AFAIK this is possible with structures, so is CLOS more
    > > limited?
    > > TIA

    >
    > see defmethod initialize-instance :after


    Thanks a lot. That was quick and right on target!

  4. Default Re: CLOS constructors

    On Dec 10, 2:23 pm, proton <leosara...@gmail.com> wrote:
    > On Dec 10, 10:57 pm, Jason <jeme...@gmail.com> wrote:
    >
    >
    >
    > > On Dec 10, 1:53 pm, proton <leosara...@gmail.com> wrote:

    >
    > > > I am a newbie to CLOS and I'm wondering if the following is possible:
    > > > I want to have an initform for a slot which is a function of the value
    > > > of another slot. For example: I create a class with two slots, the
    > > > first one is initialized with a number, and the second slot should be
    > > > initialized with twice the value of the first slot, everytime I call
    > > > make-instance:

    >
    > > > (defclass test ()
    > > > ((slot0 :accessor slot0 :initform 3 :initarg :slot0)
    > > > (slot1 :accessor slot1 :initform (* 2 slot0))))

    >
    > > > (Obviously the above doesn't work)
    > > > How is it possible to do this? How can you refer to slots within the
    > > > same class? AFAIK this is possible with structures, so is CLOS more
    > > > limited?
    > > > TIA

    >
    > > see defmethod initialize-instance :after

    >
    > Thanks a lot. That was quick and right on target!


    CLOS is really handy. It's not too big and not too small to do clever
    stuff. In addition to the initialize-instance trick, there's
    also a trick you can do with lazy evaluation; I do this frequently
    with class definitions containing heavy calculations that you
    don't want to evaluate at initialization time. Bear with me ... there
    may be a few syntax glitches:

    Define a class generic class:

    (in-package :my-workspace)

    (defclass product ()
    ((parent
    :initarg arent
    :reader parent)
    (index
    :initarg :index
    :reader index)))

    ;; I've added a few extra slots here; they're handy for establishing
    product-structure.
    ;; If you define the slots against a special package (one where you
    are unlikely have
    ;; function vs. generic function problems), you can avoid name-space
    collisions. I
    ;; call mine "iv"...

    (in-package :cl-user)

    (defpackage "iv"
    (:nicknames :IV :iv "IV")
    (:use :cl-user :ccl :cl)) ;; Mac Common Lisp -- got to cover
    all the bases

    ;; Now redefine extended-class declaring the slot-names with the
    package defined for
    ;; this purpose and make handing initialization arguments to the slots
    optional:

    (in-package :my-workspace) ;; or whatever your package is

    (defclass product ()
    ((iv:arent
    :initarg arent
    :reader iv:arent)
    (iv::index
    :initarg :index
    :reader iv::index))
    (:default-initargs arent nil :index nil))

    ;; Define a couple of lazy evaluation helper methods that retrieve the
    cached
    ;; slot value or calculates, saves, and returns the value:

    (defmethod eval-iv ((self product) (iv symbol) (rule function))
    (if (slot-exists-p self iv)
    (if (slot-boundp self iv)
    (slot-value self iv)
    (setf (slot-value self iv) (funcall rule self)))
    (error "No IV slot ~a exists for product instance ~a." iv self)))

    (defmethod eval-iv ((self product) (iv symbol) (rule t))
    (if (slot-exists-p self iv)
    (if (slot-boundp self iv)
    (slot-value self iv)
    (setf (slot-value self iv) rule))
    (error "No IV slot ~a exists for product instance ~a." iv self)))

    ;; Now do something interesting with your class...

    (defclass box (product)
    ((iv::depth :initarg :depth :reader iv::depth)
    (iv::width :initarg :width :reader iv::width)
    (iv::height :initarg :height :reader iv::height)
    (iv::volume)
    (iv::boxes))
    (:default-initargs :depth 1.0 :width 1.0 :height 1.0))

    ;; ...and define the reader/evaluator methods for the slots that don't
    have a reader specified:

    (defmethod iv::volume ((self box))
    (eval-iv
    self
    'iv::volume
    #'(lambda(self)(* (iv::depth self) (iv::width self) (iv::height
    self)))))

    ;; The rule for this slot is volume = depth x width x height

    (defmethod iv::boxes ((self box))
    (eval-iv
    self
    'iv::boxes
    #'(lambda(self)
    (mapcar
    #'(lambda(index)(make-instance 'box
    arent self
    :index index
    :depth (* (iv::depth self) 0.5)
    :width (* (iv::width self) 0.5)
    :height (* (iv::height self) 0.5)))
    '(0 1 2)))))

    ;; The rule for this slot is: make 3 boxes with dimensions half the
    size of the parent's dimensions.

    ;; Now try it:

    (setq my-box (make-instance 'box :depth 2.0 :width 3.0 :height 4.0))

    #<BOX #x9C27CA6>

    ;; At this point , slots iv::volume and iv::boxes are unbound.

    (iv::volume my-box)

    24.0

    (iv::boxes my-box)

    (#<BOX #x9D515CE> #<BOX #x9D528E6> #<BOX #x9D537B6>)


    ;; This is a stupid example and the class methods for volume and child
    boxes are
    ;; implemented in a simplistic way for demo purposes, but you should
    get the idea.
    ;; I have taken this step further and wrapped a macro around the whole
    thing (defproduct)
    ;; in which I can define inputs, optional inputs, quantified child
    products, descendant
    ;; slot values (all child products inherit the value from an
    ancestor), and more
    ;; non-caching instance methods. I also define a macro called THIS
    which implicitly
    ;; defines the SELF variable for the method expression so that you can
    define the slot
    ;; method (the "rule") with a reference to the class instance itself
    (which was your
    ;; original issue.) defmacro is your friend.

    #'M

  5. Default Re: CLOS constructors

    > CLOS is really handy. It's not too big and not too small to do clever
    > stuff. In addition to the initialize-instance trick, there's
    > also a trick you can do with lazy evaluation; I do this frequently
    > with class definitions containing heavy calculations that you
    > don't want to evaluate at initialization time. Bear with me ... there
    > may be a few syntax glitches:


    http://common-lisp.net/project/computed-class/ does that transparently
    as a MOP extension. cells, too.

    - attila

  6. Default Re: CLOS constructors

    attila.lendvai@gmail.com wrote:
    >> CLOS is really handy. It's not too big and not too small to do clever
    >> stuff. In addition to the initialize-instance trick, there's
    >> also a trick you can do with lazy evaluation; I do this frequently
    >> with class definitions containing heavy calculations that you
    >> don't want to evaluate at initialization time. Bear with me ... there
    >> may be a few syntax glitches:

    >
    > http://common-lisp.net/project/computed-class/ does that transparently
    > as a MOP extension. cells, too.


    A pretty straightforward way is also this:

    (defclass foo ()
    ((a :initarg :a :initform 0 :reader a)
    (b :reader b)))

    (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
    (setf (slot-value object 'b)
    (1+ (slot-value object 'a))))

    > (defvar *bar* (make-instance 'foo :a 5))

    *BAR*

    > (b *bar*)

    6

    The nice thing about this is that you don't have to check for slot
    unboundness yourself, but can rely on the CLOS implementation to do this
    for you. This is probably more efficient than having calls for
    slot-boundp in your own code. You can also force recomputation by
    calling slot-makunbound on the respective slots. (I have used that
    technique in a few places, and it works like a charm.)

    There is also a generic function slot-missing where you can do similar
    things for missing slots. For example, it is very straightforward to
    implement Python-style hashtable-based slots via slot-missing without
    having to go through the CLOS MOP at all this way.


    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/

  7. Default Re: CLOS constructors

    On Dec 11, 9:52 am, Pascal Costanza <p...@p-cos.net> wrote:
    > attila.lend...@gmail.com wrote:
    > >> CLOS is really handy. It's not too big and not too small to do clever
    > >> stuff. In addition to the initialize-instance trick, there's
    > >> also a trick you can do with lazy evaluation; I do this frequently
    > >> with class definitions containing heavy calculations that you
    > >> don't want to evaluate at initialization time. Bear with me ... there
    > >> may be a few syntax glitches:

    >
    > >http://common-lisp.net/project/computed-class/does that transparently
    > > as a MOP extension. cells, too.

    >
    > A pretty straightforward way is also this:
    >
    > (defclass foo ()
    > ((a :initarg :a :initform 0 :reader a)
    > (b :reader b)))
    >
    > (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
    > (setf (slot-value object 'b)
    > (1+ (slot-value object 'a))))
    >
    > > (defvar *bar* (make-instance 'foo :a 5))

    > *BAR*
    >
    > > (b *bar*)

    > 6
    >
    > The nice thing about this is that you don't have to check for slot
    > unboundness yourself, but can rely on the CLOS implementation to do this
    > for you. This is probably more efficient than having calls for
    > slot-boundp in your own code. You can also force recomputation by
    > calling slot-makunbound on the respective slots. (I have used that
    > technique in a few places, and it works like a charm.)
    >
    > There is also a generic function slot-missing where you can do similar
    > things for missing slots. For example, it is very straightforward to
    > implement Python-style hashtable-based slots via slot-missing without
    > having to go through the CLOS MOP at all this way.
    >
    > Pascal


    Very nice trick, thank you Pascal.

    Slobodan
    http://tourdelisp.blogspot.com
    >
    > --
    > My website:http://p-cos.net
    > Common Lisp Document Repository:http://cdr.eurolisp.org
    > Closer to MOP & ContextL:http://common-lisp.net/project/closer/



  8. Default Re: CLOS constructors

    On Dec 11, 9:52 pm, Pascal Costanza <p...@p-cos.net> wrote:

    [[ ... ]]

    > >> also a trick you can do with lazy evaluation; I do this frequently
    > >> with class definitions containing heavy calculations that you


    [[ ... ]]

    >
    > A pretty straightforward way is also this:
    >
    > (defclass foo ()
    > ((a :initarg :a :initform 0 :reader a)
    > (b :reader b)))
    >
    > (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
    > (setf (slot-value object 'b)
    > (1+ (slot-value object 'a))))
    >
    > > (defvar *bar* (make-instance 'foo :a 5))

    > *BAR*
    >
    > > (b *bar*)

    > 6
    >
    > The nice thing about this is that you don't have to check for slot
    > unboundness yourself, but can rely on the CLOS implementation to do this
    > for you. This is probably more efficient than having calls for
    > slot-boundp in your own code. You can also force recomputation by
    > calling slot-makunbound on the respective slots. (I have used that
    > technique in a few places, and it works like a charm.)
    >
    > There is also a generic function slot-missing where you can do similar
    > things for missing slots. For example, it is very straightforward to
    > implement Python-style hashtable-based slots via slot-missing without
    > having to go through the CLOS MOP at all this way.
    >


    Wow, this is cool. I didn't know this, but it
    is so similar to the doesNotUnderstand message
    for handling most "errors" in Smalltalk. I was
    too slow, but was gonna suggest doing it with
    a :before method. Not sure if it's better.

    (defclass test ()
    ((a :accessor a
    :initarg :a)
    (b :accessor b
    :initarg :b)
    (lazy-product :accessor prod)))


    (defmacro def-lazy-slot (accessor-name ((obj class) slot-name) &body
    body)
    `(defmethod ,accessor-name :before ((,obj ,class))
    (when (not (slot-boundp ,obj ',slot-name))
    (setf (slot-value ,obj ',slot-name)
    (progn
    ,@body)))))

    (def-lazy-slot prod ((self test) lazy-product)
    (* (a self) (b self)))

    which macroexpands to

    (DEFMETHOD PROD :BEFORE ((SELF TEST))
    (WHEN (NOT (SLOT-BOUNDP SELF 'LAZY-PRODUCT))
    (SETF (SLOT-VALUE SELF 'LAZY-PRODUCT)
    (PROGN (* (A SELF) (B SELF))))))


  9. Default Re: CLOS constructors

    szergling wrote:
    > On Dec 11, 9:52 pm, Pascal Costanza <p...@p-cos.net> wrote:
    >
    > [[ ... ]]
    >
    >>>> also a trick you can do with lazy evaluation; I do this frequently
    >>>> with class definitions containing heavy calculations that you

    >
    > [[ ... ]]
    >
    >> A pretty straightforward way is also this:
    >>
    >> (defclass foo ()
    >> ((a :initarg :a :initform 0 :reader a)
    >> (b :reader b)))
    >>
    >> (defmethod slot-unbound (class (object foo) (slot (eql 'b)))
    >> (setf (slot-value object 'b)
    >> (1+ (slot-value object 'a))))
    >>
    >> > (defvar *bar* (make-instance 'foo :a 5))

    >> *BAR*
    >>
    >> > (b *bar*)

    >> 6
    >>
    >> The nice thing about this is that you don't have to check for slot
    >> unboundness yourself, but can rely on the CLOS implementation to do this
    >> for you. This is probably more efficient than having calls for
    >> slot-boundp in your own code. You can also force recomputation by
    >> calling slot-makunbound on the respective slots. (I have used that
    >> technique in a few places, and it works like a charm.)
    >>
    >> There is also a generic function slot-missing where you can do similar
    >> things for missing slots. For example, it is very straightforward to
    >> implement Python-style hashtable-based slots via slot-missing without
    >> having to go through the CLOS MOP at all this way.
    >>

    >
    > Wow, this is cool. I didn't know this, but it
    > is so similar to the doesNotUnderstand message
    > for handling most "errors" in Smalltalk. I was
    > too slow, but was gonna suggest doing it with
    > a :before method. Not sure if it's better.
    >
    > (defclass test ()
    > ((a :accessor a
    > :initarg :a)
    > (b :accessor b
    > :initarg :b)
    > (lazy-product :accessor prod)))
    >
    >
    > (defmacro def-lazy-slot (accessor-name ((obj class) slot-name) &body
    > body)
    > `(defmethod ,accessor-name :before ((,obj ,class))
    > (when (not (slot-boundp ,obj ',slot-name))
    > (setf (slot-value ,obj ',slot-name)
    > (progn
    > ,@body)))))
    >
    > (def-lazy-slot prod ((self test) lazy-product)
    > (* (a self) (b self)))
    >
    > which macroexpands to
    >
    > (DEFMETHOD PROD :BEFORE ((SELF TEST))
    > (WHEN (NOT (SLOT-BOUNDP SELF 'LAZY-PRODUCT))
    > (SETF (SLOT-VALUE SELF 'LAZY-PRODUCT)
    > (PROGN (* (A SELF) (B SELF))))))


    Well, there are two things to note:

    - Whenever you call slot-value or a reader on a slot, CLOS has to do the
    unboundness check anyway. So idioms like (and (slot-boundp object
    some-slot) (slot-value object some-slot)) actually result in two checks
    for unboundness, which is not so efficient.

    - Reader methods are especially optimized to yield fast slot accesses. I
    don't know what impact before/after/around on slot accessors actually
    have in terms of performance, but I'd be careful here.

    - Methods on slot-unbound avoid all these potential performance issues
    from the start.

    There is also a potential problem wrt to multi-threading: In between
    your own slot-boundp check and the eventual call to slot-value, another
    thread might perform a slot-makunbound on the slot in question. In
    general, it is better not to perform such checks explicitly, but rather
    delegate this to an implicit check where you can react to exceptional
    situations where your assumptions don't hold. (Methods on slot-unbound
    are an example for this.) This should help you to better avoid race
    conditions.

    This is only a hypothetical remark, though, since CLOS and
    multithreading don't go that well together, and you have to be more
    careful than that anyway...


    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/

  10. Default Re: CLOS constructors

    On Dec 11, 10:27 am, szergling <senatorZergl...@gmail.com> wrote:
    > On Dec 11, 9:52 pm, Pascal Costanza <p...@p-cos.net> wrote:


    > > There is also a generic function slot-missing where you can do similar
    > > things for missing slots. For example, it is very straightforward to
    > > implement Python-style hashtable-based slots via slot-missing without
    > > having to go through the CLOS MOP at all this way.

    >
    > Wow, this is cool. I didn't know this, but it
    > is so similar to the doesNotUnderstand message
    > for handling most "errors" in Smalltalk.


    Yes, slot-missing and slot-unbound are kind of like doesNotUnderstand
    for slot access. no-applicable-method is even more like
    doesNotUnderstand in that it gives you a hook into the machinery where
    no method was found; however, due partly to the way CLOS generic
    functions work, and partly to its design, it's not an especially
    useful hook.


+ Reply to Thread
Page 1 of 3 1 2 3 LastLast

Similar Threads

  1. C++ to CLOS mapping
    By Application Development in forum lisp
    Replies: 53
    Last Post: 12-30-2007, 12:18 PM
  2. Few Questions about CLOS?
    By Application Development in forum lisp
    Replies: 4
    Last Post: 10-04-2007, 05:30 PM
  3. Copy Constructors vs Move Constructors
    By Application Development in forum c++
    Replies: 3
    Last Post: 08-04-2007, 01:34 PM
  4. CLOS question
    By Application Development in forum lisp
    Replies: 14
    Last Post: 08-01-2007, 03:41 AM
  5. Replies: 5
    Last Post: 06-07-2007, 06:09 AM