views:

137

answers:

3

I have the following record:

(defrecord Signal [samples ^double sample-rate ^double scaling-factor])

How can I specify samples to be a double array?

I am using clojure 1.2.0

Edit:

@dreish I get the following output when I call (show Signal) after the changes from levand:

[35] <init> (Object,double,double)
[36] <init> (Object,double,double,Object,Object)
[37] __extmap : Object
[38] __meta : Object
[39] sample_rate : double
[40] samples : Object
[41] scaling_factor : double

I know that hinting of non-primitive type is just used to avoid reflection. From http://clojure.org/datatypes

  • note that currently a type hint of a non-primitive type will not be used to constrain the field type nor the constructor arg, but will be used to optimize its use in the class methods

Thanks everybody!

+11  A: 

Like this:

(defrecord Signal [^doubles samples ^double sample-rate ^double scaling-factor])

Rich Hickey added this a while back:

Added special type hints for primitive arrays - #^ints, #^floats, #^longs, #^doubles

See http://clojure.org/news for a discussion of how it works.

I don't have a Clojure environment with me to see if this is still the best way to do it. I assume the #^ syntax was updated to ^ along with all the other type hints in Clojure in 1.2

Edit: Another blog post on it: http://asymmetrical-view.com/2009/07/02/clojure-primitive-arrays.html

levand
+3  A: 

I agree with levand's answer on which type hint to use, but you might want to check whether defrecord actually uses these type hints. On my installation (also 1.2.0), it does not.

user=> (defrecord Signal [^doubles samples ^double sample-rate ^double scaling-factor])
user.Signal
user=> (use '[clojure.contrib.repl-utils :only [show]])    
nil
user=> (show Signal)
===  public final user.Signal  ===

[stuff deleted]

[38] <init> (Object,Object,Object)
[39] __extmap : Object
[40] __meta : Object
[41] sample_rate : Object
[42] samples : Object
[43] scaling_factor : Object

[more stuff deleted]

As you can see, the constructor arguments (38) and the member variables (41-43) are still just Objects. (Arrays are references anyway, but it will be nice to someday be able to store unboxed numbers in a record once that feature is implemented.)

dreish
+3  A: 

To elaborate on what dreish wrote:

As it is currently implemented (1.2), type hints do not manifest in the API (instance variables, constructor/method signatures), but rather are used to eliminate reflection calls within the lexical scope. For example:

user=> (set! *warn-on-reflection* true)
true
user=> (defprotocol P (foo [p]))
P
user=> (defrecord R [n] P (foo [_] (.intValue n)))
Reflection warning, NO_SOURCE_PATH:4 - reference to field intValue can't be resolved.
user.R
user=> (defrecord R [^Number n] P (foo [_] (.intValue n)))
user.R

The issue that remains is the boxing of primitive numbers, though a double array is-a Object, so no worries there.

That said, I believe there are some enhancements in the master branch (1.3) such that the instance variables, etc., can be emitted as primitive types based on type hinting.

Alex Taggart