Fork me on GitHub
#clojure-dev
<
2021-11-24
>
Alex Miller (Clojure team)00:11:14

Well there are only I think 3 functions that have that ambiguity

Alex Miller (Clojure team)00:11:42

abs min max are the 3 I have in mind

seancorfield00:11:46

Yeah, I was poring over the API and saw that nearly everything else was either just for long or just for double. But those calls don't need type hints anyway so, again, I'm not sure what clojure.java.math buys us?

potetm01:11:42

You can call static methods as fns?

potetm01:11:24

My point is there is no mechanism in clojure to resolve those type hints for you (short of having 3 methods or a switch on type I guess).

potetm01:11:21

Oh wait, I see your point: If you must type hint to avoid reflection, then you’re back to wrapping every invocation in another fn.

potetm01:11:26

Yeah fair.

seancorfield01:11:56

FWIW, Clojure 1.11 Alpha 3 is officially on QA at World Singles Networks, along with several calls to random-uuid, parse-long, and parse-double which replace previous java.util.uuid/randomUUID, Long/parseLong, and Double/parseDouble calls respectively just to test things out.

Alex Miller (Clojure team)01:11:39

There are actually two things here to keep in mind - these fns are inlined, so if you want the best perf it's really on you to ensure there is a primitive local being passed to it (unboxing will happen automatically but, not the fastest of course). Type hinting helps really when you are combining this with other interop calls (they don't affect the inlining). Is it better than using static methods? Not really, perf will be similar, but you can use them as higher order functions if needed (caveats around boxing). But the reason we got into this was really discoverability. I believe it is far more likely that people will find and use these in good ways than reaching for java.lang.Math or math.numeric-tower (which is deeply bad from a perf perspective). That is, you are not the target audience. :) I would also say that I've looked at 100s of instances of public code using Math or numeric-tower and most of that code is doing things worse than what is in clojure.java.Math. We also looked at a variety of other options, including full polymorphic support ala the existing Numbers stuff around Clojure math. That is maybe objectively better but it is a huge amount of very tedious code. In the end it did not seem that much better than where we ended up.

thanks2 1
vlaaad08:11:14

So the over-arching goal is to make clojure more beginner friendly?

vlaaad08:11:59

since developers with experience in java can just use java.lang.Math…

seancorfield01:11:31

Ah, good to know the motivation. That makes perfect sense. Thank you!

1
seancorfield02:11:12

(I read over the ticket but clearly just skimmed it and didn't read it in-depth since all of this is covered in the ticket... I'm not sure I would have answered my own initial question, based just on the ticket details, but re-reading it I can see why abs and friends are not handled differently)

Alex Miller (Clojure team)02:11:50

even the ticket is a summation of 5x more work, but I really am working hard to get the core of it into these tickets

1
👍 1
quoll02:11:48

Interesting to see @seancorfield asking about clojure.lang.math as well. I did notice that the inlined versions aren’t going to get the type hints that the functions have, so I was interested to see this mentioned. https://clojurians.slack.com/archives/C03S1KBA2/p1637714515459500

quoll02:11:50

But I’m still wondering why the namespace is being kept in the java platform domain, when it can be reimplemented for other platforms as well?

quoll02:11:46

From the perspective of ClojureScript, there are a few missing functions, but these can be reimplemented manually. I’m in the process of doing this ATM

Alex Miller (Clojure team)03:11:29

there are a lot of guarantees in these methods - can those guarantees be met for JavaScript's notions of numbers (particularly 64-bit floats)? if yes, then that might make sense, but it was more than I wanted to bite off. if not, then what does it mean for it to be portable?

Alex Miller (Clojure team)03:11:40

the goal here was to expose java.lang.Math, not to make a portable math library

quoll03:11:43

On the first question… yes. On your point of wanting to expose the class, I do get it. But as someone who is constantly writing .cljc files, it will be frustrating to have identically operating functions between two of the common platforms coming from different namespaces.

1
quoll03:11:16

I just saw clojure.java as being a place to isolate things that only made sense on the JVM

quoll03:11:02

The implementation of js/Math also complies with IEEE-754, including the bit representations. The main thing is that js/Math is missing a few functions, but the source code for the bit manipulation is available in the JVM (e.g. java.lang.Math/IEEEremainder). I’m rewriting these for ClojureScript, though I’m probably not the only person doing that 🙂

Alex Miller (Clojure team)03:11:42

well, happy to have feedback. if it turns out to be closer then maybe we'll move it.

quoll03:11:09

OK. I’m doing a POC. If I can show that it’s the same, then I think I’ll have a stronger argument to make.

kenny14:11:22

Fwiw, we will also be maintaining a cljc wrapper around java.math and would much prefer the impl to be portable.

seancorfield02:11:52

"the inlined versions aren’t going to get the type hints" -- could you elaborate on that @quoll?

quoll03:11:04

Just that the inline versions don’t include type hinting at all. I think that the compiler will probably figure it out on almost everything though, won’t it?

quoll03:11:46

e.g. to-radians is just

(defn to-radians
  {:inline-arities #{1}
   :inline (fn [deg] `(Math/toRadians ~deg))}
  ^double [^double deg]
  (Math/toRadians deg))

Alex Miller (Clojure team)03:11:50

the type hints are helpful when you use these with other Java interop methods to disambiguate and avoid reflection (like if the result of this was passed to a method with overrides)

imre14:11:31

So, not having type hints on the inlined bit doesn't affect perf negatively for the case @quoll presented?

imre14:11:30

And for the likes of abs and the rest where there aren't any type hints, can reflection warnings be ignored if inputs are either long or double without a worry for performance?

Alex Miller (Clojure team)14:11:57

again, if the call is inlined the body isn't used so it doesn't matter

imre14:11:43

Thank you

Alex Miller (Clojure team)14:11:37

yields bytecode like this

Alex Miller (Clojure team)14:11:42

everything there is primitive long. you do still need type hints in a couple places

Alex Miller (Clojure team)14:11:49

actually, I don't think you even need the one on abs, you can leave that off (the return type one is needed to avoid boxing the return)

1
2
ghadi15:11:06

another nice thing is that the invokestatic call to java.lang.Math::abs is a hotspot intrinsic (like many of the methods on that class)

👏 2
Alex Miller (Clojure team)15:11:33

I think the one place where the reflective body matters is if you use these functions as a higher order function like (map math/abs nums) and that may drive us to a different choice on those (abs, min, max)

Alex Miller (Clojure team)15:11:04

thanks for the feedback on all this - that's why we do alphas

imre15:11:10

> (map math/abs nums) We don't use it precisely like that but there are some normalization fns in our codebase that are used transitively in multiple contexts and in those fns we cannot assume either long or double as both will come through. However, isn't one of the aims of the new namespace to enable using these fns as higher-order fns without having to wrap them?

Alex Miller (Clojure team)15:11:06

yes, that's why I just said we were considering some different choices for those ?

imre15:11:37

Ah, apologies, I wasn't sure your response directly implied that, all clear now. Thank you for releasing alphas and giving us the opportunity to provide feedback and adjust expectations!