With all of the praise of “typeless” languages in the past few days across a number of CF blogs, it was ironic that a co-worker ran into a real world example at work yesterday of a strong counterpoint to using typless languages. I use typeless in quotes as all variables in ColdFusion are eventually cast as something in Java. Now don’t get me wrong, I’m more of a fan of typeless languages myself because I can get things done much faster, but here is an instance where it lets us down (at least in ColdFusion). Granted this is one of those rare cases that most developers will probably never run into, but it does happen obviously.
Said problem seems to happen in all versions of CFMX when comparing two large integers. If both integers were different but contained a large number of digits, they would both return true. For instance, this bit of code will return true (pardon the formatting):
<cfset Variables.num1 = 25309420985992540513730623 />
<cfset Variables.num2 = 25309420985992540513730622 />
<cfif Variables.num1 EQ Variables.num2>
<p>They are equal</p>
<p>They are not equal</p>
If you add a letter into those variables or compare them using ListFind(), they are then cast as a string by CF and are evaulated correctly. Why would two seemingly normal integers which are obviously not the same not compare correctly? Our running theory is that all integers in CF are converted to the Java datatype of double in the whole auto-scalarizing magic that CF uses to convert our “messy” typeless code to typed variables.
So why does it matter that they are probably cast as double? At a very high level, the double datatype looses accuracy as the number of digits for a given number increase which explains why two large numbers with a difference of only 1 would seem to be the same at the machine level. There is a large amount of mathmatic theory regarding floating point representation of numbers behind this basic assumption, so feel free to read more about that here in detail if you wish to learn more about how they work. At a bit lower level, you can read about the various Java data types here.
I assume this is done so that if a number with decimal (a double, float, etc) is added to an existing integer, there will not be any casting problems. However, it does propose an interesting problem to be aware of when working with large integers in ColdFusion MX. It would seem like the best way to get around this is if you expect to be comparing large integers, use ListFind() rather than EQ in if statements.
12/5 Update: Spike Milligan tried to add a comment about this but apparently my comments are broken at the moment (still haven’t had a chance to take a look at them). Anyhow, apparently this is a known issue and you should use the Compare() method to get around problems like this. I almost always find myself comparing/evaluating booleans as most strings I work with are processed in a switch statement and had never run across this before, but it’s certainly good to know. Thanks Spike!