Polymorphism. Types , records , protocols , multimethods, tag hierarchy.

Deftype in dunaj creates map-like object similar to what defprotocol does, and no longer implicitly imports created class into the namespace (a somewhat controversial change from Clojure).
When using dunaj-lite, some functions defined here works only on types and protocols created with respective dunaj variants.
Documentation needs more work.

Primary

Protocol

Available since version 1.0 (view source)

not referred automatically

VAR of type Signature

Type signature for protocols.

Record

Available since version 1.0 (view source)

not referred automatically

VAR of type Signature

Type signature for records.

Type

Available since version 1.0 (view source)

not referred automatically

VAR of type Signature

Type signature for types.

defprotocol

Available since version 1.0 (alias of clojure.bootstrap/defprotocol)

MACRO (defprotocol name & opts+sigs)

Defines a var with newly created protocol as a root binding, defines polymorphic protocol functions, generates host interface and returns protocol var.

defrecord

Available since version 1.0 (alias of clojure.bootstrap/defrecord)

MACRO (defrecord name & args)

Generates a record, defines constructor fns and returns that record type.

deftype

Available since version 1.0 (alias of clojure.bootstrap/deftype)

MACRO (deftype name & args)

Generates a record, defines constructor fns and returns that type.

See also: Type, type?, type-instance?

ensure-instance

Available since version 1.0 (view source)

Usage:
  • (ensure-instance type x)

Type signature:
  • ((U Class+ Type) ⨯ Any) → Any

Returns x, throwing if x is not an instance of type.

extend!

Available since version 1.0 (alias of clojure.core/extend)

Usage:
  • (extend! atype & proto+mmaps)

Type signature:
  • ((U Class+ Type) ⨯ (Va Any)) → nil

Implementations of protocol methods can be provided using the extend construct:

(extend! AType
  AProtocol
   {:foo an-existing-fn
    :bar (fn [a b] ...)
    :baz (fn ([a]...) ([a b] ...)...)}
  BProtocol
    {...}
  ...)

extend! takes a type/class (or interface, see below), and one or more protocol + method map pairs. It will extend the polymorphism of the protocol’s methods to call the supplied methods when an AType is provided as the first argument.

Method maps are maps of the keyword-ized method names to ordinary fns. This facilitates easy reuse of existing fns and fn maps, for code reuse/mixins without derivation or composition. You can extend an interface to a protocol. This is primarily to facilitate interop with the host (e.g. Java) but opens the door to incidental multiple inheritance of implementation since a class can inherit from more than one interface, both of which extend the protocol. It is TBD how to specify which impl to use. You can extend a protocol on nil.

If you are supplying the definitions explicitly (i.e. not reusing existing functions or mixin maps), you may find it more convenient to use the extend-type! or extend-protocol! macros.

Note that multiple independent extend clauses can exist for the same type, not all protocols need be defined in a single extend call.

extend-protocol!

Available since version 1.0 (alias of clojure.core/extend-protocol)

MACRO (extend-protocol! p & specs)

Useful when you want to provide several implementations of the same protocol all at once. Takes a single protocol and the implementation of that protocol for one or more types. Expands into calls to extend-type!:

(extend-protocol! Protocol
  AType
  (foo [x] ...)
  (bar [x y] ...)
  BType
  (foo [x] ...)
  (bar [x y] ...)
  AClass (foo [x] ...)
  (bar [x y] ...)
  nil
  (foo [x] ...) (bar [x y] ...))

;; expands into:

(do
  (extend-type! AType Protocol (foo [x] ...) (bar [x y] ...))
  (extend-type! BType Protocol (foo [x] ...) (bar [x y] ...))
  (extend-type! AClass Protocol (foo [x] ...) (bar [x y] ...))
  (extend-type! nil Protocol (foo [x] ...) (bar [x y] ...)))

extend-type!

Available since version 1.0 (alias of clojure.core/extend-type)

MACRO (extend-type! t & specs)

A macro that expands into an extend! call. Useful when you are supplying the definitions explicitly inline, extend-type! automatically creates the maps required by extend!. Propagates the class as a type hint on the first argument of all fns.

(extend-type! MyType
  Countable
  (cnt [c] ...)
  Foo
  (bar [x y] ...)
  (baz ([x] ...) ([x y & zs] ...)))

;; expands into:

(extend! MyType
  Countable {:cnt (fn [c] ...)}
  Foo {:baz (fn ([x] ...) ([x y & zs] ...)) :bar (fn [x y] ...)})

extenders

Available since version 1.0 (alias of clojure.core/extenders)

not referred automatically

Usage:
  • (extenders protocol)

Type signature:
  • () → [(U Type Class+) Protocol]

Returns a collection of the types/classes explicitly extending protocol.

