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

From: Wade Humeniuk
Subject: Re: evaluation of defstruct slot initforms
Date: 
Message-ID: <9lejod$47v$1@news3.cadvision.com>
> 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
From: Kent M Pitman
Subject: Re: evaluation of defstruct slot initforms
Date: 
Message-ID: <sfwk8052hzp.fsf@world.std.com>
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.
From: Marco Antoniotti
Subject: Re: evaluation of defstruct slot initforms
Date: 
Message-ID: <y6cd75xm5hh.fsf@octagon.mrl.nyu.edu>
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