Javascript and the pitfalls of weak typing
've had a bit of free time of late, due to the sleepless nights that my newborn son is assisting, and for some reason or another, I decided to write an extension for KomodoEdit that worked along the same lines as an addin for Visual Studio called CopySourceAsHtml.
The problem
Anyhoo, I had a bug that I couldn't figure out - in my HTML writing function, all my line delimiters were being converted to . That is, whenever \r\n or \n were encountered, the function was supposed to close any open spans and insert a break element, but a was being inserted instead.
The code responsible:
var c = text[i]; var s = styles[i] if (s == 0) { //Is whitespace of some sort if (s == " ") { sb.push(" "); } else if (c == "\t") { sb.push(" "); //tab } else if (c == "\r") { continue; } else { // \n if (innerSpanOpen == true) { sb.push("</span>"); //close inner span innerSpanOpen = false; }
sb.push("</span>"); //close line newRow = true; } }
You're (as in me) doing it wrong
The ultimate root of the error was me using undescriptive variable names, as it made confusion far too easy, so c has now been refactored to character and s to style. But my lack of understanding of Javascript also played a key part. The error stems from this line in particular:
if (s == " ") {
This is a typo/logical error. It was 4am in the morning when I was writing this, so probably the latter. I of course, wanted to check if the character was a space, not the style, which is an integer, but the reason that it was always returning true is an interesting one for me, because it was always returning true when s/style was 0, when compared to a string consisting of a space.
Dynamic types, weakly held
So, it turns out that in Javascript 0 == " ". This confused me, as I couldn't see how that worked (did I mention my background is 99% strongly typed languages?), so after some digging through the Mozilla Javascript reference I came across this:
When comparing a number and a string, the string is converted to a number value. JavaScript attempts to convert the string numeric literal to a Number type value. First, a mathematical value is derived from the string numeric literal.
The Javascript reference shed no further light on how a mathematical value was derived, so I downloaded ECMA-262, the ECMAScript spec, and presto:
The conversion of a string to a number value is similar overall to the determination of the number value for a numeric literal (see 7.8.3), but some of the details are different, so the process for converting a string numeric literal to a value of Number type is given here in full. This value is determined in two steps: first, a mathematical value (MV) is derived from the string numeric literal; second, this mathematical value is rounded as described below.
The MV of StringNumericLiteral ::: [empty] is 0. The MV of StringNumericLiteral ::: StrWhiteSpace is 0.
So there we go. 0 == " " in Javascript because it does. On the plus side, I hadn't even realised that Javascript had a === operator, so I'll be using that a bit more often.
It's worth noting that this code would've caused mysterious errors in most type systems. In a strongly typed language like Python, the error would have manifested as a lack of generation of non-breaking spaces, as the condition would've always evaluated to False.