When using dunaj-lite, this function works only on types and protocols created with respective dunaj variants.

extends?

Available since version 1.0 (view source)

Usage:
  • (extends? protocol type)

Type signature:
  • (Protocol ⨯ (U Class+ Type)) → Boolean+

Returns true if type extends protocol. Also accepts class instead of type.

When using dunaj-lite, this function works only on types and protocols created with respective dunaj variants.

identical-type?

Available since version 1.0 (view source)

Usage:
  • (identical-type? x y)

Type signature:
  • (Any ⨯ Any) → Boolean+

Returns true if x and y are of identical type, otherwise returns false.

instance?

Available since version 1.0 (view source)

Usage:
  • (instance? type x)

Type signature:
  • ((U Class+ Type) ⨯ Any) → Boolean+

Returns true if x is an instance of type. Also accepts class instead of type.

protocol?

Available since version 1.0 (view source)

Usage:
  • (protocol? x)

Type signature:
  • (Any) → Boolean+

Returns true if x is a protocol, otherwise returns false.

When using dunaj-lite, this function works only on types and protocols created with respective dunaj variants.

record-instance?

Available since version 1.0 (view source)

Usage:
  • (record-instance? x)

Type signature:
  • (Any) → Boolean+

Returns true if x is a record instance, otherwise returns false.

record?

Available since version 1.0 (view source)

Usage:
  • (record? x)

Type signature:
  • (Any) → Boolean+

Returns true if x is a record (a record type, not instance of a record), otherwise returns false.

When using dunaj-lite, this function works only on types and protocols created with respective dunaj variants.

reify

Available since version 1.0 (alias of clojure.core/reify)

MACRO (reify & opts+specs)

reify is a macro with the following structure:

(reify options* specs*)

Currently there are no options.

Each spec consists of the protocol or interface name followed by zero or more method bodies:

protocol-or-interface-or-Object
(methodName [args+] body)*

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 the first 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.

The return type can be indicated by a type hint on the method name, and arg types can be indicated by a type hint on arg names. If you leave out all hints, reify will try to match on same name/arity method in the protocol(s)/interface(s) - this is preferred. If you supply any hints at all, no inference is done, so all hints (or default of Object) must be correct, for both arguments and return type. If a method is overloaded in a protocol/interface, multiple independent method definitions must be supplied. If overloaded with same arity in an interface you must specify complete hints to disambiguate - a missing hint implies Object.

recur works to method heads The method bodies of reify are lexical closures, and can refer to the surrounding local scope:

(str (let [f "foo"]
     (reify Object
       (toString [this] f))))
;;=> "foo"

(seq (let [f "foo"]
     (reify clojure.lang.Seqable
       (seq [this] (seq f)))))
;;=> (\f \o \o))

reify always implements clojure.lang.IObj and transfers meta data of the form to the created object.

(meta ^{:k :v} (reify Object (toString [this] "foo")))
;;=> {:k :v}

See also: deftype

satisfies?

Available since version 1.0 (alias of clojure.core/satisfies?)

Usage:
  • (satisfies? protocol x)

Type signature:
  • (Protocol ⨯ Any) → Boolean+

Returns true if x satisfies the protocol.

See also: extend!, deftype, extends?

type

Available since version 1.0 (view source)

Usage:
  • (type x)

Type signature:
  • (Any) → Any

Returns the :type metadata of x, or its type if none. Returns nil if type cannot be found.

When using dunaj-lite, this function works only on types and protocols created with respective dunaj variants.

See also: dunaj.host/class

type-instance?

Available since version 1.0 (view source)

Usage:
  • (type-instance? x)

Type signature:
  • (Any) → Boolean+

Returns true if x is a type instance, otherwise returns false.

type?

Available since version 1.0 (view source)

Usage:
  • (type? x)

Type signature:
  • (Any) → Boolean+

Returns true if x is a type, otherwise returns false.

When using dunaj-lite, this function works only on types and protocols created with respective dunaj variants.

Multimethods

Multimethod

Available since version 1.0 (view source)

TYPE

A type for multimethods. List of methods and preferreds is stored in the attached configuration map.

ancestors

Available since version 1.0 (alias of clojure.core/ancestors)

not referred automatically

Usage:
  • (ancestors tag)

  • (ancestors h tag)

Type signatures:
  • (Any) → [Any]

  • (Any ⨯ Any) → [Any]

Returns the immediate and indirect parents of tag, either via host type inheritance relationship or a relationship established via derive. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to the global hierarchy.

See also: isa?, parents, descendants

defmethod

Available since version 1.0 (alias of clojure.core/defmethod)

MACRO (defmethod multifn dispatch-val & fn-tail)

Creates and installs a new method of multimethod multifn associated with dispatch-val.

