1

In most implementations, you can use (make-instance 'struct-type) to create a struct regardless of whether you defined a constructor function for that type. This doesn't work on Allegro or ABCL, but those implementations can still create structs at read-time with #S(struct-type), which makes me think there must be some other way to construct them at runtime given the type name as a symbol.

Kyle
  • 178
  • 1
  • 8
  • What exactly are you trying to achieve? – acelent May 05 '15 at 08:53
  • Declarative specifications for generating test data: https://github.com/DalekBaldwin/check-it#struct-generator . I was hoping for simple, portable ways to get extract the information I need through introspection, but I'm prepared to go under the hood and handle each implementation separately if it comes down to that. – Kyle May 05 '15 at 11:20

3 Answers3

1

You shouldn't mix structure and object creation. The standard defined make-instance for standard-class, and for symbol such that the provided symbol is passed to find-class, then make-instance recurses.

As such, a stock implementation that extends make-instance for named structure types is not conforming, and neither is your code if you rely on it.

Then, #S is specified to work correctly only if the structure has a standard constructor, so there's not much magic left there.

Given this restriction, you could implement #S yourself by interning a symbol named make- concatenated with the structure name, followed by the keyword argument list.

But again, the implementation dependent details hit. You ask about when there's no constructor, which implies :constructor nil in defstruct. Note that not specifying the constructor argument means it'll have a default constructor. The implementation can have internal bookkeeping, including a hidden standard constructor that it creates regardless of your options (or a parameterless constructor and slot accessors) to be used in make-load-form-using-slots, an extended #S, and possibly to optimize literal structure loading (as opposed to forms that create one) in file compilation through make-load-form's specialization for structures.

acelent
  • 7,965
  • 21
  • 39
  • So if I'm reading you right, there's no way to portably ask for a list of available constructors? I'd like to get your thoughts on my proposed solution too: http://stackoverflow.com/questions/30030304/in-allegro-cl-and-abcl-can-i-construct-a-struct-given-only-its-type-name/30042130#30042130 – Kyle May 05 '15 at 00:22
0

Maybe not very elegant, but whats about:

(defun make-struct-by-name (name &rest args)
  (apply (symbol-function
          (intern (concatenate 'string "MAKE-"
                               (symbol-name name))))
         args))

Usage:

CL-USER> (defstruct foo
           a b)
FOO

CL-USER> (make-struct-by-name 'foo :a 1 :b 2)
#S(FOO :A 1 :B 2)
Frank Zalkow
  • 3,850
  • 1
  • 22
  • 23
0

I've thought of one potential solution, but it's a bit of a hack. Since the #S reader macro works but I can't find out how ABCL and Allegro implement it (it may be totally internal to the implementation and not defined in Lisp), I can at least generate a string and programmatically invoke the reader macro function on it:

(defun make-struct-from-type (type-name)
  (with-input-from-string
      (s (format nil "(~A::~A)"
                 (package-name (symbol-package type-name))
                 (symbol-name type-name)))
    (funcall (get-dispatch-macro-character #\# #\S)
             s #\S nil)))

This might not work on other implementations though. SBCL complains about sb-impl::*read-buffer* being unbound, so it may require a little more finessing to trick the implementation into thinking the reader macro is being invoked in a typical context.

This should invoke the default constructor even if it was given a name without the default make- prefix.

Kyle
  • 178
  • 1
  • 8
  • That SBCL behavior is a bug. As you show, one might want to exercise a dispatch macro character's function out of the reader context. A workaround is to use `(read s)` instead of calling the dispatch macro character function yourself. – acelent May 05 '15 at 15:09
  • Even so, this gets you struct creation, but not initialization. – acelent May 05 '15 at 15:13