Is this known behavior?
(clojure-version) ; => "1.12.0-beta1"
(definterface IThing
(beSlow [^Long x])
(beSlow [^String x]))
(def ^IThing x
(reify IThing
(beSlow [_ ^Long _x] :long)
(beSlow [_ ^String _x] :string)))
(.beSlow x 1) ; causes reflection warning
(IThing/.beSlow x 1) ; causes reflection warning
(^[Long] IThing/.beSlow x 12) ; ok
(.beSlow x (Long. 1)) ; ok
(.beSlow x "hello") ; ok
more details:
• this seems to happen only when there are overloads with the same arity.
• it happens with any class, I just spun up the example with definterface to be minimal
• reflection calls the right overload even if there is e.g. an Integer arity and a int arity; however, if a long and a Long overload exist, the long overload is called on unboxed inputs onlyFWIW beta2 is out
No changes in this behavior, but ty for the heads up
Long is java.lang.Long
to avoid reflection warning you might want ^long as an alias to primitive long
(set! *warn-on-reflection* true)
(definterface IThing
(beSlow [^long x])
(beSlow [^String x]))
(def ^IThing x
(reify IThing
(beSlow [_ ^long _x] :long)
(beSlow [_ ^String _x] :string)))
(.beSlow x 1) ;; => :long
no reflection warningyeah I know, but I'm working with a type I don't own which has a Number-accepting overload.
I think my best bets at the moment are wrapping the arity with a function and call that, or box manually at callsite.
@doppiaelle1999 Which part(s) of the behavior are you surprised by or think are wrong?
This has caused a reflection warning back to Clojure 1.3:
(.beSlow x 1) ; causes reflection warningI expected the compiler to fallback to trying to resolve the overload as if it were passed a boxed Long, like it happens in this case:
(definterface IAnotherThing
(beFast [^Long x]))
(IAnotherThing/.beFast (reify IAnotherThing (beFast [_ x] 3)) 3)It doesn't need reflection since there are no alternatives.
yeah, ig this is why
I was a bit surprised the compiler accepted this line going as far back as Clojure 1.3 -- but it does, and also produces a reflection warning from 1.3 up to the latest:
(IThing/.beSlow x 1) ; causes reflection warningit does because it ignores the ns haha
Ah, right. I remember that being mentioned earlier in the 1.12 cycle now...
So I guess the answer to your original question is "yes"?
guess so 🤷
Still, not much of an issue. I guess the way the beSlow case is handled is consistent with the way resolution is handled in the presence of both a boxed-accepting and unboxed-accepting overload -where the unboxed-accepting overload is called only if an unboxed value is supplied-.
The thing that confuses me the most is why in the beFast case there is a silent fallback to the boxed-accepting overload, and that in the opposite situation (unboxed-accepting overload called with boxed value) reflection never arises.
In the beSlow case, you're attempting to use the qualified method IThing/.beSlow . In 1.12 qualified methods must resolve to a single signature, else invocation falls back to reflection. We can use param-tags to specify the exact method to invoke, i.e. (^[Long] IThing/.beSlow x 1) (note: attempting to use long in the param-tag is not a match for Long).
It just was to test if the behavior was consistent with the pre-1.12.x style interop.
None of these are reflective calls (from Clojure 1.3 to 1.12):
(definterface IThing
(boxed [^Long x])
(primitive [^long x]))
(def ^IThing x
(reify IThing
(boxed [_ ^Long _x] :boxed-long)
(primitive [_ ^long _x] :primitive-long)))
(.boxed x 1)
(.primitive x 1)
(.boxed x (Long. 1))
(.primitive x (Long. 1))
Because there's only one choice for each method and auto-boxing / auto-unboxing is used in both directions.yeah, the behavior only appears to come up when the signature can't be resolved by method name and arity alone
Right. Which is to be expected (at least, for me).