(deftype name [& fields] & opts+specs)
(deftype name [fields*] options* specs*)
Options are expressed as sequential keywords and arguments (in any order).
Supported options:
:load-ns - if true, importing the type class will cause the
namespace in which the type was defined to be loaded.
Defaults to false.
Each spec consists of a protocol or interface name followed by zero
or more method bodies:
protocol-or-interface-or-Object
(methodName [args*] body)*
Dynamically generates compiled bytecode for class with the given
name, in a package with the same name as the current namespace, the
given fields, and, optionally, methods for protocols and/or
interfaces.
The class will have the (by default, immutable) fields named by
fields, which can have type hints. Protocols/interfaces and methods
are optional. The only methods that can be supplied are those
declared in the protocols/interfaces. Note that method bodies are
not closures, the local environment includes only the named fields,
and those fields can be accessed directly. Fields can be qualified
with the metadata :volatile-mutable true or :unsynchronized-mutable
true, at which point (set! afield aval) will be supported in method
bodies. Note well that mutable fields are extremely difficult to use
correctly, and are present only to facilitate the building of higher
level constructs, such as Clojure's reference types, in Clojure
itself. They are for experts only - if the semantics and
implications of :volatile-mutable or :unsynchronized-mutable are not
immediately apparent to you, you should not be using them.
Method definitions take the form:
(methodname [args*] body)
The argument and return types can be hinted on the arg and
methodname symbols. If not supplied, they will be inferred, so type
hints should be reserved for disambiguation.
Methods should be supplied for all methods of the desired
protocol(s) and interface(s). You can also define overrides for
methods of Object. Note that a parameter must be supplied to
correspond to the target object ('this' in Java parlance). Thus
methods for interfaces will take one more argument than do the
interface declarations. Note also that recur calls to the method
head should *not* pass the target object, it will be supplied
automatically and can not be substituted.
In the method bodies, the (unqualified) name can be used to name the
class (for calls to new, instance? etc).
When AOT compiling, generates compiled bytecode for a class with the
given name (a symbol), prepends the current ns as the package, and
writes the .class file to the *compile-path* directory.
One constructor will be defined, taking the designated fields. Note
that the field names __meta, __extmap, __hash and __hasheq are currently
reserved and should not be used when defining your own types.
Given (deftype TypeName ...), a factory function called ->TypeName
will be defined, taking positional parameters for the fields
Source
(defmacro deftype
"(deftype name [fields*] options* specs*)
Options are expressed as sequential keywords and arguments (in any order).
Supported options:
:load-ns - if true, importing the type class will cause the
namespace in which the type was defined to be loaded.
Defaults to false.
Each spec consists of a protocol or interface name followed by zero
or more method bodies:
protocol-or-interface-or-Object
(methodName [args*] body)*
Dynamically generates compiled bytecode for class with the given
name, in a package with the same name as the current namespace, the
given fields, and, optionally, methods for protocols and/or
interfaces.
The class will have the (by default, immutable) fields named by
fields, which can have type hints. Protocols/interfaces and methods
are optional. The only methods that can be supplied are those
declared in the protocols/interfaces. Note that method bodies are
not closures, the local environment includes only the named fields,
and those fields can be accessed directly. Fields can be qualified
with the metadata :volatile-mutable true or :unsynchronized-mutable
true, at which point (set! afield aval) will be supported in method
bodies. Note well that mutable fields are extremely difficult to use
correctly, and are present only to facilitate the building of higher
level constructs, such as Clojure's reference types, in Clojure
itself. They are for experts only - if the semantics and
implications of :volatile-mutable or :unsynchronized-mutable are not
immediately apparent to you, you should not be using them.
Method definitions take the form:
(methodname [args*] body)
The argument and return types can be hinted on the arg and
methodname symbols. If not supplied, they will be inferred, so type
hints should be reserved for disambiguation.
Methods should be supplied for all methods of the desired
protocol(s) and interface(s). You can also define overrides for
methods of Object. Note that a parameter must be supplied to
correspond to the target object ('this' in Java parlance). Thus
methods for interfaces will take one more argument than do the
interface declarations. Note also that recur calls to the method
head should *not* pass the target object, it will be supplied
automatically and can not be substituted.
In the method bodies, the (unqualified) name can be used to name the
class (for calls to new, instance? etc).
When AOT compiling, generates compiled bytecode for a class with the
given name (a symbol), prepends the current ns as the package, and
writes the .class file to the *compile-path* directory.
One constructor will be defined, taking the designated fields. Note
that the field names __meta, __extmap, __hash and __hasheq are currently
reserved and should not be used when defining your own types.
Given (deftype TypeName ...), a factory function called ->TypeName
will be defined, taking positional parameters for the fields"
{:added "1.2"
:arglists '([name [& fields] & opts+specs])}
[name fields & opts+specs]
(validate-fields fields name)
(let [gname name
[interfaces methods opts] (parse-opts+specs opts+specs)
ns-part (namespace-munge *ns*)
classname (symbol (str ns-part "." gname))
hinted-fields fields
fields (vec (map #(with-meta % nil) fields))
[field-args over] (split-at 20 fields)]
`(let []
~(emit-deftype* name gname (vec hinted-fields) (vec interfaces) methods opts)
(import ~classname)
~(build-positional-factory gname classname fields)
~classname)))