java method overloading and clojure interop

199 views
Skip to first unread message

Jo Geraerts

unread,
Jul 7, 2015, 9:04:59 AM7/7/15
to clo...@googlegroups.com
Hello,

I'm trying to create a small wrapper for the java money api. The api uses method overloading. 



has methods

* multiply(long x)
* multiply(double x)
* multiply(Number x)

In clojure i want to do something like

(defn multiply[^MonetaryAmount amount multiplicant]
  (.multiply amount multiplicant))

Ofcourse i get reflection warnings. I can add typehints to the multiplicant to 1 of the 3 versions above, but obviously that doesnt allow me to expose the other versions.

What would be the most idiomatic choice to handle this?

Things i considered myself are:

* multimethods: they can only work on the boxed versions of long/double
* have different function names like multiplyLong multiplyDouble.... but that doesnt sound right either. 

Kr,

Jo

Mike Rodriguez

unread,
Jul 7, 2015, 10:33:48 PM7/7/15
to clo...@googlegroups.com
You can do some consional instance? checks at runtime and type hint each method call appropriately.

Java would determine the correct method based on the type information known to the compiler at compile time.

You don't have that given in Clojure so you have to runtime check the type and then dispatch to the correctly hinted method signature.

Mike Rodriguez

unread,
Jul 7, 2015, 10:36:26 PM7/7/15
to clo...@googlegroups.com
consional => conditional

Typo sorry.

Herwig Hochleitner

unread,
Jul 7, 2015, 11:20:51 PM7/7/15
to clo...@googlegroups.com
2015-07-07 15:04 GMT+02:00 Jo Geraerts <j...@umask.net>:
* multiply(long x)
* multiply(double x)
* multiply(Number x)

In clojure i want to do something like

(defn multiply[^MonetaryAmount amount multiplicant]
  (.multiply amount multiplicant))

Function parameters in Clojure, are generally passed as a java.lang.Object, so numbers are boxed by default.
Clojure does have infrastructure to pass primitive numbers, see invokePrim here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java#L97 see also http://clojure.org/java_interop#Java Interop-Support for Java Primitives
however, this requires a specific type hint on the multiply fn, so normally that means separate multiply-double and multiply-long fns.

The way I would do it: Define multiply as a function calling (.multiply amount ^Number x), for higher order usage, and then add an :inline function to its metadata, which returns `(.multiply ~amount ~x).
That acts as a compiler macro, which inlines the call to .multiply, that way, its parameter type can be assigned via local type inferrence (which clojure does).
Beware, that inline functions aren't public API and subject to change.

kind regards

Jo Geraerts

unread,
Jul 8, 2015, 3:11:07 AM7/8/15
to clo...@googlegroups.com
Herwig Hochleitner schreef op 2015-07-08 05:20:
> 2015-07-07 15:04 GMT+02:00 Jo Geraerts <j...@umask.net [1]>:
>
>> * multiply(long x)
>> * multiply(double x)
>> * multiply(Number x)
>>
>> In clojure i want to do something like
>>
>> (defn multiply[^MonetaryAmount amount multiplicant]
>>   (.multiply amount multiplicant))

> Function parameters in Clojure, are generally passed as a
> java.lang.Object, so numbers are boxed by default.
> Clojure does have infrastructure to pass primitive numbers, see
> invokePrim
>
> here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java#L97
> [2] see also http://clojure.org/java_interop#Java [3] Interop-Support
> for Java Primitives
> however, this requires a specific type hint on the multiply fn, so
> normally that means separate multiply-double and multiply-long fns.

> The way I would do it: Define multiply as a function calling
> (.multiply amount ^Number x), for higher order usage, and then add an
> :inline function to its metadata, which returns `(.multiply ~amount
> ~x).
> That acts as a compiler macro, which inlines the call to .multiply,
> that way, its parameter type can be assigned via local type
> inferrence
> (which clojure does).
>
> See http://www.bytopia.org/2014/07/07/inline-functions-in-clojure/#sec-3
> [4]
> Beware, that inline functions aren't public API and subject to
> change.

This is enlightening. I found such constructs in clojure's core.clj
cause there similar things should happen for certain functions, but i
couldn't fully grasp what was going on. In core.clj also quite some
dispatching happens to clojure.lang.RT which i figured was part of the
:inline setup.

Thank you for the explanation.


Kr,

Jo



Mike Rodriguez

unread,
Jul 8, 2015, 10:36:19 AM7/8/15
to clo...@googlegroups.com
Good call on the auto-boxing.  I wasn't considering that before, but obviously it is important.

Nice insight into :inline.  I never really did understand the usefulness of it before.

Jo Geraerts

unread,
Jul 9, 2015, 3:49:08 AM7/9/15
to clo...@googlegroups.com


Op woensdag 8 juli 2015 05:20:51 UTC+2 schreef Herwig Hochleitner:
The way I would do it: Define multiply as a function calling (.multiply amount ^Number x), for higher order usage, and then add an :inline function to its metadata, which returns `(.multiply ~amount ~x).
That acts as a compiler macro, which inlines the call to .multiply, that way, its parameter type can be assigned via local type inferrence (which clojure does).
Beware, that inline functions aren't public API and subject to change.


One more question. What does :inline-arities exactly do?

 

Herwig Hochleitner

unread,
Jul 9, 2015, 5:04:37 AM7/9/15
to clo...@googlegroups.com
:inline-arities tells the compiler, which arities (i.e. parameter counts) should be inlined: https://github.com/clojure/clojure/blob/9d70bc1051ec8117df6436e07474c586ea9e85b0/src/jvm/clojure/lang/Compiler.java#L6596


 

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages