Why?
If the posts title looks weird: it is. This is a small rant about code-functionality that makes little to no sense (in my eyes).
This whole article can be summed up like this:
How?
I was talking to a coworker about getting the numerical value of a character, like you can in Java, because a char
stores the number behind that character.
As an example of that behavior is this function, that counts the occurrence of every character:
public static int[] countCharacters(String input) {
int[] summand = new int[256];
for (char c : input.toCharArray()) {
summand[c]++;
}
return summand;
}
My naive suggestion was that you could just run number.to_i
to convert it to its (what I think is) ASCII number.
The problem with that are cases like converting "49".to_i
, where ruby, as a non-typed language, has to convert that to the number the string represents:
irb(main):017> "12".to_i
=> 12
irb(main):018> "12".sum
=> 99
On the one hand there is the "12".to_i
, which translates to 12
. Fair enough, that makes sense. The other case, where the String
doesn't represent a number, it just translates to 0
:
irb(main):012> "a".to_i
=> 0
irb(main):013> "fdsgsdf".to_i
=> 0
That leads to some weird (but expected) behaviour:
irb(main):003> summand = []
=> []
irb(main):006> summand["a".to_i] = 'test'
=> "test"
irb(main):008> summand["4".to_i] = 'test'
=> "test"
irb(main):009> summand
=> ["test", nil, nil, nil, "test"]
Now look closely at that first codeblock. You might realize that there are two operations used:
irb(main):017> "12".to_i
=> 12
irb(main):018> "12".sum
=> 99
The weird part is the "12".sum
- as ruby loves translating strings to the numbers they represent, you would expect that to translate to something like this:
irb(main):018> "12".sum
=> 12
irb(main):018> "12".sum
=> 3 # Because 1 + 2 = 3
But you get something completely different:
irb(main):018> "12".sum
=> 99
And now why does this happen you might as?
Because of this:
irb(main):027> "2".sum
=> 50
irb(main):028> "1".sum
=> 49
Because it takes their ASCII representation, the same as java does!
Okay, so shouldn't this work for accessing arrays?
This (obviously) doesn't work out of the box, as you need to convert the string to a number:
irb(main):004> summand["1"] = 'test'
(irb):4:in `[]=': no implicit conversion of String into Integer (TypeError)
summand["1"] = 'test'
^^^^^^^^^^^^^
from (irb):4:in `<main>'
irb(main):005> summand["a"] = 'test'
(irb):5:in `[]=': no implicit conversion of String into Integer (TypeError)
summand["a"] = 'test'
^^^^^^^^^^^^^
from (irb):5:in `<main>'
What about scientific notation?
"What about scientific notation?" you might ask. That's also what I was wondering:
irb(main):022> 2e10
=> 20000000000.0
irb(main):024> "2e10".to_i
=> 2
?!
Yes, you are seeing this right: It converts the "2e10"
to a 2
, as it's all the numbers until the first non-number. This behavior is seen in longer strings too:
irb(main):036> "21f10".to_i
=> 21
Here it cuts the to_i
operation after reaching the f
.
Actually converting scientific notation to a number
Now, how can we make this work? This is how:
irb(main):037> "2e10".to_f.to_i
=> 20000000000
And this only works, as numbers of scientific notation have the class Float
per default:
irb(main):038> 2e10.class
=> Float
For a dynamically-typed language it still seems to be unable to do a lot of casting for you!
Where is this leading?
Nowhere. Everything I mentioned before is really obscure and won't be important 99% of the time. This article is just for those 1% of cases.
Top comments (1)
How code communicates is a very interesting topic. I've got some comments on this and I hope that they are useful:
String#sum
in your explanation. Your argument against Ruby here would be better made against the naming of the checksum tooling.int
with anInteger
.int
from -127 to 128 are stored in a lookup table for efficiency. Or did you ever ask yourself why it has aNullPointerException
? There are no pointers (anymore).