From: Dave MacDonald
Subject: evaluation of defstruct slot initforms
Date:
Message-ID: <871ymdqgsn.fsf@idirect.com>
Consider the following DEFSTRUCT form:
(defstruct (test (:constructor make-test (valA)))
valA
(valB (+ valA 10)))
The intention is to have valB's initform evaluated inside the
constructor, within the scope of valA's binding, by defining make-test
like this:
(defun make-test (valA)
(let ((valB-value (+ valA 10)))
(<system-dependent code to initialize slots valA and valB>)))
This is how CMUCL and SBCL behave.
Another interpretation could be to define make-test like this:
(let ((valB-initfunc (lambda () (+ valA 10))))
(defun make-test (valA &aux (valB (funcall valB-initfunc)))
(<system-dependent code to initialize slots valA and valB>)))
This is how CLISP does it. This causes an error since there is no
valA binding in scope when the initform is evaluated.
Which do people think is correct?
-Dave
> Consider the following DEFSTRUCT form:
>
> (defstruct (test (:constructor make-test (valA)))
> valA
> (valB (+ valA 10)))
>
...
> Which do people think is correct?
Neither.
CL-USER 28 > (defclass test ()
((vala :initarg :vala :initform 0)
(valb :initarg :valb :initform nil)))
#<STANDARD-CLASS TEST 2103146C>
CL-USER 29 > (defmethod initialize-instance :after ((test test) &rest
initargs)
(with-slots (vala valb) test
(setf valb (+ vala 10))))
#<STANDARD-METHOD INITIALIZE-INSTANCE (:AFTER) (TEST) 204072C4>
CL-USER 30 > (setf test (make-instance 'test :vala 10))
#<TEST 2041A4A4>
CL-USER 31 > (describe test)
#<TEST 2041A4A4> is a TEST
VALA 10
VALB 20
CL-USER 32 >
You could also create a new defstruct macro which allows the kind of slot
initialization you are looking for. However its more work than it is worth.
Wade
From: Dave MacDonald
Subject: Re: evaluation of defstruct slot initforms
Date:
Message-ID: <87vgjpoyhw.fsf@idirect.com>
"Wade Humeniuk" <········@cadvision.com> writes:
> > Consider the following DEFSTRUCT form:
> >
> > (defstruct (test (:constructor make-test (valA)))
> > valA
> > (valB (+ valA 10)))
> >
> ...
> > Which do people think is correct?
>
> Neither.
>
> CL-USER 28 > (defclass test ()
> ((vala :initarg :vala :initform 0)
> (valb :initarg :valb :initform nil)))
> #<STANDARD-CLASS TEST 2103146C>
[...]
Maybe a better question is "What is the correct result of evaluating
the DEFSTRUCT form?"
I understand that CLOS provides a more straightforward way to achieve
a similar result, but it doesn't help me determine who I should file a
bug-report with.
I'm trying to use CLISP to bootstrap SBCL, and the above idiom in the
SBCL sources makes CLISP generate an error.
I interpret the CLHS as not requiring the first behavior, but not
disallowing it either. I guess this means that a plausible answer is
"Both are correct, but portable code should not depend on the first
behavior." In that case, SBCL gets the bug report. But, I'm just a
beginner, so I'm interested in what others think.
-Dave
Dave MacDonald <······@idirect.com> writes:
> Consider the following DEFSTRUCT form:
>
> (defstruct (test (:constructor make-test (valA)))
> valA
> (valB (+ valA 10)))
This refers to a free variable valA. The slot bindings are not bound
when the efault slots are evaluated. You want
(defstruct (test (:constructor make-test (valA &aux (valB (+ valA 10)))))
valA valB)
See the description of DEFSTRUCT in CLHS and the associated description
of "boa constructors".
>
> The intention is to have valB's initform evaluated inside the
> constructor, within the scope of valA's binding, by defining make-test
> like this:
>
> (defun make-test (valA)
> (let ((valB-value (+ valA 10)))
> (<system-dependent code to initialize slots valA and valB>)))
>
> This is how CMUCL and SBCL behave.
I think I don't think this is right.
> Another interpretation could be to define make-test like this:
>
> (let ((valB-initfunc (lambda () (+ valA 10))))
> (defun make-test (valA &aux (valB (funcall valB-initfunc)))
> (<system-dependent code to initialize slots valA and valB>)))
>
> This is how CLISP does it. This causes an error since there is no
> valA binding in scope when the initform is evaluated.
I think I think this is right.
Kent M Pitman <······@world.std.com> writes:
> Dave MacDonald <······@idirect.com> writes:
>
> > Consider the following DEFSTRUCT form:
> >
> > (defstruct (test (:constructor make-test (valA)))
> > valA
> > (valB (+ valA 10)))
>
> This refers to a free variable valA. The slot bindings are not bound
> when the efault slots are evaluated. You want
>
> (defstruct (test (:constructor make-test (valA &aux (valB (+ valA 10)))))
> valA valB)
>
> See the description of DEFSTRUCT in CLHS and the associated description
> of "boa constructors".
The following will also maintain the "look and feel" of defstruct
constructors.
(defstruct (test (:constructor make-test (&key valA (valB (+ valA 10)))))
(valA 0) ; Just to be sure to have a "good" initial value.
valB)
or
(defstruct (test (:constructor make-test (&key (valA 0) (valB (+ valA 10)))))
valA
valB)
I do not know how conformant these would be though (I have not checked
the CLHS).
Cheers
--
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488
719 Broadway 12th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://bioinformatics.cat.nyu.edu
"Hello New York! We'll do what we can!"
Bill Murray in `Ghostbusters'.
From: Dave MacDonald
Subject: Re: evaluation of defstruct slot initforms
Date:
Message-ID: <87r8udoy0e.fsf@idirect.com>
Kent M Pitman <······@world.std.com> writes:
> Dave MacDonald <······@idirect.com> writes:
>
> > Consider the following DEFSTRUCT form:
> >
> > (defstruct (test (:constructor make-test (valA)))
> > valA
> > (valB (+ valA 10)))
>
> This refers to a free variable valA. The slot bindings are not bound
> when the efault slots are evaluated. You want
>
> (defstruct (test (:constructor make-test (valA &aux (valB (+ valA 10)))))
> valA valB)
>
> See the description of DEFSTRUCT in CLHS and the associated description
> of "boa constructors".
>
Yes, I had read this section, but I failed to come to a conclusion
about whether this is conforming or not. And neither did I see the
possibility of using this idiom; thanks for pointing it out.
-Dave