Access to overloaded java method in org.jscience.physics.amount.Amount

42 views
Skip to first unread message

markm

unread,
Sep 15, 2008, 3:20:03 PM9/15/08
to Clojure
Hi,

Clojure novice here.

Macbook 2.4ghz/4gram/osx10.5.4/java1.6
Clojure from svn last week
Jython 2.5a3

I've been exploring using the jscience.org reference implementation of
JSR-275 to provide physical quantities support in Clojure. Generally,
things are working:

(import '(org.jscience.physics.amount Amount AmountFormat))
(import '(javax.measure.unit AlternateUnit BaseUnit CompoundUnit
DerivedUnit
Dimension NonSI ProductUnit SI SystemOfUnits
TransformedUnit Unit UnitFormat))
(import '(javax.measure Measure))

;;; Create an Amount by parsing string

(def amount1 (. Amount valueOf "234 mA"))
(def amount2 (. Amount valueOf "10 m"))
(def amt3 (. Amount valueOf "3 "))

;;; Create an Amount or Measure from long or double and a Unit

(def amount3 (. Amount valueOf 12.3 (. SI METER)))
(def amount4 (. Amount valueOf 100.0 (. NonSI POUND)))
(def amt-e2 (. Amount valueOf (long 33) (. NonSI FOOT)))
(def m1 (. Measure valueOf 100.0 (. NonSI POUND)))
(def m2 (. Measure valueOf 100 (. NonSI POUND)))

;;; Extract long or double value from a Measure with Unit conversion

(.doubleValue m1 (. SI KILOGRAM))
(.longValue m1 (. SI KILOGRAM))
(.doubleValue m2 (. SI KILOGRAM))
(.longValue m2 (. SI KILOGRAM))

;;; Chained access to nested stuff

(class (.. amt-e2 getUnit getDimension))

;;; Testing exactness ...

.isExact amt-e3)
(.getExactValue amt-e3)
(.isExact (.to amt-e3 (. SI METER)))

;;; Dividing and multiplying Amounts by Amounts

(.times amount4 amt3)
(def amt-e3 (.times (.divide amt-e2 (. Amount valueOf "11 ")) (.
Amount valueOf "2 ")))

;;; Dividing Amounts by long or double

(.divide amt-e3 33.2) ; Works (looks doubleish?)
(.divide amt-e3 33) ; Doesn't work (insufficiently
longish?)

java.lang.IllegalArgumentException: No matching method found: divide
java.lang.IllegalArgumentException: No matching method found: divide
at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:71)
at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
at user.eval__2453.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:3850)
at clojure.lang.Repl.main(Repl.java:75)

(.divide amt-e3 (long 33)) ; Works
(.divide amt-e3 (double 33.2)) ; Works


;;; Multiplying Amounts by long or double
; Doesn't find appropriate overloaded method

(.times amt-e3 (double 12.3))
(.times amt-e3 12.3)

java.lang.ClassCastException: java.lang.Double cannot be cast to
org.jscience.physics.amount.Amount
java.lang.ClassCastException: java.lang.Double cannot be cast to
org.jscience.physics.amount.Amount
at org.jscience.physics.amount.Amount.times(Amount.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:82)
at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
at user.eval__2381.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:3850)
at clojure.lang.Repl.main(Repl.java:75)

=============================================================
Using jython all types of parameters work for both divide and times
=============================================================

>>> from org.jscience.physics.amount import Amount

>>> amt1 = Amount.valueOf("3.2 ft")
>>> amt2 = Amount.valueOf("23 ft")
>>> amt3 = Amount.valueOf("3 ")

>>> amt1.divide(amt2)
>>> amt1.divide(amt3)
>>> amt.divide(3.2)
>>> amt1.divide(3)

>>> amt1.times(amt2)
>>> amt1.times(amt3)
>>> amt2.times(3)
>>> amt1.times(3.2)

Anyone have a clue to offer me?






.Bill Smith

unread,
Sep 15, 2008, 10:48:43 PM9/15/08
to Clojure
> (.divide amt-e3 33)                  ; Doesn't work (insufficiently longish?)
>
> java.lang.IllegalArgumentException: No matching method found: divide
[...]
> (.divide amt-e3 (long 33))         ; Works

That is because 33 is considered an integer, not a long:

user=> (. 33 (getClass))
java.lang.Integer
user=> (. (long 33) (getClass))
java.lang.Long

> (.times amt-e3 (double 12.3))
> (.times amt-e3 12.3)
>
> java.lang.ClassCastException: java.lang.Double cannot be cast to
> org.jscience.physics.amount.Amount
[...]

Looks like a Clojure bug. Investigating now.

Bill

Bill Smith

unread,
Sep 16, 2008, 12:14:42 AM9/16/08
to Clojure
Attached is a one-line change that appears to fix the problem.  Is there a Clojure test suite that I should run? 

The problem has to do with how Clojure deals with an overloaded method with a generic parameter.  The fix is to ignore bridge methods, I think.

Bill
diff.txt

Rich Hickey

unread,
Sep 16, 2008, 7:51:57 AM9/16/08
to Clojure
Unfortunately it's not that simple. That's what Clojure used to do,
and it works ok for Java 1.5. However, there are many non-filterable
functions tagged as bridge/synthetic in JDK 6. See this thread:

