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
on 07.08.2008 06:15
on 14.08.2008 12:07
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 Braun Charles Oliver Nutter 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 Braun email: mikio@cs.tu-berlin.de 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
on 15.08.2008 00:07
Mikio Braun 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
on 15.08.2008 16:42
> 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:in `setWithExceptionHandling' from org.jruby.java.addons.ArrayJavaAddons:108:in `copyDataToJavaArray' from org.jruby.javasupport.JavaClass:1486:in `javaArrayFromRubyArray' from org.jruby.java.addons.ArrayJavaAddons:80:in `to_java' from org.jruby.java.addons.ArrayJavaAddons$s_method_multi$RUBYFRAMEDINVOKER$to_java:-1:in `call' from org.jruby.runtime.CallSite$InlineCachingCallSite:156:in `cacheAndCall' from org.jruby.runtime.CallSite$InlineCachingCallSite:394:in `call' from org.jruby.ast.CallOneArgNode:57:in `interpret' from org.jruby.ast.NewlineNode:101:in `interpret' 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
on 15.08.2008 17:51
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 Braun <mikio@cs.tu-berlin.de> 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
on 18.08.2008 12:17
Charles Oliver Nutter 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
on 22.08.2008 12:13
Charles Oliver Nutter 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