Removing JI features

I’m still in the midst of the JI refactoring, and I’m coming across a
few places where it seems like features represent enough complexity and
enough code that they should just be deleted and reconsidered. Usually
these are obscure cases not covered by any current tests. Here’s one
example…

Ruby Array can be converted to a Java array in a number of ways. Some of
them are the obvious ones you know…the 99% cases:

ary.to_java # creates an Object array
ary.to_java(type) # creates an array of the specified type

type can be a class name (string or symbol) or a shortcut like :int

But then there’s a few other cases that no code anywhere in our tests
appears to use:

ary.to_java(type, dimensions)

creates an array of the specified type and specified dimensions,

recursively converting contained arrays

ary.to_java(type, dimensions, fill)

creates an array of the specified type and specified dimensions,

filling extra spaces with the fill value to make it even

I think I’d argue these two options should probably be punted. The code
involved is rather complicated, complicated enough that I don’t want
to port it to the new, faster logic and I don’t want to maintain and
write tests for it where none exist now. And I think there’s a very
strong case to be made that there’s little gain having these built-in
but implemented in Ruby when a few lines of inject logic could do both
of them pretty tidily in user code. That is, if users were doing this.

Eliminating these two variants would allow me to delete several hundred
lines of Array-coercing code. And the payoff is pretty big from this
rework:

code:

require ‘java’
require ‘benchmark’

TIMES = (ARGV[0] || 5).to_i

TIMES.times do
Benchmark.bm(30) do |bm|
bm.report(“control”) {a = [1,2,3,4]; 100_000.times {a}}
bm.report(“ary.to_java”) {a = [1,2,3,4]; 100_000.times {a.to_java}}
bm.report(“ary.to_java :object”) {a = [1,2,3,4]; 100_000.times
{a.to_java :object}}
bm.report(“ary.to_java :string”) {a = [1,2,3,4]; 100_000.times
{a.to_java :string}}
end
end

JRuby 1.1.3:
user system total real
control 0.015000 0.000000 0.015000 ( 0.015103)
ary.to_java 9.614000 0.000000 9.614000 ( 9.614086)
ary.to_java :object 10.657000 0.000000 10.657000 ( 10.656700)
ary.to_java :string 11.272000 0.000000 11.272000 ( 11.272060)

JRuby trunk (1.1.4):
user system total real
control 0.012000 0.000000 0.012000 ( 0.011422)
ary.to_java 0.302000 0.000000 0.302000 ( 0.301836)
ary.to_java :object 0.315000 0.000000 0.315000 ( 0.315322)
ary.to_java :string 0.540000 0.000000 0.540000 ( 0.540372)

Thoughts? Is anyone using the multi-dimensional Array#to_java variants?
Perhaps you’d be interested in providing a 5-line version with tests?

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hello Charles,

I just saw your post and it might already be too late, but I thought I’d
tell you my thoughts anyway.

I’m working on a java backed matrix library for jruby. One of the
constructors for a matrix takes a double[][] array to fill the initial
values of the matrix. Currently, I’m using the to_java(type) variant to
call that constructor from ruby like this:

DoubleMatrix.new([[1,2,3],[4,5,6],[7,8,9]].to_java(:double))

Are you thinking about removing the support for converting
multi-dimensional arrays, or are you only talking about the special
versions of to_java taking additional arguments?

So while my use might be somewhat marginal, being able to convert
multidimensional arrays would be useful.

Then again, I actually have to do some checks (for example to make sure
that the arrays in the array all have the same length and are numeric)
anyway, so I guess I could also live without that feature.

Best,

Mikio B.

Charles Oliver N. wrote:

ary.to_java(type) # creates an array of the specified type
ary.to_java(type, dimensions, fill)

ary.to_java 0.302000 0.000000 0.302000 ( 0.301836)

http://xircles.codehaus.org/manage_email


Dr. Mikio B. email: [email protected]
TU Berlin web: ml.cs.tu-berlin.de/~mikio
Franklinstr. 28/29 tel: +49 30 314 78627
10587 Berlin, Germany


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Mikio B. wrote:

DoubleMatrix.new([[1,2,3],[4,5,6],[7,8,9]].to_java(:double))

Are you thinking about removing the support for converting
multi-dimensional arrays, or are you only talking about the special
versions of to_java taking additional arguments?

I was just talking about the support for converting arrays using the
to_java versions that take extra arguments, but I can see where your
case would be useful. I believe that might have been taken out on trunk,
but it’s certainly possible to add it back in. Would it be possible for
you to pull trunk and we’ll see if we can come up with a middle ground
that works for this use case?

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Would it be possible for
you to pull trunk and we’ll see if we can come up with a middle ground
that works for this use case?

Ok, it seems that jruby-trunk actually doesn’t handle multi-dimensional
arrays anymore:

jruby-1.1.3:

a plain array and a nested (2d) array

a = [1,2,3]
==>[1, 2, 3]
b = [[1,2],[3,4],[5,6]]
==>[[1, 2], [3, 4], [5, 6]]

converting plain array to integer array

a.to_java(:long)
==>#<#Class:01xb8d09d:0x187f9f1 @java_object=[J@2a5ab9>

converting 2d array