http://groups.google.com/group/clojure/browse_frm/thread/a4e1b58061962479/23a1efe8d9f45eb3

The workaround I came up with fails to filter the bridge method in
org.jscience.physics.amount.Amount. I'm still looking into this issue.

http://groups.google.com/group/jvm-languages/browse_frm/thread/a64c755db0a91c1c

Rich

markm

unread,
Sep 16, 2008, 9:48:54 AM9/16/08
to Clojure


On Sep 16, 7:51 am, Rich Hickey <richhic...@gmail.com> wrote:


...
> The workaround I came up with fails to filter the bridge method in
> org.jscience.physics.amount.Amount. I'm still looking into this issue.
>
> http://groups.google.com/group/jvm-languages/browse_frm/thread/a64c75...
>
> Rich

Below is the source code from Amount.divide and Amount.times for the
long and double parameter versions. Other than the obvious
substitution of variable and operator names, the times <double> and
divide <double> methods are structurally equivalent. The times <long>
and divide <long> method have one difference: the divide method makes
use of local variables <min> and <max> -- as do both double methods --
the times <long> method directly assigns the result of calculation
into the m._minimum and m._maximum fields.

===========Java code excerpt from Amount.java====================

public Amount<Q> times(double factor) {
Amount<Q> m = Amount.newInstance(_unit);
double min = (factor > 0) ? _minimum * factor : _maximum *
factor;
double max = (factor > 0) ? _maximum * factor : _minimum *
factor;
m._isExact = false;
m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
return m;
}

public Amount<Q> divide(double divisor) {
Amount<Q> m = Amount.newInstance(_unit);
double min = (divisor > 0) ? _minimum / divisor : _maximum /
divisor;
double max = (divisor > 0) ? _maximum / divisor : _minimum /
divisor;
m._isExact = false;
m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
return m;
}

public Amount<Q> times(long factor) {
Amount<Q> m = Amount.newInstance(_unit);
if (this._isExact) {
long productLong = _exactValue * factor;
double productDouble = ((double) _exactValue) * factor;
if (productLong == productDouble)
return m.setExact(productLong);
}
m._isExact = false;
m._minimum = (factor > 0) ? _minimum * factor : _maximum *
factor;
m._maximum = (factor > 0) ? _maximum * factor : _minimum *
factor;
return m;
}

public Amount<Q> divide(long divisor) {
Amount<Q> m = Amount.newInstance(_unit);
if (this._isExact) {
long quotientLong = _exactValue / divisor;
double quotientDouble = ((double) _exactValue) / divisor;
if (quotientLong == quotientDouble)
return m.setExact(quotientLong);
}
double min = (divisor > 0) ? _minimum / divisor : _maximum /
divisor;
double max = (divisor > 0) ? _maximum / divisor : _minimum /
divisor;
m._isExact = false;
m._minimum = (min < 0) ? min * INCREMENT : min * DECREMENT;
m._maximum = (max < 0) ? max * DECREMENT : max * INCREMENT;
return m;
}

=================================================

Could this difference be triggering the jdk/vm 1.6 into treating the
<whatever the name for the aggregate of> the 'times' methods
differently from the <whatever the name for the aggregate of> the
'divide' method?

Mark

Rich Hickey

unread,
Sep 16, 2008, 10:27:33 AM9/16/08
to Clojure


On Sep 16, 9:48 am, markm <markmilli...@gmail.com> wrote:
> On Sep 16, 7:51 am, Rich Hickey <richhic...@gmail.com> wrote:
>
> ...
>
> > The workaround I came up with fails to filter the bridge method in
> > org.jscience.physics.amount.Amount. I'm still looking into this issue.
>
> >http://groups.google.com/group/jvm-languages/browse_frm/thread/a64c75...
>
> > Rich
>
> Below is the source code from Amount.divide and Amount.times for the
> long and double parameter versions. Other than the obvious
> substitution of variable and operator names, the times <double> and
> divide <double> methods are structurally equivalent. The times <long>
> and divide <long> method have one difference: the divide method makes
> use of local variables <min> and <max> -- as do both double methods --
> the times <long> method directly assigns the result of calculation
> into the m._minimum and m._maximum fields.
>

> Could this difference be triggering the jdk/vm 1.6 into treating the
> <whatever the name for the aggregate of> the 'times' methods
> differently from the <whatever the name for the aggregate of> the
> 'divide' method?
>

No. The problem relates to times being inherited from
GroupMultiplicative<G>.

I understand what is happening, just trying to find a workaround that
will work for this case and not break on others (e.g. StringBuilder)

Rich

Rich Hickey

unread,
Oct 4, 2008, 4:17:57 PM10/4/08
to Clojure
I've hardwired the JDK 6 StringBuilder workaround to StringBuilder, so
the JScience stuff should now work.

Rich

markm

unread,
Oct 5, 2008, 10:06:42 AM10/5/08
to Clojure


On Oct 4, 4:17 pm, Rich Hickey <richhic...@gmail.com> wrote:

> I've hardwired the JDK 6 StringBuilder workaround to StringBuilder, so
> the JScience stuff should now work.
>
> Rich

Thanks Rich, works like a charm.
Reply all
Reply to author
Forward
0 new messages