defstruct constructor uses slot-names in lambda list.

Bug #984813 reported by Nikodemus Siivola
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Triaged
Low
Unassigned

Bug Description

Norbert Paul <email address hidden> via lists.sourceforge.net to sbcl-bugs

Hi,

reading the hyperspec on defstruct I stumbled over what I consider a bug in
sbcl:

When I do
  (macroexpand '(defstruct (boa (:constructor make-boa (b o a))) b o a))
in sbcl I get
  (PROGN
   #<stuff>
   ;; and
   (DEFUN MAKE-BOA (B O A)
     (SB-KERNEL::%MAKE-STRUCTURE-INSTANCE-MACRO
      #<SB-KERNEL:DEFSTRUCT-DESCRIPTION BOA>
      '((:SLOT T . 1) (:SLOT T . 2) (:SLOT T . 3)) B O A))
   (LOCALLY (DECLARE (NOTINLINE SB-KERNEL:FIND-CLASSOID)))
   'BOA).

Note that it uses the slot symbols b, o, and a as parameters for
make-boa. Doesn't this violate the specification, as the hyperspec says

  "The symbols which name the slots must not be used by the implementation
   as the names for the lambda variables in the constructor function, since
   one or more of those symbols might have been proclaimed special or might
   be defined as the name of a constant variable."?

In fact,
  (defconstant c 'a-constant)
  (defstruct (boo (:constructor make-boo (c))) c)
generates the error
  ; C names a defined constant, and cannot be used as a local variable.

A solution could be to replace each argument SYM by (make-symbol (symbol-mane SYM)).
I am using SBCL 1.0.52 on Debian Linux.

Regards
Norbert

Revision history for this message
Nikodemus Siivola (nikodemus) wrote :

Actually, I'm having second thoughts.

Consider:

(defvar *foo* (list 1 2))

(defun bar ()
  (car *foo*))

(defstruct (foo (:constructor make-foo (*foo* &aux (bar (bar)))))
  *foo*
  bar)

(let ((foo (make-foo (list 'a 'b))))
  (list (foo-*foo* foo) (foo-bar foo))) ; => ((A B) A)

It is not clear to me that this is wrong, and that ((A B) 1) would be right. Renaming user-specified arguments strikes me as suspect: the spec talks about implementation not being allowed to do X, but this is the user explicitly specifying something.

Granted, /not/ considering this a bug means that you cannot use a boa-constructor if you name a slot with a symbol also used as a defconstant or defglobal.

Hm.

tags: added: defstruct
Nick Levine (ndl)
Changed in sbcl:
assignee: nobody → Nick Levine (ndl)
Nick Levine (ndl)
Changed in sbcl:
assignee: Nick Levine (ndl) → nobody
Revision history for this message
Steve Losh (stevelosh) wrote :

For what it's worth, CLtL2 seems to agree that the user-specified names should be used. In https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node174.html there's the following example:

(defstruct (ice-cream-factory
             (:constructor fabricate-factory
               (&key (capacity 5)
                      location
                      (local-flavors
                        (case location
                          ((hawaii) '(pineapple macadamia guava))
                          ((massachusetts) '(lobster baked-bean))
                          ((california) '(ginger lotus avocado bean-sprout garlic))
                          ((texas) '(jalapeno barbecue))))
                      (flavors (subseq (append local-flavors
                                               '(vanilla chocolate strawberry pistachio maple-walnut peppermint))
                                       0 capacity)))))
  (capacity 3)
  (flavors '(vanilla chocolate strawberry mango)))

The flavors argument refers back to the capacity argument, which is also the name of a slot.

Unfortunately as far as I can tell the standard itself carefully avoids giving any explicit examples like this. The bit about the restriction on naming comes in the section where it's talking about the default keyword-style constructor function that defstruct creates, and it specifically says "THE constructor function" (emphasis mine), so I guess it could be argued it only applies to the default constructor function and not BOA constructors.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.