Avoiding coercion of a Java constant

Hi,

Does JRuby allow you to pass a Java object without coercion? I’m trying
to call
some code java code which uses == to decide which static final Integer
it was passed.
So while the integer I pass in is the right value the code throws a not
recognised exception.

Since the constant is an Integer I can only see it as a Fixnum if I try
to use java_object I get
“undefined method `java_object’ for 1:Fixnum (NoMethodError)”.

The java looks roughly like this:

public static final Integer MODE_GSI = new Integer(1);
public static final Oid MODE = new Oid(…);

public void setOption( Oid key, Object value){
if key.equals(MODE){
if (v instanceof Integer && v == MODE_GSI){
// Work
} else {
throw new BigScaryException(“Not recognised”);
}
}
}

I can call the method without it complaining about the class of the
value with:

context.set_option(GSSConstants::GSS_MODE,
java.lang.Integer.new(GSIConstants::MODE_GSI))

but I get the exception.

Thanks

  Chris

I might be off the mark with this, but I don’t think your Java code will
work the way you are using it. Because you are using Integer objects
you
should be using the equals method on Integer and not ==. In your Ruby
code
you are creating a new Integer object, it happens to have the same int
value
as your constant, but in your Java code you are not checking their int
values, you are checking to see if it is the same object. Since you are
using the constructor for Integer this will never work. Now if you
changed
your code to use Integer.valueOf(1) then it might work how you are
doing
it because most JVM’s will cache some Integer objects for commonly used
values, but I still think your code is a little suspect. I would change
your Java code to this:

public static final Integer MODE_GSI = new Integer(1);
public static final Oid MODE = new Oid(…);

public void setOption( Oid key, Object value){
if key.equals(MODE){
if (MODE_GSI.equals(value)){
// Work
} else {
throw new BigScaryException(“Not recognised”);
}
}
}

On Wed, Apr 7, 2010 at 1:13 PM, Christopher Bayliss <

On Wed, Apr 7, 2010 at 2:52 PM, Joseph A. [email protected]
wrote:

your Java code to this:
Yeah, I was about to reply saying the same thing. It’s a bug waiting
to happen to do == checks against String or Number subclasses since
they get created and destroyed at the drop of a hat. For example, you
can’t pass an Integer object through an int method without it becoming
a new object on the other side.

This is also a bit of an antipattern in Java code where most people
will recommend using an Enumeration instead of integer values:

public enum ModeThing { GSI, ETC, SOMETHING_ELSE }

You can pass enum values around, == compare them, and much more
without running into the antipattern of numeric identifiers. They’re
also easier to keep backward compatible as you introduce new values.

As for the original question…there’s not really a way to prevent
coercion of Number or String coming out of Java right now, but it’s an
interesting idea. We have often kicked around the idea of not
auto-coercing anything coming from Java and just making them duck-type
to the appropriate Ruby behavior (i.e. defining a bunch of Ruby String
methods on Java String so it at least feels like a Ruby String). So
I feel your pain on this one, and it’s something we’ve talked about
but never had a good backward-compatible way to fix (obviously we
can’t just turn it off without affecting a lot of users). Having a way
to do a non-coerced call might be a useful feature to add…something
akin to java_send but more “direct”?

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Charles Oliver N. wrote:

values, but I still think your code is a little suspect. I would change
your Java code to this:

Yeah, I was about to reply saying the same thing. It’s a bug waiting
to happen to do == checks against String or Number subclasses since
they get created and destroyed at the drop of a hat. For example, you
can’t pass an Integer object through an int method without it becoming
a new object on the other side.

As I said in my earlier reply its a third party API.

This is also a bit of an antipattern in Java code where most people
will recommend using an Enumeration instead of integer values:

public enum ModeThing { GSI, ETC, SOMETHING_ELSE }

You can pass enum values around, == compare them, and much more
without running into the antipattern of numeric identifiers. They’re
also easier to keep backward compatible as you introduce new values.

Yes that would be easier however that library maintains Java 1.4
compatibility for some reason. ( Don’t ask why. It will hurt your brain)

to do a non-coerced call might be a useful feature to add…something
akin to java_send but more “direct”?

Well my first attempt was to try java_object as the documentation seems
to hint that this is the way to go about this. Obviously it doesn’t
work.

Chris


The University of Glasgow, charity number SC004401


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Joseph A. wrote:

a little suspect.� I would change your Java code to this:
That’s my problem. The Java code is a third party API so I can’t do the
obvious thing and switch to something from j.l.Comparable and JRuby
coerces the Integer auto-magically to a Fixnum so I can’t get at the raw
Java object.

One solution is to write a JRuby friendly interface in Java but I feel
that this anti-pattern is probably quite common and wondered if there
was a solution in pure JRuby.

}
Integer it was passed.
public static final Oid MODE = new Oid(…);

I can call the method without it complaining about the class of the
value with:

context.set_option(GSSConstants::GSS_MODE,
java.lang.Integer.new(GSIConstants::MODE_GSI))

but I get the exception.
 Chris


The University of Glasgow, charity number SC004401


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Thu, Apr 8, 2010 at 2:40 AM, Christopher Bayliss
[email protected] wrote:

That’s my problem. The Java code is a third party API so I can’t do the
obvious thing and switch to something from j.l.Comparable and JRuby coerces
the Integer auto-magically to a Fixnum so I can’t get at the raw Java
object.

What an awful thing for an API designer to do to you :slight_smile:

One solution is to write a JRuby friendly interface in Java but I feel that
this anti-pattern is probably quite common and wondered if there was a
solution in pure JRuby.

This is actually the first time (ever!) that anyone has asked for a a
“primitive” boxed value to be the same object coming in and going out.
It’s extremely rare to see this need.

The problem with trying to hack around it in Ruby is that even if you
get access to the raw methods directly, it’s still calling through
JRuby’s Java integration layers and will try to turn Integer into
Fixnum. I’ll poke around a bit and see if there’s any way to hack
around this.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Thu, Apr 8, 2010 at 2:07 PM, Charles Oliver N.
[email protected] wrote:

this anti-pattern is probably quite common and wondered if there was a
around this.
It’s easy to stop Integer’s auto coercion. Just commenting out the
line below in org.jruby.javasupport.JavaUtil,
JAVA_CONVERTERS.put(Integer.class, JAVA_INT_CONVERTER);
then Integer is proxied like other user defined classes.

However, I think this easy fix has at least two problems. The all
Integer values will be always Java::JavaLang::Integer type and don’t
have any way to convert to ruby type. Maybe, to_i or to_ruby should be
supported? And the bigger problem is… for users who expect auto
coercion, the change will be regression. We may need a new option to
stop auto coercion or something that controls turning on/off coercion.

-Yoko

  • Charlie

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

I think we need you to file a bug/feature issue for this, please. I
could not find a way to “route around” the coercion mechanisms from
Ruby, so it would need to be a change or enhancement to Java dispatch.
This probably won’t get into 1.5RC1, but it’s possible it might still
get into 1.5 final.

Let me know when you’ve filed an issue, and ideally provide an example
case so we have something to test against.

On Thu, Apr 8, 2010 at 1:07 PM, Charles Oliver N.
[email protected] wrote:

this anti-pattern is probably quite common and wondered if there was a
around this.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Has anyone said the word “light-weights” or “interface injection” yet?
:slight_smile:

The issue of boxed numeric types aside (sorry not an attempt to
hi-jack the thread) we should keep adding ducktypeable behavior to
classes when they line-up. Exception is a good example, but I imagine
if we spent a little time examining primary Java interfaces we could
probably get a pretty large list quickly.

-Tom

On Fri, Apr 9, 2010 at 2:04 PM, Charles Oliver N.
[email protected] wrote:

Integer values will be always Java::JavaLang::Integer type and don’t
UTF-8 encoded/decoded on the way in and out). But I haven’t been able
appropriate subclasses Integer, Float, Fixnum, etc.
auto-coercing, and people could start to play with it. That would show


blog: http://blog.enebo.com twitter: tom_enebo
mail: [email protected]


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Yeah, this seems like a good path forward, along with encouraging
people to ignore the actual types of “coercibles” entering Ruby from
Java. If we do our duck-typing job right and users keep this eventual
change in mind, the transition may be completely transparent.

On Friday, April 9, 2010, Thomas E Enebo [email protected] wrote:

access to java.lang.String.charAt or other string methods). In some
methods but act like a frozen Ruby String (no mutation)
java.lang.Throwable. Once we get to a point where we have all the


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 Thu, Apr 8, 2010 at 7:46 PM, Yoko H. [email protected] wrote:

It’s easy to stop Integer’s auto coercion. Just commenting out the
line below in org.jruby.javasupport.JavaUtil,
JAVA_CONVERTERS.put(Integer.class, JAVA_INT_CONVERTER);
then Integer is proxied like other user defined classes.

Yeah, it’s not a complicated change to make, but as you point out
below it would be a behavioral change.

However, I think this easy fix has at least two problems. The all
Integer values will be always Java::JavaLang::Integer type and don’t
have any way to convert to ruby type. Maybe, to_i or to_ruby should be
supported? And the bigger problem is… for users who expect auto
coercion, the change will be regression. We may need a new option to
stop auto coercion or something that controls turning on/off coercion.

I have secretly wanted to turn off all auto-coercion of Java values
entering Ruby simply because they automatically make it impossible to
get at the original Java objects (for example, it’s really hard to get
access to java.lang.String.charAt or other string methods). In some
cases, they can actually be a perf issue (like Strings having to be
UTF-8 encoded/decoded on the way in and out). But I haven’t been able
to reconcile the fact that people expect these coercions now with my
desire to eliminate them. We’re a bit stuck.

In a future “JRuby 2.0” it seems like the natural progression would be
to remove these auto-coercions and make the auto-coercing Java types
duck-type to the appropriate Ruby types. So for example:

  • java.lang.CharSequence/String would implement most Ruby String
    methods but act like a frozen Ruby String (no mutation)
  • java.lang.Number subclasses would implement methods from Numeric and
    appropriate subclasses Integer, Float, Fixnum, etc.

The ultimate goal would be to make those types act like the Ruby
equivalents and coerce to the Ruby equivalents (with to_s, to_str,
to_i, to_int, etc), but not actually coerce until you tell them to.

We could probably start this process by adding methods to the Java
types, similar to the work you did on making Java Maps look like a
Ruby Hash or the work I just did adding Ruby Exception methods to
java.lang.Throwable. Once we get to a point where we have all the
duck-typing in place, we could provide a flag or option to turn off
auto-coercing, and people could start to play with it. That would show
us where the gaps are. (and perhaps we could provide the flag earlier,
for people who are comfortable with the idea that Java values would
stop auto-coercing?)

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Charles Oliver N. wrote:

I think we need you to file a bug/feature issue for this, please. I
could not find a way to “route around” the coercion mechanisms from
Ruby, so it would need to be a change or enhancement to Java dispatch.
This probably won’t get into 1.5RC1, but it’s possible it might still
get into 1.5 final.

I’ve give in and started patching the library so this isn’t vital for
me.

Let me know when you’ve filed an issue, and ideally provide an example
case so we have something to test against.

Its JRUBY-4716. I’ve included a test case, small chunk of Java and a
Rake file to exercise it. Whether or not all the test cases should pass
is another question.

Interestingly, if you coerce an object then pass it back you seem to get
the same reference. This also happens if you create multiple JRuby
variables from the same Java source or copies.

 Chris

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email