Nested types in clojure? - clojure

In clojure, how do I type type hint a type that I have created? (I want to nest the types.)
e.g. I had thought that this would work:
(deftype A
[#^somePrimitive someField])
(deftype B
[#^A Avalue])
This brings up an error message:
Unknown location:
error: java.lang.ClassNotFoundException: A
Note: clojure types are a new feature which currently exists only in the 'new' branch of clojure.
Edit: I was confused by the different ways of type hinting in clojure for java and clojure types.
java classes are hinted as
#^java.some.class
while clojure types are hinted as:
#^:some.Namespace/type

For each deftype, a type tag (basically a namespace-qualified keyword) is created so you don't have to AOT-compile your code before you can use the resulting class.
If type A is in the current namespace, you can write it like this:
(deftype B [^::A Avalue])
For types in other namespaces, qualify the keyword using its namespace:
(deftype B [^:user/A Avalue])

(deftype B [#^:user/A Avalue]) works for me.

Related

Is it possible to type hint a Clojure array filled with a deftype object?

I'm optimizing a small performance focused section of an application. I'm attempting to create a Java array of a type created via deftype
(deftype MyThing [foo bar baz])
However, I can't seem to find any documentation on how to type hint these arrays, and without a type hint, reflection occurs.
(def my-array (make-array MyThing 10))
(aget my-array 0)
Gives the warning:
Reflection warning, call to static method aget on clojure.lang.RT can't be resolved (argument types: core.MyThing, int).
Is there a way to correctly hint the type?
I'm surprised to not find any question on this topic on Stack Overflow, and still more surprised to see that the official documentation for adding type hints does not cover this - I was sure I'd be able to close this as a duplicate, or link to official documentation, but here I am typing it out by hand like a barbarian.
The "primitive" version of type hinting, for which other forms are mere shorthand1, is
^"Foo" xs
where Foo is the JVM's internal name for the class you want to hint. There are shorthands for primitive arrays (^ints xs), and for ordinary class types (^MyType x), but this doesn't cover arrays of non-primitive types. For that, you have to know the official class name for your type. You could look up the rules for this, but the simplest thing to do is to just ask the interpreter!
user=> (defrecord Foo [])
user.Foo
user=> (def foos (make-array Foo 10))
#'user/foos
user=> (class foos)
[Luser.Foo;
user=> (aget foos 0)
Reflection warning, null:1:1 - call to static method aget on clojure.lang.RT can't be resolved (argument types: unknown, int).
nil
user=> (aget ^"[Luser.Foo;" foos 0)
nil
1 Actually, even more primitive is ^{:tag "Foo"}, but this distinction doesn't matter for this question.

how to combine protocol function with function with same name and different arity?

I have a function foo that takes a single argument whose implementation depends on the type of the argument, hence a protocol:
(defprotocol Foo
(foo [x]))
On the same namespace, I also would like a function with the same name (foo) that takes variable arguments and that calls for each argument the single-arg foo. Something like:
(defn foo [x1 x2 & more]
(doseq [x (concat [x1 x2] more)])
(foo x))))
How to implement that?
Just adding to Tim Pote's answer, let me quote an answer from Stuart Halloway:
[...] protocols are the contract for implementers, not the contract for callers. If you change a contract for implementers, then the implementers must change.
[...] a function that has a reasonable default for any object. Often such a function does not need to be part of the contract for implementers (i.e. the protocol) at all.
It's liberating for the protocol implementers, because you can set default values or add support to multiple arities (like in your case) in the public api fn, without having to worry about all of that in the concrete implementations.
With the defprotocol you've declared the function foo. Later calling (defn foo ...) effectively overwrites your previous declaration.
One common idiom is to prepend a - to your protocol fn (i.e. -foo). This is basically Hungarian Notation for "This is an internal protocol function. There is a wrapper for it in this namespace. You should call that instead." This leaves the protocol open for extension, but allows you to wrap the invocation.
Another thing I would consider in your case is whether or not the name foo is appropriate for your wrapper. The fact that it operates on multiple Foos indicates that maybe something like do-foos is more appropriate.

Is it possible to destructure a map in a bind?

Is it possible to do this in one function:
(binding [*configs* (merge default-configs configs)]
(let [{:keys [login url max-pages]} *configs*]
..
When I tried this:
(binding [{:keys [login url max-pages] :as *configs*} (merge default-configs configs)]
It gave me this error:
CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Symbol
A little googling showed me that Common Lisp has a function called destructure-bind but I'm not sure if that's related.
No, nothing like this will work with core macros.
The reason is that both binding and let (and friends, e.g. with-bindings) do just one thing. In the case of binding, that thing is installing thread-local bindings for Vars; for let, it is introducing local bindings. These are entirely different operations.
In let, destructuring has a clear meaning: it introduces new locals, which is exactly what the basic, non-destructuring let bindings do. This is also clearly useful, as prying appart data structures and binding different parts to different locals is a common need. The names of the locals are also locally determined, so things like :keys in associative destructuring work well.
In binding, to be consistent with its main purpose, destructuring would need to bind several Vars simultaneously to several parts of a data structure. This is not nearly as useful. If instead destructuring in binding were to introduce locals, then all of a sudden binding would do two unrelated things, possibly both in the same binding pair (note how the failing binding form from the question text expects the bindings introduced by :keys to be locals, but the binding made by :as to be the usual thread-local binding of a Var). Thus binding simply opts not to support destructuring. (If you need to bind parts of a data structure to several Vars, you can use a let to perform the destructuring, then install the bindings with binding.)
As for destructuring-bind, it's basically the destructuring-enabled version of let in Common Lisp. CL's let does not support destructuring.
"Binding Forms (Destructuring)" section:
Clojure supports abstract structural binding, often called
destructuring, in let binding lists, fn parameter lists, and any macro
that expands into a let or fn. ...
AFAIK binding itself doesn't use destructuring mechanism (via fn of let).

What does "^:static" do in Clojure?

I've seen the ^:static metadata on quite a few function in the Clojure core.clj source code, e.g. in the definition of seq?:
(def
^{:arglists '([x])
:doc "Return true if x implements ISeq"
:added "1.0"
:static true}
seq? (fn ^:static seq? [x] (instance? clojure.lang.ISeq x)))
What precisely does this metadata do, and why it it used so frequently throughout core.clj?
In the development of Clojure 1.3 Rich wanted to add the ability for functions to return types other than Object. This would allow native math operators to be used without having to cram everything into one function.
The original implementation required functions that supported this to be marked :static. this meta data caused the compiler to produce two versions to the function, one that returned Object and one that returned that specific type. in cases where the compiler determined that the types would always match the more specific version would be used.
This was later made fully automatic so you don't need to add this anymore.
According to the Google Groups thread “Type hinting inconsistencies in 1.3.0”, it’s a no-op.
^:static has been a no-op for a while AFAIK, made unnecessary after changes to vars a while back.
— a May 2011 post by Chas Emerick
Seems it's a new metadata attribute in clojure 1.3. And you can compare the source between 1.3 and 1.2:
http://clojuredocs.org/clojure_core/clojure.core/seq_q
http://clojuredocs.org/clojure_core/1.2.0/clojure.core/seq_q
So I think it has something to do with ^:dynamic which indicates whether the var is allowed for dynamic binding. Just my guess. Not sure until I see document about this attribute.

What is the :: used for in clojure?

I understand keywords in Clojure being :keyword. But what is the :: used for? Why does it look like it has a binding?
user=> :foo
:foo
user=> ::foo
:user/foo
The double colon is there to fully qualify keywords with your current namespace. This is intended to avoid name clashes for keywords which are meaningful for different libraries. Without fully qualified keywords you might accidentally overwrite some values in a map and break compatibility with a library.
As now documented for Clojure as well as for ClojureScript, :: keywords can also be used to resolve namespace aliases. For example, ::foo/bar will evaluate to :clojure.core/bar if foo is an alias of clojure.core. Reader exception is thrown if foo does not resolve to a namespace.