Ruby Forum JRuby > Removing JI features

Posted by Charles Oliver Nutter (Guest)
on 07.08.2008 06:15
(Received via mailing list)
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
Posted by Mikio Braun (Guest)
on 14.08.2008 12:07
(Received via mailing list)
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
Posted by Charles Oliver Nutter (Guest)
on 15.08.2008 00:07
(Received via mailing list)
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
Posted by Mikio Braun (Guest)
on 15.08.2008 16:42
Attachment: multidim.rb (307 Bytes)
Attachment: multidim-by-hand.rb (206 Bytes)
(Received via mailing list)
> 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
Posted by Charles Oliver Nutter (Guest)
on 15.08.2008 17:51
(Received via mailing list)
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
Posted by Mikio Braun (Guest)
on 18.08.2008 12:17
Attachment: signature.asc (253 Bytes)
(Received via mailing list)
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
Posted by Mikio Braun (Guest)
on 22.08.2008 12:13
Attachment: signature.asc (253 Bytes)
(Received via mailing list)
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