in_rogers_neighborhood
in_rogers_neighborhood

Reputation: 317

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?

Upvotes: 4

Views: 623

Answers (1)

amalloy
amalloy

Reputation: 91837

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.

Upvotes: 6

Related Questions