This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-07
Channels
- # babashka (20)
- # beginners (72)
- # biff (7)
- # calva (15)
- # clj-kondo (36)
- # clj-on-windows (5)
- # cljs-dev (30)
- # clojure (27)
- # clojure-europe (2)
- # clojure-nl (1)
- # clojure-norway (6)
- # clojure-uk (2)
- # clojurescript (26)
- # conjure (14)
- # cursive (17)
- # events (1)
- # honeysql (5)
- # hyperfiddle (1)
- # leiningen (1)
- # off-topic (3)
- # reitit (5)
- # shadow-cljs (1)
- # xtdb (13)
I wonder what’s the use of bytes
given we have byte-array
. it is stated bytes
converts arguments to byte[], what are the potential arguments?
bytes
states it "Casts to bytes[]"
. It ends up with
static public byte[] bytes(Object array){
return (byte[]) array;
}
This is not creating an array like (byte-array coll)
but is casting its object as a byte arrayproteus=> (bytes [1 2 3])
Execution error (ClassCastException) at proteus/eval395 (REPL:15).
class clojure.lang.PersistentVector cannot be cast to class [B (clojure.lang.PersistentVector is in unnamed module of loader 'app'; [B is in module java.base of loader 'bootstrap')
proteus=> (byte-array [1 2 3])
[1, 2, 3]
So the only usage is passing it an object with static type Object, but runtime type bytes[].
@U11BV7MTK Wonder how you find the source code. I use jump to definition but at a loss at
(definline bytes
"Casts to bytes[]"
{:added "1.1"}
[xs] `(. clojure.lang.Numbers bytes ~xs))
and cannot go further.i opened up the Clojure repo, went to the Numbers.java
file and looked for the bytes
method
Type Hints are to avoid reflection, and the type casting functions are to enable primitive math in locals.
See Coercions here: https://clojure.org/reference/java_interop
Basically, for local primitives you should cast the right hand side instead of type hinting the local:
;; Good
(let [a (bytes b)]
...)
;; Bad
(let [^bytes a b]
...)
For primitive input/output on functions you can use the primitive type hints, but only long, double and the array primitives are supported, others won't result in primitive.
> For primitive input/output on functions you can use the primitive type hints, Not quite catching this part. Could you make an example? I am aware that some methods have overloadings which can take Objects, or take primitives. Type hinting helps choosing the right method with less overheads.
So in Java most types are reference types. So all objects are accessed through a pointer. This is also true for doubles and long and arrays, when you call a function it doesn't pass the primitive long, or double, and the array won't directly point to the primitives, but have a reference to them. That means when you do math on them, between each operations it's looked up/stored back and it's slower. Also takes a bit more memory. That's called boxing. Where primitives are boxed in an object. By default all primitives are of the boxed variant in Clojure, so when you type 12 it actually creates a boxed Long, not a primitive long. Even if you have a primitive, and you pass it to a function it'll automatically be boxed so that it's passed to the function by reference. So if you want fast math, you need to explicitly say not to box. So if you want a function that can actually be passed a primitive so it can use it as such, and not have it be boxed you have to type hint as a primitive on the function:
(defn add[^long a ^long b]
(+ a b))
It only works for long, double and arrays of primitives. If you type as int Clojure will still box it.
Locally though, instead of type hints, you should use cast:
(let [a (long x)
b (long b)]
(+ a b)
engine.repl=> (byte \a)
97
engine.repl=> (set! *unchecked-math* :warn-on-boxed)
:warn-on-boxed
engine.repl=> (byte \a)
Execution error (ClassCastException) at engine.repl/eval10467 (form-init6436663342808242775.clj:1).
class java.lang.Character cannot be cast to class java.lang.Number (java.lang.Character and java.lang.Number are in module java.base of loader 'bootstrap')
engine.repl=> (Byte/parseByte \a)
Execution error (ClassCastException) at engine.repl/eval10469 (form-init6436663342808242775.clj:1).
class java.lang.Character cannot be cast to class java.lang.String (java.lang.Character and java.lang.String are in module java.base of loader 'bootstrap')
Can someone explain this?you get the behaviour of unchecked-byte
when setting *unchecked-math*
to a truthy value (if the form gets "inlined"). Looks like a bug to me, some "unchecked" operation handle chars, some don't. (unchecked-int \a)
will work but (unchecked-long \a)
and (unchecked-short \a)
won't :face_with_raised_eyebrow:
Ya, this may be a bug, or an omission. Cut an issue at http://ask.clojure.org maybe
Wonder why
(instance? java.util.Map {:a :b})
returns true
. The Map is a generic interface, so something like Map<K,V>. I didn’t specify the K,V here, so why this works? Does it implicitly assume Map<Object,Object> to be used here?In the JVM that KV doesn't exist at runtime and it's treated as Object. This is called generic type erasure. All generic types in java classes are actually just some superclass in the resulting code.
@U5NCUG8NR I googled and found this tutorial: https://www.baeldung.com/java-type-erasure#1-class-type-erasure. Since public class Stack<E> , can be used to instantiate a lot of concrete class with different Es. So how come the JVM know which concrete Classs I am referring to? The same goes for the original question, java.util.Map. Their might be lots of different java.uti.Map classes.
That's the thing, there's only one concrete class Stack
.
As far as the JVM is concerned, generics don't exist, that's only something you see from the Java side.
Any function or class that takes generic type arguments actually just results in one function or class which has the type of that thing decided as a parent class of all the possible types. So for types like <? extends A>
then it's just the type A
. For generics like <T>
it's just Object
then java compilation makes sure that all those types line up at compile time.
These types don't exist at runtime.
> Any function or class that takes generic type arguments actually just results in one function or class which has the type of that thing decided as a parent class of all the possible types. So for types like <? extends A>
then it’s just the type A
. For generics like <T>
it’s just Object
Thanks! That’s really concise and accurate.