See also: Multimethod, defmulti

defmulti

Available since version 1.0 (alias of clojure.core/defmulti)

MACRO (defmulti name docstring? attr-map? dispatch-fn & options)

Creates a new multimethod with the associated dispatch function.

Options are key-value pairs and may be one of:

  • :default - The default dispatch value, defaults to :default

  • :hierarchy - The value used for hierarchical dispatch (e.g. ::square is-a ::shape)

    Hierarchies are type-like relationships that do not depend upon type inheritance. By default multimethods dispatch off of a global hierarchy map. However, a hierarchy relationship can be created with the derive! function used to augment the root ancestor created with make-hierarchy.

    Multimethods expect the value of the hierarchy option to be supplied as a reference type e.g. a var (i.e. via the Var-quote dispatch macro #' or the dunaj.state.var/var macro).

See also: Multimethod, defmethod

derive!

Available since version 1.0 (alias of clojure.core/derive)

not referred automatically

Usage:
  • (derive! tag parent)

  • (derive! h tag parent)

Type signatures:
  • (Any ⨯ Any) → Any

  • (Any ⨯ Any ⨯ Any) → Any

Establishes a parent/child relationship between parent and tag. parent must be a namespace-qualified symbol or keyword and child tag can be either a namespace-qualified symbol or keyword or a class. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to, and modifies, the global hierarchy.

descendants

Available since version 1.0 (alias of clojure.core/descendants)

not referred automatically

Usage:
  • (descendants tag)

  • (descendants h tag)

Type signatures:
  • (Any) → [Any]

  • (Any ⨯ Any) → [Any]

Returns the immediate and indirect children of tag, through a relationship established via derive. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to the global hierarchy.

JVM host specific: Does not work on Java type inheritance relationships.

See also: isa?, ancestors, parents

get-method

Available since version 1.0 (alias of clojure.core/get-method)

not referred automatically

Usage:
  • (get-method multifn dispatch-val)

Type signature:
  • (Multimethod ⨯ Any) → Multimethod

Given a multimethod multifn and a dispatch value dispatch-val, returns the dispatch fn that would apply to that value, or nil if none apply and there is no default method.

isa?

Available since version 1.0 (alias of clojure.core/isa?)

not referred automatically

Usage:
  • (isa? child parent)

  • (isa? h child parent)

Type signatures:
  • (Any ⨯ Any) → Boolean+

  • (Any ⨯ Any ⨯ Any) → Boolean+

Returns true if (= child parent), or child is directly or indirectly derived from parent, either via host type inheritance relationship or a relationship established via derive. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to the global hierarchy.

make-hierarchy

Available since version 1.0 (alias of clojure.core/make-hierarchy)

not referred automatically

Usage:
  • (make-hierarchy)

Type signature:
  • () → Any

Creates a hierarchy object for use with derive!, isa? etc.

See also: derive!, isa?

multimethod?

Available since version 1.0 (view source)

not referred automatically

Usage:
  • (multimethod? x)

Type signature: Predicate

Returns true if object x is an instance of Multimethod type, false otherwise.

parents

Available since version 1.0 (alias of clojure.core/parents)

not referred automatically

Usage:
  • (parents tag)

  • (parents h tag)

Type signatures:
  • (Any) → [Any]

  • (Any ⨯ Any) → [Any]

Returns the immediate parents of tag, either via host type inheritance relationship or a relationship established via derive. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to the global hierarchy.

See also: isa?, ancestors, descendants

prefer-method!

Available since version 1.0 (alias of clojure.core/prefer-method)

not referred automatically

Usage:
  • (prefer-method! multifn dispatch-val-x dispatch-val-y)

Type signature:
  • (Multimethod ⨯ Any ⨯ Any) → Multimethod

Causes the multimethod multifn to prefer matches of dispatch-val-x over dispatch-val-y when there is a conflict.

remove-all-methods!

Available since version 1.0 (alias of clojure.core/remove-all-methods)

not referred automatically

Usage:
  • (remove-all-methods! multifn)

Type signature:
  • (Multimethod) → Multimethod

Removes all of the methods of multimethod multifn.

remove-method!

Available since version 1.0 (alias of clojure.core/remove-method)

not referred automatically

Usage:
  • (remove-method! multifn dispatch-val)

Type signature:
  • (Multimethod ⨯ Any) → Multimethod

Removes the method of multimethod multifn associated with dispatch-val.

underive!

Available since version 1.0 (alias of clojure.core/underive)

not referred automatically

Usage:
  • (underive! tag parent)

  • (underive! h tag parent)

Type signatures:
  • (Any ⨯ Any) → Any

  • (Any ⨯ Any ⨯ Any) → Any

Removes a parent/child relationship between parent and tag. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to, and modifies, the global hierarchy.