defnt
is a way of defining an efficiently-dispatched dynamic, type-checked function without resorting to using the un-function-like syntax of defprotocol
or reify
. An example of it is the following:
(defnt ^java.math.BigInteger ->big-integer
([^java.math.BigInteger x] x)
([^clojure.lang.BigInt x] (.toBigInteger x))
([#{(- number? BigInteger BigInt)} x]
(-> x long (BigInteger/valueOf))))
This will be faster than the clojure.lang.RT version (I haven't tested the example function above but similar ones, yes), because instead of doing possibly O(n) hops (instanceof checks) to dispatch on type, it does it in only O(1) with the reify
version of defnt
under the hood if it can determine the type of the first argument to ->big-integer
, or O(log32(n)) if it can't determine the type at runtime, in which case it uses the defprotocol
version. Additionally, for convenience, one can define predicates such as number?
to use in the type check, which will expand to the set #{int, long, float, double, Integer, Long, BigDecimal ...}
. And then one can e.g. take the difference of that set or union it, etc. to more expressively define the set of types that are accepted in that particular arity of the function. All the expansion of type predicates happens at compile time.
As another example, if three entirely unrelated objects all use .quit
to free their resources and you're tired of type-hinting to avoid reflection, you could just abstract that to, say:
(defnt free
([#{UnrelatedClass0 UnrelatedClass1 UnrelatedClass2} x] (.quit x))
Voila! No type hints needed anymore, and no performance hit or repetitive code with cond
+ instance?
checks.
defnt
.
(make it work with lazy loading first, and only then handle eager loading)
lein
for Clojure or Google Closure Compiler for ClojureScript),
If you could guarantee that the consumer of the AOT artifact had bytecode generation capability
AND If the consumer of the AOT artifact found some degree of non-AOT compilation acceptable,
-main
) (note that non-bytecode generating, 'interpreting' eval
is fine because it will be compiled),
If you could guarantee that `eval` was suddenly possible and performant with the Google Closure Compiler (big stretch here)
AND If the consumer of the AOT artifact found some degree of non-AOT compilation acceptable,
-main
) (note that non-bytecode generating, 'interpreting' eval
is fine because it will be compiled),
clojure.spec
+ protocols/interfacesA goal might be to merge clojure.spec with protocols and interfaces like so:
(def-validated double-between-3-and-5-exclusive
(v/and double? #(< 3 % 5)))
(def-validated double-between-1-and-8-inclusive
(v/and double? #(< 1 % 8)))
(defnt ^double-between-1-and-8-inclusive my-fn
[^double-between-3-and-5-exclusive v]
(+ @v 10))
and have the compiler complain. I realize that this is probably prohibitively expensive, though.
Look at:
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close