Consider this snippet:
(def vertices [
-0.5 -0.5 0
0.5 -0.5 0
0 0.5 0])
(def vertex-buffer (doto (BufferUtils/createFloatBuffer (count vertices))
(dorun (map #(.put (float %)) vertices))))
which yields this error:
No matching field found: put for class java.lang.Float
How does clojure decide that put should belong to Float (and not the FloatBuffer created above)?
How can I tell clojure that put belongs to FloatBuffer?
If this approach is not as elegant as I thought it would be, I wouldn't mind a nudge in the right direction.
In Java, you would call .put
with one argument:
buffer.put(1);
In Clojure, you have to provide buffer as the first argument:
(.put buffer 1)
If you call multiple such methods in Java, you can chain them:
buffer.put(1).put(2).put(3);
In Clojure, you would have to repeat word buffer
:
(.put buffer (float 1))
(.put buffer (float 2))
(.put buffer (float 3))
Or nest those calls, starting from the last method:
(.put (.put (.put buffer (float 1)) (float 2)) (float 3))
With doto
, you will avoid verbosity and increase readability:
(doto (BufferUtils/createFloatBuffer 3)
(.put (float 1))
(.put (float 2))
(.put (float 3)))
doto
is a macro that:
Evaluates x then calls all of the methods and functions with the
value of x supplied at the front of the given arguments. The forms
are evaluated in order. Returns x.
Your code will be transformed into:
(dorun (BufferUtils/createFloatBuffer (count vertices))
(map #(.put (float %)) vertices))
Put
still has only one argument and dorun
has two.
You can use let
+ run!
here:
(def buffer (let [buffer (BufferUtils/createFloatBuffer (count vertices))]
(run! #(.put buffer (float %)) vertices)
buffer))
Buffers also have bulk .put, so you can do this:
(def buffer (.put (BufferUtils/createFloatBuffer (count vertices))
(float-array vertices)))
And if you plan to call .get
or .write
after that, don't forget to .flip
:
(def buffer (doto (BufferUtils/createFloatBuffer (count vertices))
(.put (float-array vertices))
(.flip)))