Home » Modeling » EMF » EObject#eSet and autoboxing
|
Re: EObject#eSet and autoboxing [message #652254 is a reply to message #652229] |
Thu, 03 February 2011 10:36 |
Ed Merks Messages: 33218 Registered: July 2009 |
Senior Member |
|
|
Tom,
Comments below.
Tom Schindl wrote:
> Hi,
>
> I've been run into troubles using eSet, primitive values and autoboxing
> (in conjunction with databinding where I was able to fix the problem).
>
> Suppose you have the following feature:
>
> -----------8<-----------
> private long myLongFeature;
>
> public void setMyLongFeature(long myLongFeature) {
> // ...
> }
>
> public void eSet(int featureID, Object newValue) {
> switch (featureID) {
> //
> setMyLongFeature((Long)newValue);
> }
> }
> -----------8<-----------
>
> Now the problem is that when databinding under certain circumstances
> converts a String to a number it can happen that the eSet-Method is
> called with an int-value which results in ClassCastException because an
> int is converted to Integer and the cast above fails.
>
As it should...
> My question now is would it be better if we'd make the eSet get
> generated like this:
>
> -----------8<-----------
> public void eSet(int featureID, Object newValue) {
> switch (featureID) {
> //
> setMyLongFeature(((Number)newValue).longValue());
> }
> }
>
It's never been the intention for eSet to do any kind of type
conversion. In the case of int you'd do the same, and if you passed a
long that was too big, it would just truncate the value...
> -----------8<-----------
>
> My understanding of autoboxing is that this is more or less what the
> compiler makes from setMyLongFeature((Long)newValue) anyways because at
> the bytecode level you'll get something like this:
>
> -----------8<-----------
> setMyLongFeature(((Long)newValue).longValue());
> -----------8<-----------
>
> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
> myinstance.setMyLongFeature(10).
>
> So my suggestion would be to make the eSet-code behave like statically
> typed Java method calls in terms of primitive conversion (for types like
> long/double this is as easy as shown above) for other types the
> primitive conversion rules have be taken into account.
>
I don't think this is a great idea. It makes all numbers
interchangeable in any direction, some of them lossy. That's just not
the intent...
> Tom
>
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: EObject#eSet and autoboxing [message #652256 is a reply to message #652254] |
Thu, 03 February 2011 11:06 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
[...]
> It's never been the intention for eSet to do any kind of type
> conversion. In the case of int you'd do the same, and if you passed a
> long that was too big, it would just truncate the value...
Is it really a conversion when we talk about primitives? Isn't every int
a long - so to any method I can pass a long I'm free to pass an int,
short, char, byte?
>> -----------8<-----------
>>
>> My understanding of autoboxing is that this is more or less what the
>> compiler makes from setMyLongFeature((Long)newValue) anyways because at
>> the bytecode level you'll get something like this:
>>
>> -----------8<-----------
>> setMyLongFeature(((Long)newValue).longValue());
>> -----------8<-----------
>>
>> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
>> myinstance.setMyLongFeature(10).
>>
>> So my suggestion would be to make the eSet-code behave like statically
>> typed Java method calls in terms of primitive conversion (for types like
>> long/double this is as easy as shown above) for other types the
>> primitive conversion rules have be taken into account.
>>
> I don't think this is a great idea. It makes all numbers
> interchangeable in any direction, some of them lossy. That's just not
> the intent...
This is certainly NOT true for double/long as you wrote "some of them
lossy".
Would it change your opinion when I tell you that Java-Reflection does
what I request here?
> import java.lang.reflect.Method;
>
> public class TestReflection {
>
> public static void setLong(long l) {
> System.err.println("Long: " + l);
> }
>
> public static void setInt(int i) {
> System.err.println("Integer: " + i);
> }
>
> public static void setShort(short s) {
> System.err.println("Short: " + s);
> }
>
> public static void setDouble(double i) {
> System.err.println("Double: " + i);
> }
>
> /**
> * @param args
> */
> public static void main(String[] args) {
> // TODO Auto-generated method stub
> try {
> Method m = TestReflection.class.getMethod("setLong", new Class[] { long.class });
> m.invoke(null, new Object[] { 10 } );
>
> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
> m.invoke(null, new Object[] { 10 } );
>
> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
> m.invoke(null, new Object[] { 10L } );
>
> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
> m.invoke(null, new Object[] { 10f } );
>
> //WILL FAIL m = TestReflection.class.getMethod("setInt", new Class[] { int.class });
> // m.invoke(null, new Object[] { 10L } );
>
> //WILL FAIL m = TestReflection.class.getMethod("setShort", new Class[] { short.class });
> // m.invoke(null, new Object[] { 10 } );
> } catch (Exception e) {
> // TODO Auto-generated catch block
> e.printStackTrace();
> }
> }
>
> }
So it looks like Java-Reflection has certain rules when it comes to
primitive types when called reflectively.
To a method with:
* double: you can pass Double,Float,Long,Integer,Short,Character,Byte
* float: you can pass Float,Integer
* long: you can pass Long,Integer,Short,Character,Byte
* ...
Tom
|
|
|
Re: EObject#eSet and autoboxing [message #652418 is a reply to message #652256] |
Thu, 03 February 2011 19:48 |
Ed Merks Messages: 33218 Registered: July 2009 |
Senior Member |
|
|
This is a multi-part message in MIME format.
--------------000000080702080309020700
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit
Tom,
Comments below.
Tom Schindl wrote:
> [...]
>
>> It's never been the intention for eSet to do any kind of type
>> conversion. In the case of int you'd do the same, and if you passed a
>> long that was too big, it would just truncate the value...
>>
>
> Is it really a conversion when we talk about primitives? Isn't every int
> a long - so to any method I can pass a long I'm free to pass an int,
> short, char, byte?
>
Well of course the issue is, how does this generalize?
>
>>> -----------8<-----------
>>>
>>> My understanding of autoboxing is that this is more or less what the
>>> compiler makes from setMyLongFeature((Long)newValue) anyways because at
>>> the bytecode level you'll get something like this:
>>>
>>> -----------8<-----------
>>> setMyLongFeature(((Long)newValue).longValue());
>>> -----------8<-----------
>>>
>>> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
>>> myinstance.setMyLongFeature(10).
>>>
>>> So my suggestion would be to make the eSet-code behave like statically
>>> typed Java method calls in terms of primitive conversion (for types like
>>> long/double this is as easy as shown above) for other types the
>>> primitive conversion rules have be taken into account.
>>>
>>>
>> I don't think this is a great idea. It makes all numbers
>> interchangeable in any direction, some of them lossy. That's just not
>> the intent...
>>
>
> This is certainly NOT true for double/long as you wrote "some of them
> lossy".
>
Actually it's is true for Double->Long.
> Would it change your opinion when I tell you that Java-Reflection does
> what I request here?
>
Not necessarily. Complexity is something that is often best avoided.
So something that's not been an issue for almost 10 years might be
better off left as is.
>
>> import java.lang.reflect.Method;
>>
>> public class TestReflection {
>>
>> public static void setLong(long l) {
>> System.err.println("Long: " + l);
>> }
>>
>> public static void setInt(int i) {
>> System.err.println("Integer: " + i);
>> }
>>
>> public static void setShort(short s) {
>> System.err.println("Short: " + s);
>> }
>>
>> public static void setDouble(double i) {
>> System.err.println("Double: " + i);
>> }
>>
>> /**
>> * @param args
>> */
>> public static void main(String[] args) {
>> // TODO Auto-generated method stub
>> try {
>> Method m = TestReflection.class.getMethod("setLong", new Class[] { long.class });
>> m.invoke(null, new Object[] { 10 } );
>>
>> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
>> m.invoke(null, new Object[] { 10 } );
>>
>> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
>> m.invoke(null, new Object[] { 10L } );
>>
>> m = TestReflection.class.getMethod("setDouble", new Class[] { double.class });
>> m.invoke(null, new Object[] { 10f } );
>>
>> //WILL FAIL m = TestReflection.class.getMethod("setInt", new Class[] { int.class });
>> // m.invoke(null, new Object[] { 10L } );
>>
>> //WILL FAIL m = TestReflection.class.getMethod("setShort", new Class[] { short.class });
>> // m.invoke(null, new Object[] { 10 } );
>> } catch (Exception e) {
>> // TODO Auto-generated catch block
>> e.printStackTrace();
>> }
>> }
>>
>> }
>>
>
> So it looks like Java-Reflection has certain rules when it comes to
> primitive types when called reflectively.
>
I guess the question is, what are the rules?
> To a method with:
> * double: you can pass Double,Float,Long,Integer,Short,Character,Byte
> * float: you can pass Float,Integer
> * long: you can pass Long,Integer,Short,Character,Byte
> * ...
>
So conversions that are statically know to be non-lossy... But how to
capture these rules in generated code? Are the subclasses of Number
bounded?
It' seems
> Tom
>
>
--------------000000080702080309020700
Content-Type: text/html; charset=ISO-8859-15
Content-Transfer-Encoding: 8bit
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-15"
http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Tom,<br>
<br>
Comments below.<br>
<br>
Tom Schindl wrote:
<blockquote cite="mid:iie1s1$9p2$1@news.eclipse.org" type="cite">
<pre wrap="">[...]
</pre>
<blockquote type="cite">
<pre wrap="">It's never been the intention for eSet to do any kind of type
conversion. In the case of int you'd do the same, and if you passed a
long that was too big, it would just truncate the value...
</pre>
</blockquote>
<pre wrap=""><!---->
Is it really a conversion when we talk about primitives? Isn't every int
a long - so to any method I can pass a long I'm free to pass an int,
short, char, byte?
</pre>
</blockquote>
Well of course the issue is, how does this generalize?<br>
<blockquote cite="mid:iie1s1$9p2$1@news.eclipse.org" type="cite">
<pre wrap="">
</pre>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">-----------8<-----------
My understanding of autoboxing is that this is more or less what the
compiler makes from setMyLongFeature((Long)newValue) anyways because at
the bytecode level you'll get something like this:
-----------8<-----------
setMyLongFeature(((Long)newValue).longValue());
-----------8<-----------
This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
myinstance.setMyLongFeature(10).
So my suggestion would be to make the eSet-code behave like statically
typed Java method calls in terms of primitive conversion (for types like
long/double this is as easy as shown above) for other types the
primitive conversion rules have be taken into account.
</pre>
</blockquote>
<pre wrap="">I don't think this is a great idea. It makes all numbers
interchangeable in any direction, some of them lossy. That's just not
the intent...
</pre>
</blockquote>
<pre wrap=""><!---->
This is certainly NOT true for double/long as you wrote "some of them
lossy".
</pre>
</blockquote>
Actually it's is true for Double->Long.<br>
<blockquote cite="mid:iie1s1$9p2$1@news.eclipse.org" type="cite">
<pre wrap="">
Would it change your opinion when I tell you that Java-Reflection does
what I request here?
</pre>
</blockquote>
Not necessarily.
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: EObject#eSet and autoboxing [message #652426 is a reply to message #652418] |
Thu, 03 February 2011 20:22 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
Am 03.02.11 20:48, schrieb Ed Merks:
> Tom,
>
> Comments below.
>
> Tom Schindl wrote:
>> [...]
>>
>>> It's never been the intention for eSet to do any kind of type
>>> conversion. In the case of int you'd do the same, and if you passed a
>>> long that was too big, it would just truncate the value...
>>>
>>
>> Is it really a conversion when we talk about primitives? Isn't every int
>> a long - so to any method I can pass a long I'm free to pass an int,
>> short, char, byte?
>>
> Well of course the issue is, how does this generalize?
>>
>>>> -----------8<-----------
>>>>
>>>> My understanding of autoboxing is that this is more or less what the
>>>> compiler makes from setMyLongFeature((Long)newValue) anyways because at
>>>> the bytecode level you'll get something like this:
>>>>
>>>> -----------8<-----------
>>>> setMyLongFeature(((Long)newValue).longValue());
>>>> -----------8<-----------
>>>>
>>>> This way a call to myinstance.eSet(MY_LONG_FEATURE,10) works like
>>>> myinstance.setMyLongFeature(10).
>>>>
>>>> So my suggestion would be to make the eSet-code behave like statically
>>>> typed Java method calls in terms of primitive conversion (for types like
>>>> long/double this is as easy as shown above) for other types the
>>>> primitive conversion rules have be taken into account.
>>>>
>>>>
>>> I don't think this is a great idea. It makes all numbers
>>> interchangeable in any direction, some of them lossy. That's just not
>>> the intent...
>>>
>>
>> This is certainly NOT true for double/long as you wrote "some of them
>> lossy".
>>
> Actually it's is true for Double->Long.
I meant there's not potential loss for methods who get passed in a
double or long ;-)
>> Would it change your opinion when I tell you that Java-Reflection does
>> what I request here?
>>
> Not necessarily. Complexity is something that is often best avoided.
> So something that's not been an issue for almost 10 years might be
> better off left as is.
[...]
> I guess the question is, what are the rules?
>> To a method with:
>> * double: you can pass Double,Float,Long,Integer,Short,Character,Byte
>> * float: you can pass Float,Integer
>> * long: you can pass Long,Integer,Short,Character,Byte
>> * ...
>>
> So conversions that are statically know to be non-lossy... But how to
> capture these rules in generated code? Are the subclasses of Number
> bounded?
I'll try to find that out ;-)
Tom
|
|
|
Goto Forum:
Current Time: Tue Sep 24 21:34:34 GMT 2024
Powered by FUDForum. Page generated in 0.03090 seconds
|