The Gamer Corner
Dr. Seuss couldn't have come up with this kind of shit
Balerion
Lost your password?

Everything that is wrong with java, in a nutshell

Everything that is wrong with java, in a nutshell – April 21, 2010 7:09 PM (edited 4/21/10 3:09 PM)
chaoscat (452 posts) Ambassador of Good Will
Rating: Not Rated
This is the root cause of a problem that has been plaguing me for over a day at this point:


import java.io.*;

public class StringValueOfDemo {
public static void main(String[] args) {
String intVersion = String.valueOf(65);
String charVersion = String.valueOf( (char)65 );

if (65 == (char)65) {
System.out.println("numeric values are equal");
}
else {
System.out.println("numeric values are not equal");
}

if (intVersion.equals(charVersion)) {
System.out.println("String values are equal");
}
else {
System.out.println("String values are not equal");
}
}
}
Output:

numeric values are equal
String values are not equal

What possible logic could exist under which it's good design to have a function which, given identical input, produces different output depending on the type you have cast the input value to make a whit of sense?

And it's not like this is in some obscure third party module - this is String. As in java.lang.String. As in a core language component. What the fuck, java? seriously, what the fuck?

_________________________________________________
Why in the world is your title "Ambassador of Good Will"? Is it some attempt at the Guiness Record for Irony?
--Balerion
Re: Everything that is wrong with java, in a nutshell – April 21, 2010 7:39 PM (edited 4/21/10 3:39 PM)
Cuzzdog (1522 posts) Head of Gamer Corner R&D
Rating: Not Rated
For what it's worth, the reason you get this is because == is overloaded for a numeric value. So behind the scenes your first if statement is really evaluating:

if (65 == (int)((char)65) )

Which is why the output is equal. It's also why you need to do MyString.equals "Hello" instead of MyString == "Hello"

This is, of course, not a defense of Java. It's just an explanation of what's happening for your own understanding.

Also, you need to understand what the function ValueOf does. ValueOf converts it's passed in argument from whatever type it is to a String. So in your example code you're calling two different overloaded functions String.ValueOf(int i) and String.ValueOf(char c). It's the same as initializing your input variables as:

String intVersion = "65";
String charVersion = (char)65;




n00b

Re: Everything that is wrong with java, in a nutshell – April 21, 2010 8:11 PM (edited 4/21/10 4:11 PM)
chaoscat (452 posts) Ambassador of Good Will
Rating: Not Rated
Most poor design decisions have some rationale behind them Wink

I guess to my mind, having a method that does two very different things depending on the type of the input is what bothers me here. I get what valueOf is doing, and I understand that I'm calling two essentially different methods that just happen to have the same name, based on the overloaded type input, but that doesn't make it ok.

The function of converting an integer to a string of digits, to my mind, seems much more appropriately placed in Integer.toString() (which, in fact, does exactly that, and don't get me started on having more than one routine that does this. Although, I suppose valueOf could just return the parameter's toString value, but then they would/should have made one version which takes an Object, not several typed versions.)

Point being, it does something unexpected, and that is almost always a Bad Thing.

_________________________________________________
Why in the world is your title "Ambassador of Good Will"? Is it some attempt at the Guiness Record for Irony?
--Balerion
Re: Everything that is wrong with java, in a nutshell – April 22, 2010 12:18 PM (edited 4/22/10 8:18 AM)
Cuzzdog (1522 posts) Head of Gamer Corner R&D
Rating: Not Rated
Your issue here isn't with valueOf. ValueOf is working exactly as it should be working. The function takes it's input and produces a string representation of that input. You passed it two different types of input and it gave you two different outputs. It's also providing a service not covered by Integer.toString(). Integer.toString() isn't a static method, meaning if you want to use that to convert an int to a sting you would need to do this:

int i = 5;
Integer i2 = i;
String s = i2.toString();

Instead of
int i =5;
String s = String.valueOf(i);

Further, valueOf is a common function to have in all the basic datatype classes (Integer, Float, Double, etc...), so it would be odd to not have that functionality in the String class as well.


The real issue you're having here is with the == operator, which in java compares references. Primitive data types in have the same references in java, but instantiated objects, obviously, do not. That's why you can test (int)i == 5 but not (String)s == "Hello". I believe even testing (Integer)i == 5 fails. Further, and this is what took me a while to understand as well, the primitive data type char is listed as a numeric in the same category as int. So (char)65 really does equal (int) 65. I believe you could even test 'A' == 65 (with single quotes around A) and get true back.

Re: Everything that is wrong with java, in a nutshell – April 22, 2010 1:08 PM (edited 4/22/10 9:08 AM)
chaoscat (452 posts) Ambassador of Good Will
Rating: Not Rated
A few points:

First off, Integer implements a static version of toString which is, as far as I can tell, identical to String.valueOf(int).

Second, my issue is not with the == operator. The sample code I posted is a watered down excerpt from my actual code, which was a little long and involved to make a nice demo. The actual issue I was having was trying to construct a delimited line of data where the delimiter was a non-printable ascii character. It looked something like:


String delim = String.valueOf(31);
String testData = "foo" + delim + "bar" + delim + "baz";

parser.parse(testData);

Needless to say, I was confused when my parser did not find any delimiters. Changing to


String delim = String.valueOf( (char)31 );

resolved the problem, prompting me to write the above test to figure out what was going on.

Finally, I do not have a problem with (char)65 == (int)65. I would be much more upset if they were not equal. My problem is that, given that the inputs are equal, the method should have equal outputs, which it clearly doesn't. The two behaviors are fundamentally different: one does an ascii lookup conversion, the other does a decimal digit conversion. That's a bad design choice. It's not clear from looking at the code what result you'll get from a given valueOf call, especially when you're calling it with the output of some other routine, which means essentially you will always need to cast it to ensure that the behavior you want is the one that is used. Type casting should definitely not be used to determine behavior. The two behaviors should have two different method names.

_________________________________________________
Why in the world is your title "Ambassador of Good Will"? Is it some attempt at the Guiness Record for Irony?
--Balerion
Active Users: (guests only)
1 user viewing | Refresh