Common Lisp is a functional language (and also an
imperative, object-oriented one, which, moreover, can be used in a
declarative fashion) and it has a mode of operation where
"objects" are created on the fly (on the heap, and
then dispatched by the garbage collector). Object creation is done
through a slew of ad-hoc constructors (think
constructors tied to a specific structure and
Alas, many "new" programming languages have settled on an
operator that dynamically creates new objects in memory:
This library (which is nothing new) introduces the
newq operators for Common Lisp. The idea is to
provide an alternative to all (or most) ad-hoc constructors and
make-instance, so that you can write something
like the following:
cl-prompt> (defclass foo () ()) FOO cl-prompt> (new 'foo) #<FOO 42>or, with a convenience macro
cl-prompt> (newq foo) #<FOO 42>
Of course, this does not amount to much, yet, things become more interesting when you try things like the following:
cl-prompt> (newq (array single-float (2 2)) '((1.0 0.0) (0.0 1.0))) #2A((1.0 0.0) (0.0 1.0)) cl-prompt> (type-of *) (SIMPLE-ARRAY SINGLE-FLOAT (2 2)) cl-prompt> (newq (array double-float) '((1.0 0.0) (0.0 1.0)) Error: Attempt to set double-float array element to 1.0 of type SINGLE-FLOAT. cl-prompt> (new '(mod 42) (read)) 1024 Error: 1024 is not of type (INTEGER 0 (42)).
The problem is that as soon as you wade in CL "type specifiers" land, you hit the dreaded "implementation dependent" wall, or, worse. the "this is not even mentioned in the ANSI spec" wall. Think of DEFSTRUCT and the fact that there is no portable way to get to the constructor, not to mention DEFTYPE.
The rationale for the specification of the
operator is simply to provide an operator that is familiar to many
programmers and that seamlessly meshes in a regular CL environment.
Ancillary functionalities are provided to make the
operator work for special (and not so special) cases.
The key and simple invariant that should always hold for the specification, the reference implementation and for any user-provided extension is the following:
cl-prompt> (typep (new type ...) type) T
The main operator
new is a generic function
with several methods defined (at least in the reference implementation).
newq is a convenience macro that does not evaluate the
first argument and simply expands in a call to
CL types can be defined with
deftype. The result is a
type specifier that is either a symbol, or, most likely, a
cons. The primary method for
dispatches on the generic function
type-cons, which mostly
eql specializers on the head of the type
The main problem that any implementation of the NEW API must
face is how to deal with
structure-classes. The CL
specification does not make provisions for ways to fetch the
constructors of a DEFSTRUCT, which can be many.
The NEW API provides two ways to deal with such a problem: (1) by introducing a modicum of new "syntax" that can be used to circumvent the problem, and (2) by providing a way to record the DEFSTRUCT constructors.
In order to provide a way to specify the "constructor" (and
therefore the standard one) in a call to
newq for a
following syntax is introduced to specify a "pseudo type" clearly
identifying strucutre types (and, simmetrically, class types); in some
circuitous way this is akin to the C++
'(' structure <structure type designator> [ by <constructor> ] ')' '(' class <class designator> [ by <constructor> ] ')'
cl-prompt> (defstruct foo a s d) FOO cl-prompt> (new '(structure foo) :s 42) #S(FOO :A NIL :S 42 :D NIL) cl-prompt> (defstruct (bar (:constructor baryfy (a s)) (:constructor babar (a &optional (d (+1 a))))) a s d) FOO cl-prompt> (new '(structure bar :by baryfy) "QWE" "RTY") #S(FOO :A "QWE" :S "RTY" :D NIL) cl-prompt> (newq (structure bar :by babar) 42) #S(FOO :A 42 :S NIL :D 43) cl-prompt> (defclass baz () ()) BAZ cl-prompt> (newq (class BAZ)) #<BAZ 42>
While implementations must have a "generic" structure constructor
to deal with the
#S(STRUC-CLASS-NAME ...) syntax, alas,
such functionality is not portably advertised. Because of this fact,
in order to allow the "plain" use of constructors (i.e., without the
new must rely on an explicit "recording" of a constructor
for the structure, lest redefining the macro DEFSTRUCT. In order to
register a constructor for the benefit of
register-structure-constructor is thus
cl-prompt> (defstruct foo a s d) FOO cl-prompt> (register-structure-constructor 'foo #'make-foo) #<Function MAKE-FOO ...> cl-prompt> (new 'foo :s 42) #S(FOO :A NIL :S 42 :D NIL)
The NEW specification and reference implementation can be found at common-lisp.net. The implementation lies within a package nicknamed NEW-OP and is based on the generic functions new, type-cons, and the macro newq.
The reference implementation contains a number of predefined
methods for new and
type-cons that handle most
of the basic CL types and classes.
The NEW-OP library is available from Quicklisp.
The specification and (reference) implementation can be found at common-lisp.net.
The git can be gotten from the common-lisp.net GitLab instance in the NEW-OP project page.
The usual ones. Plus various past discussions on C.L.L. and elsewhere.
The code associated to these documents is not completely tested and it is bound to contain errors and omissions. This documentation may contain errors and omissions as well.
The code is released under a BSD license. See the file COPYING in the code tree. You are advised to use the code at your own risk. No warranty whatsoever is provided, the author will not be held responsible for any effect generated by your use of the library, and you can put here and around each piece of the library code the scariest extra disclaimer you can think of.