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.
In Allegro CL and ABCL, can I construct a struct given only its type name?
265 Views Asked by Kyle AtThere are 3 best solutions below
On
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)
On
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.
You shouldn't mix structure and object creation. The standard defined
make-instanceforstandard-class, and forsymbolsuch that the provided symbol is passed tofind-class, thenmake-instancerecurses.As such, a stock implementation that extends
make-instancefor named structure types is not conforming, and neither is your code if you rely on it.Then,
#Sis 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
#Syourself by interning a symbol namedmake-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 nilindefstruct. 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 inmake-load-form-using-slots, an extended#S, and possibly to optimize literal structure loading (as opposed to forms that create one) in file compilation throughmake-load-form's specialization for structures.