quick question: Is there any advantage/disadvantage of define your function like:
(defn some-fn [a & {:keys [b c]}]
(list a b c))
;; (some-fn 1 :b 2 :c 3)
;; vs
(defn some-fn [a & [{:keys [b c]}]
(list a b c))
;; (some-fn 1 {:b 2 :c 3})
For the second you can skip the & []
(defn some-fn [a {:keys [a b]}]
Not really. It would make it impossible to pass one arg to the fn.
Some musings here: https://stuartsierra.com/2015/06/01/clojure-donts-optional-arguments-with-varargs
Ah right
It's better to create two separate arities, [a]
and [a {:keys [b c]}]
.
Very nice. Thanks for the link and ^
[a & {:keys [b c]}]
is not that great. Yes, it enables the call sites to omit {
and }
. But it also makes it much harder to compose arguments. And it's error-prone - you can make a mistake and see a cryptic error message only in run time.
Can someone explain this behavior to me? I'd expect the two to result in the same string
user=> (Integer/toBinaryString 0xc3)
"11000011"
user=> (Integer/toBinaryString (byte 0xc3))
"11111111111111111111111111000011"
I figure it's to do with signed vs unsigned but it's weirdI really wish things like byte-array would be smart and handle these cases for me ๐
On jdk11 it throws exception "Value out of range for byte: 195". I guess your runtime overflows
I get the same binary with (Integer/toBinaryString (unchecked-byte 0xc3))
195 overflows to -61
It may depend on the relevant setting instead of the runtime:
user=> (byte 0xc3)
Execution error (IllegalArgumentException) at user/eval3 (REPL:1).
Value out of range for byte: 195
user=> (set! *unchecked-math* true)
true
user=> (byte 0xc3)
-61
Yeah that part is implementation. The base issue is why I'm told that 0xc3
which is obviously a valid single-byte value is "out of range for byte"
Because byte
is signed:
/**
* A constant holding the minimum value a {@code byte} can
* have, -2<sup>7</sup>.
*/
public static final byte MIN_VALUE = -128;
/**
* A constant holding the maximum value a {@code byte} can
* have, 2<sup>7</sup>-1.
*/
public static final byte MAX_VALUE = 127;
Java inter-op performance question. I have this Java interface (which I cannot change) that goes like:
public interface Span {
Span setTag(String k, String v);
Span setTag(String k, boolean v);
Span setTag(String k, Number v);
}
And on the other hand a Clojure function that does something like (but not really):
(defn set-tag [^Span s k v]
(.setTag s k v))
When I ran profiling I saw that this line creates an insane amount of reflection overhead (donโt have the output handy ATM).
The question is - is there a way to avoid reflection here that does not require changing the code calling set-tag
?
I can do something like:
(cond (string? v) (.setTag s k ^String v) ...)
But would that really be better?
I understand that I may just have to try some things out and benchmark, but was wandering if there is some obvious solution for this problem that I am missing.
Thanks!Dispatching with cond and instance checks won't introduce lots of overhead. In terms of performance, especially compared to reflection, it is immensely preferable.
Another option is having three functions, such as set-string-tag
, set-boolean-tag
set-numerical-tag
. More verbose, but will be clear what's expected in the code and will avoid instance checks.
Anyway, to avoid reflection you'll need to type hint the v
argument.
Thanks, this matches what I thought. What I fail to understand is why the compiler/runtime canโt do this instead of meโฆ
For good or bad, the compiler is simple and predictable. It doesn't know what type to dispatch to at runtime, so it has to find all available methods then find the one whose arguments types match the provided arguments. This is further complicated by the fact that with inheritance you can't just match types, but all the types implementing an interface or inheriting another type. That's what the runtime does, although it could be theoretically possible to generate such dispatch code for simple cases.
Yup ๐
is there a way for me to extend IFn to an existing Java type?
looks like no...
Yeah, it can be a bit annoying that Java has no option for unsigned integer types. You can of course easily create a little function like (defn unsigned-byte-to-signed-byte [x] (if (>= x 128) (- x 256) x))
for converting unsigned to signed
That particular conversion function leaves the most significant bit of the byte unchanged.
I believe that the answer "no" is correct for existing Java classes -- they cannot be extended to any new interfaces not in their original definition. That is one of the things that makes Clojure's defprotocol
and defmulti
more flexible.
Right, I think the issue here is that IFn is an interface so I canโt extend it to an existing type or class
If IFn was a protocol, I could extend the class with it
Iโm used to CLJS where IFn is a protocol