[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

change-class if the slot was unbound, it remains unbound.

Jim Newton

7/30/2015 8:59:00 AM

I always forget about this.

If I have an instance of a class which has a particular slot unbound, and I change the class of an instance with change-class to a new class which provides a :initform for a slot, I intuitively expect that initform to be evaluated and the slot initialised. But alas it does not.

http://www.lispworks.com/documentation/HyperSpec/Body/f_...

---> If in the old class there is any slot of the same name as a local slot in the new-class, the value of that slot is retained. This means that if the slot has a value, the value returned by slot-value after change-class is invoked is eql to the value returned by slot-value before change-class is invoked. Similarly, if the slot was unbound, it remains unbound. The other slots are initialized as described in Section 7.2 (Changing the Class of an Instance).

13 Answers

Kenneth Tilton

7/30/2015 9:28:00 AM

0

On Thursday, July 30, 2015 at 4:59:31 AM UTC-4, Jim Newton wrote:
> I always forget about this.

Try remembering this: slot-exists-p and slot-boundp are two different things.

hth, kt

ps. Look at that deviant hyphenation. Lisp sucks!

>
> If I have an instance of a class which has a particular slot unbound, and I change the class of an instance with change-class to a new class which provides a :initform for a slot, I intuitively expect that initform to be evaluated and the slot initialised. But alas it does not.
>
> http://www.lispworks.com/documentation/HyperSpec/Body/f_...
>
> ---> If in the old class there is any slot of the same name as a local slot in the new-class, the value of that slot is retained. This means that if the slot has a value, the value returned by slot-value after change-class is invoked is eql to the value returned by slot-value before change-class is invoked. Similarly, if the slot was unbound, it remains unbound. The other slots are initialized as described in Section 7.2 (Changing the Class of an Instance).

Pascal Costanza

7/30/2015 10:24:00 AM

0

On 30/07/2015 10:59, Jim Newton wrote:
> I always forget about this.
>
> If I have an instance of a class which has a particular slot unbound, and I change the class of an instance with change-class to a new class which provides a :initform for a slot, I intuitively expect that initform to be evaluated and the slot initialised. But alas it does not.
>
> http://www.lispworks.com/documentation/HyperSpec/Body/f_...
>
> ---> If in the old class there is any slot of the same name as a local slot in the new-class, the value of that slot is retained. This means that if the slot has a value, the value returned by slot-value after change-class is invoked is eql to the value returned by slot-value before change-class is invoked. Similarly, if the slot was unbound, it remains unbound. The other slots are initialized as described in Section 7.2 (Changing the Class of an Instance).

You can define methods on change-class and/or
update-instance-for-different-class to change that behavior.

Pascal

--
My website: http:/...
Common Lisp Document Repository: http://cdr.eu...
Closer to MOP & ContextL: http://common-lisp.net/proje...
The views expressed are my own, and not those of my employer.

Jim Newton

7/30/2015 11:56:00 AM

0

Yes exactly, or I can simply set the slot directly after calling change-class.
I just seem to always forget this rule. It does not seem correct, but it is according to the spec.

Jim Newton

7/30/2015 12:08:00 PM

0

BTW Pascal, do you know if I am allowed to changed the class of an object within initialise-instance :after. The case I have is that for particular combinations of initialisation arguments, I have more specific information, and am tempted to change the class to a more specific subclass ?

However, it sounds dangerous, as this might cause a discrepancy in the applicable methods to shared-initialize for example.

Kaz Kylheku

7/30/2015 12:45:00 PM

0

On 2015-07-30, Jim Newton <jimka.issy@gmail.com> wrote:
> Yes exactly, or I can simply set the slot directly after calling change-class.
> I just seem to always forget this rule. It does not seem correct, but it is according to the spec.

The rule is obviously correct: don't mess with any slots that
are not being added by the class change.

The function isn't called "change-class-and-patch-holes".

Kaz Kylheku

7/30/2015 1:37:00 PM

0

On 2015-07-30, Jim Newton <jimka.issy@gmail.com> wrote:
> Yes exactly, or I can simply set the slot directly after calling change-class.
> I just seem to always forget this rule. It does not seem correct, but it is
> according to the spec.

You might be thinking that the value of a slot is part of the object's type
in your scheme.

We are changing an A to a B. A B always initializes the slot, and so if that
doesn't happen, then the A to B change is invalid.

But slots values aren't part of the type. Except maybe :allocation :class
slots. That may be the right way to design things.

Suppose we have a tricycle, and tricycle has a wheels slot with a value 3.
We change-class to a car, and cars have wheels slot with value 4.
The change-class will not do anything with this value; so we end up with
a car whose wheels slot is 3.

But the number of wheels is a property of the class, not of the instance.
(Let's assume for this exercise that all cars have four wheels, which is
false).

If we make the wheels slot ":allocation class" in tricycle and car
classes, then that takes care of it.

See what you make of this:

(defclass vehicle ()
((wheels :accessor wheels)))

(defclass tricycle (vehicle)
((wheels :initform 3 :allocation :class)))

(defclass auto (vehicle)
((wheels :initform 4 :allocation :class)))

(defparameter *thing* (make-class 'vehicle))

(wheels *thing*) -> #| error condition: unbound slot |#

(change-class *thing* 'auto)

(wheels *thing*) -> 4 ;; see? unbound slot went to 4 "auto"-magically!

(change-class *thing* 'tricycle)

(wheels *thing*) -> 3 ;; and 4 even changed to 3.

(change-class *thing* 'vehicle)

(wheels *thing*) -> 3 ;; 3 stays as 3 (going from :class to :instance).

Kenneth Tilton

7/30/2015 1:38:00 PM

0

On Thursday, July 30, 2015 at 6:24:19 AM UTC-4, Pascal Costanza wrote:
> On 30/07/2015 10:59, Jim Newton wrote:
> > I always forget about this.
> >
> > If I have an instance of a class which has a particular slot unbound, and I change the class of an instance with change-class to a new class which provides a :initform for a slot, I intuitively expect that initform to be evaluated and the slot initialised. But alas it does not.
> >
> > http://www.lispworks.com/documentation/HyperSpec/Body/f_...
> >
> > ---> If in the old class there is any slot of the same name as a local slot in the new-class, the value of that slot is retained. This means that if the slot has a value, the value returned by slot-value after change-class is invoked is eql to the value returned by slot-value before change-class is invoked. Similarly, if the slot was unbound, it remains unbound. The other slots are initialized as described in Section 7.2 (Changing the Class of an Instance).
>
> You can define methods on change-class and/or
> update-instance-for-different-class to change that behavior.
>

Don't encourage him. He is fighting the language. Hell, he even considers perfectly intuitive behavior (not initializing a slot that is not being created) as alas-worthy. This is a recurring problem ("I always forget this") so we know he is overusing and abusing change-class -- itself a misguided hack -- evidenced also by the aforesaid intuition failure.

But as always c.l.l finds someway to throw a clever hack anchor to a drowning developer.

-hk

Kenneth Tilton

7/30/2015 1:40:00 PM

0

On Thursday, July 30, 2015 at 7:56:25 AM UTC-4, Jim Newton wrote:
> Yes exactly, or I can simply set the slot directly after calling change-class.
> I just seem to always forget this rule. It does not seem correct, but it is according to the spec.

Like I said, you are confusing the boundedness of a slot with its existence. An initform runs when a slot is created, and you are well aware the slot exists already when you change class.

Jim Newton

7/30/2015 2:06:00 PM

0

Hi Kenny, like I said I agree that the behaviour is as specified, but I don't quite agree with your logic about why it is the way it is. Perhaps you're right w.r.t. the original intent, which I don't know.

> An initform runs when a slot is created, and you are well aware the slot exists already when you change class

Yes an initform apparently only applies exclusively at instance creation time. Yet an initarg (including a default-initarg) is applied not only when the instance is created, but also at change-class time. I can specify an initform as an argument to change-class. And it will be applied, not only if the slot is added, but also if the slot already existed and is still unbound. OK I admit, the initargs given to change-class also apply when the slot is already bound.

Apparently I can effectively get the initform expression to evaluate at change-class time by making it a default-initarg.

Here is an example.

;; EXAMPLE 1
CLIMB-GUI> (defclass A () ((b)))
#<STANDARD-CLASS A>
CLIMB-GUI> (defvar a (make-instance 'A))
A
CLIMB-GUI> (defclass AA (A) ((b :initarg :b)))
#<STANDARD-CLASS AA>
CLIMB-GUI> (change-class a 'AA :b 100)
#<AA {11BA297B53}>
CLIMB-GUI> (slot-value a 'b)
100
CLIMB-GUI> CLIMB-GUI> (defclass A () ((b)))
#<STANDARD-CLASS A>
CLIMB-GUI> (defvar a (make-instance 'A))
A
CLIMB-GUI> (defclass AA (A) ((b :initarg :b)))
#<STANDARD-CLASS AA>
CLIMB-GUI> (change-class a 'AA :b 100)
#<AA {11BA297B53}>
CLIMB-GUI> (slot-value a 'b)
100
CLIMB-GUI>


In addition, the :default-initargs apply on change class as well.

;; EXAMPLE 2
CLIMB-GUI> (defclass A () ((b) (c :initform 12)))
#<STANDARD-CLASS A>
CLIMB-GUI> (defvar a (make-instance 'A))
A
CLIMB-GUI> (defclass AA (A) ((b :initarg :b) (c :initarg :c)) (:default-initargs :b 100 :c 200))
#<STANDARD-CLASS AA>
CLIMB-GUI> (change-class a 'AA)
#<AA {11BA297B53}>
CLIMB-GUI> (slot-value a 'b)
100
CLIMB-GUI> (slot-value a 'c)
200
CLIMB-GUI>

Zach Beane

7/30/2015 2:25:00 PM

0

Jim Newton <jimka.issy@gmail.com> writes:

> Hi Kenny, like I said I agree that the behaviour is as specified, but I don't quite agree with your logic about why it is the way it is. Perhaps you're right w.r.t. the original intent, which I don't know.
>
>> An initform runs when a slot is created, and you are well aware the slot exists already when you change class
>
> Yes an initform apparently only applies exclusively at instance creation time. Yet an initarg (including a default-initarg) is applied not only when the instance is created, but also at change-class time. I can specify an initform as an argument to change-class. And it will be applied, not only if the slot is added, but also if the slot already existed and is still unbound. OK I admit, the initargs given to change-class also apply when the slot is already bound.
>
> Apparently I can effectively get the initform expression to evaluate at change-class time by making it a default-initarg.
>
> Here is an example.
>
> ;; EXAMPLE 1
> CLIMB-GUI> (defclass A () ((b)))
> #<STANDARD-CLASS A>
> CLIMB-GUI> (defvar a (make-instance 'A))
> A
> CLIMB-GUI> (defclass AA (A) ((b :initarg :b)))
> #<STANDARD-CLASS AA>
> CLIMB-GUI> (change-class a 'AA :b 100)
> #<AA {11BA297B53}>
> CLIMB-GUI> (slot-value a 'b)
> 100
> CLIMB-GUI> CLIMB-GUI> (defclass A () ((b)))
> #<STANDARD-CLASS A>
> CLIMB-GUI> (defvar a (make-instance 'A))
> A
> CLIMB-GUI> (defclass AA (A) ((b :initarg :b)))
> #<STANDARD-CLASS AA>
> CLIMB-GUI> (change-class a 'AA :b 100)
> #<AA {11BA297B53}>
> CLIMB-GUI> (slot-value a 'b)
> 100
> CLIMB-GUI>
>
>
> In addition, the :default-initargs apply on change class as well.
>
> ;; EXAMPLE 2
> CLIMB-GUI> (defclass A () ((b) (c :initform 12)))
> #<STANDARD-CLASS A>
> CLIMB-GUI> (defvar a (make-instance 'A))
> A
> CLIMB-GUI> (defclass AA (A) ((b :initarg :b) (c :initarg :c)) (:default-initargs :b 100 :c 200))
> #<STANDARD-CLASS AA>
> CLIMB-GUI> (change-class a 'AA)
> #<AA {11BA297B53}>
> CLIMB-GUI> (slot-value a 'b)
> 100
> CLIMB-GUI> (slot-value a 'c)
> 200
> CLIMB-GUI>

https://www.cs.northwestern.edu/academics/courses/325/readings/graham/chap11-...
has a bit about the strength of default-initargs over initform.

Zach