Recently I had the dubious pleasure of working simultaneously in
C++, Python and JavaScript. I'm not saying that there is anything
wrong with any of these languages, but if you rapidly switch
back and forth between them (as, for instance, when you're
developing a JavaScript Web 2.0 application with the server in Django
and the front end), things can get pretty confused.
The
P90x
guys claim that muscle confusion leads to increased strength,
but in my experience, programming language confusion mostly leads to
problems.
The basic problem is that these languages have fairly similar
syntaxes and so it's pretty easy to inadvertantly use
the syntax of language A with language B. Here's a sampling of
some common tasks in these languages:
Task | C++ | Python | JavaScript |
Statement Separation | ; terminated | new line | ; semicolon separated (optional) |
Length of an array |
v.size() (for STL vectors) |
len(v) |
v.length |
Append to an array |
v.push_back(x) |
v.append(x) |
v.push(x)
|
Iterate through an array |
for(size_t i; i<v.size(); i++) |
for(x in v) |
for(var i=0; i<v.length; i++) |
Is an element in an associative array? |
if (a.count(k)) |
if k in a |
if (a[k]) |
Creating a new object |
new ClassName() |
ClassName() |
new Constructor() |
To make matters worse, sometimes what you would do in one
language is syntactically valid, but undesirable, in another
language and invalid in a third. For instance, in Python
you don't use semicolons to terminate statements at all,
but it doesn't choke if you use them. In JavaScript, you
mostly need them and JS will "insert" them as needed
[*]. In C++, semicolons are required and
if you don't add them, the compiler will throw an error.
So, if you switch back and forth, you're constantly
adding spurious semicolons in Python code (which makes
Python people sad) and omitting them in C++.
To take a more irritating example, consider asking
if an element is an associative array. This is actually
a lot more painful: if you do if (a[k])
on a C++ map, as is natural in JavaScript, C++ will automatically
instantiate a new copy of whatever's in the array
using the default constructor and place it at location k.
This can have really undesirable consequences, since you've
just modified the structure you mean to be examining. On the
other hand, if you dereference a nonexistent
location, it throws a KeyError, like so:
>>> a = {}
>>> a['b']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'b'
>>>
Unfortunately, this is a runtime error, so it's easy not to
notice this mistake until you get fairly far into the program,
especially if you're just checking for existence as a corner
case where the key is usually present.
Iterating through an array is another case where it's easy
to mess up. In JavaScript, like C++, you iterate through
an array by using an index from 0 to array length - 1.
In Python, however, you can iterate through it more easily
just by using for x in v
where v
is the array. Unfortunately, a similar construct is
syntactically legal in JavaScript, but the result
isn't what you want:
> a = ['a', 'b', 'c']
["a", "b", "c"]
> for (x in a) { console.log(x); }
0
1
2
undefined
Instead of iterating through the array, we're iterating
through the array indices. Again, this is syntactically
valid code, it just doesn't do what you want (though
perhaps you might want to use this as an alternative
to the familiar for (i=0; i<a.length; i++)
idiom.) Unfortunately, if you don't test your code
carefully, it might not be something you noticed.
To make matters more confusing,
the for (x in a)
idiom works fine for
another common data structure enumeration task:
enumerating the keys in a map in both Python and
JavaScript.
None of this is intended to be a criticism of the syntax
of any language, the problem is the conflict between
the syntax of each language. This is particularly troublesome
for Web applications because the client side more or less
must be written in JavaScript but the most popular Web
frameworks are written in either Python (Django) or
Ruby (RoR), so it's common to have to work in two languages
at once. I don't even want to think about what happens
if you have to work in a framework that uses Java, a language,
which, despite it's name, is not really related to JavaScript,
though they have confusingly similar syntax.
This is one advantage of Node,
a server for developing Web (or any other server)
application in JavaScript. Since the client side being
written in JavaScript is a fixed point, Node allows you
to write your entire system in JavaScript. Of course,
depending on your opinion of JavaScript, that may seem like a distinctly
mixed blessing.