b.to_java
==>#<#Class:01x177ff35:0x11402c4
@java_object=[[Ljava.lang.Object;@c19fbf>
b.to_java[0]
==>#<#Class:01x103d246:0x1e21f52
@java_object=[Ljava.lang.Object;@156d7c8>

converting 2d array to integer type

b.to_java(:long)
==>#<#Class:01x171120a:0x57828d @java_object=[[J@13c296b>
b.to_java(:long)[0]
==>#<#Class:01xb8d09d:0x1fa490e @java_object=[J@1a1bc40>

If I don’t pass a type, it just becomes Object[], as you can see if you
look at the first element. If you pass a type, it generates a 2d array

Now for jruby-trunk:

converting plain array to integer array

a.to_java(:long)
==>[J@122d9c

converting 2d array

b.to_java
==>[Ljava.lang.Object;@10bc995
b.to_java[0]
==>[1, 2]

converting 2d array to integer type

b.to_java(:long)
java.lang.reflect.Array:-2:in set': java.lang.IllegalArgumentException: argument type mismatch from org.jruby.javasupport.JavaArray:121:insetWithExceptionHandling’
from org.jruby.java.addons.ArrayJavaAddons:108:in
copyDataToJavaArray' from org.jruby.javasupport.JavaClass:1486:injavaArrayFromRubyArray’
from org.jruby.java.addons.ArrayJavaAddons:80:in to_java' from org.jruby.java.addons.ArrayJavaAddons$s_method_multi$RUBYFRAMEDINVOKER$to_java:-1:incall’
from org.jruby.runtime.CallSite$InlineCachingCallSite:156:in
cacheAndCall' from org.jruby.runtime.CallSite$InlineCachingCallSite:394:incall’
from org.jruby.ast.CallOneArgNode:57:in interpret' from org.jruby.ast.NewlineNode:101:ininterpret’
from org.jruby.ast.RootNode:126:in `interpret’
[…]

If I don’t pass a type, it seems that b.to_java[0] is a
RubyObject. If I pass a type, jruby crashes, I guess because
it has set up a long[] and then tries to put a RubyObject in there.

So, the question is how to deal with multi-dimensional
arrays, in particular multi-dimensional arrays for primitive
types. There, taking care of the inner arrays by hand won’t work.
Actually, I’m wondering how to generate multi-dimensional
arrays of primitive types at all from jruby at all, short of typing

java.lang.reflect.Array.newInstance(java.lang.Double::TYPE, [1, 3,
5].to_java(:int))

Although if you do it like this, you can then populate the inner arrays
using to_java even in jruby-trunk:

d = java.lang.reflect.Array.newInstance(java.lang.Double::TYPE, [2,
0].to_java(:int))
==>#<#Class:01x1c958af:0x1dd7736 @java_object=[[D@18c458>

d[0] = [1,2,3].to_java :double; d[1] = [4,5].to_java :double
==>[D@bb6086

d.to_a
==>[[1.0, 2.0, 3.0], [4.0, 5.0]]

So I guess one could either put the support for multi-dimensional arrays
back in, or
at least come up with a nice way to construct (empty) multi-dimensional
arrays, in particular
for primitive types.

Hope this helps,

Mikio

Charles Oliver N. wrote:

If you could come up with some specs (under spec/java_integration) that
pass under 1.1.3 and fail on trunk, we can use that as a start. There
are some existing specs there for arrays you can build off.

  • Charlie

[1,2,3].to_java(Java::long[]) looks quite reasonable.

I wonder if once couldn’t integrate arrays even more to be
automatically cast. But then again, you would also want to be able
pass Hashes, etc. Ultimately, you might want to be able to control how
ruby objects are passed to the java side. But I guess that is still
far in the future.

Anyways, I’ll have a look the the rspec stuff.

-M

I think we can either put it back on top of the rewritten logic (so
everything else is still fast) or provide a better way to indicate you
want a multidimensional array.

For example, since what you actually want is an array of arrays of
that component type, maybe we specify to_java Java::long[] and
recognize from that we need to convert component elements. I recognize
the need for a way to create a multidim array from a ruby array, but I
think we need to partition that logic and make it a little less
“magic” so as not to penalize the much more common single-dim case.

If you could come up with some specs (under spec/java_integration)
that pass under 1.1.3 and fail on trunk, we can use that as a start.
There are some existing specs there for arrays you can build off.

  • Charlie

On Aug 15, 2008, at 10:43, Mikio B. [email protected] wrote:

converting 2d array

b.to_java(:long)[0]

converting plain array to integer array

b.to_java(:long)
$RUBYFRAMEDINVOKER$to_java:-1:in `call’
RubyObject. If I pass a type, jruby crashes, I guess because
5].to_java(:int))
==>[D@bb6086

<multidim.rb>
<multidim-by-hand.rb>

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Charles Oliver N. wrote:

If you could come up with some specs (under spec/java_integration) that
pass under 1.1.3 and fail on trunk, we can use that as a start. There
are some existing specs there for arrays you can build off.

  • Charlie

Sorry, it took a bit longer, I got diverted on other things. I wrote
some specs for multi-dimensional arrays (only for double right now,
but the problem is the same for other types) which run under
jruby-1.1.3 and fail on trunk. I’ve attached the diff as I got it from
svn diff.

Actually, although the specs pass under 1.1.3, I think the behavior is
not correct when you have non-rectangular multi-dimensional arrays
like [[1,2],[3]] which are converted to [[1,2],[3,0]]. (See comments
in the spec file)

Hope this helps,

-M