Came to know Python via the famous article by Eric, where he recommended Python as the first language for programmers. I followed the doc from official website of Python, but the overall experience was not so satisfying. (Not exactly sure why.) I didn’t pursue this language too much afterwards, and the reason I told myself is that redundancy in this language, namely the : for introducing one block and the indentation inside one block. CoffeeScript is one example that removes this redundancy.

Someone may call this nitpicking, so more reasons are required to show Python is the not as intuitive as one thinks. Luckily, I came across this article recently.

Among the ten mistakes, only three are language (syntax) related, which do not have very intuitive semantics. Therefore, one get surprising outcome. The rest are problems existing in practice. (As one theorist, I don’t deal with problems in reality.)

  • OOP related. (#2 Using class variables incorrectly) It feels weird to use OOP in one scripting language, so I will skip this category.

  • Exception related. (#3 Specifying parameters incorrectly for an exception block) Exceptions maybe very useful in production code, but I have never written any production code, so I can’t comment on this category.

  • Programmer related. (#5 Modifying a list while iterating over it #7 Creating circular module dependencies) It’s just wrong in any languages, so what I can say…

  • Module related. (#8 Name clashing with Python Standard Library modules)

  • Compatibility related. (#9 Failing to address differences between Python2 and Python3)

  • Hidden stuff related. (#10 Misusing the __del__ method) I guess it’s not meant to be used, for it has this weird prefix.

function default arguments

Personally, I expect the code does what it seems to do, but I am wrong for Python. (I didn’t even bother myself to find out the “why” for Python.)

def foo (bar = [])
    return bar

Running above Python program in the repl:

>>> foo()
>>> foo()
["baz", "baz"]
>>> foo()
["baz", "baz", "baz"]

Fortunately, CoffeeScript is intuitive this time.

foo = (bar = []) -> bar.push 'baz'; bar

>>> foo()
[ 'baz' ]
>>> foo()
[ 'baz' ]
>>> foo()
[ 'baz' ]

scoping rules

This is pure stupid. Any reason to back up this design is excuse.

x = 10
def foo():
    x += 1
    print x

>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment

Let’s see what the right way is:

x = 10
foo = ->
  x += 1
  console.log x

>>> foo()

variables binding in closures

It’s actually one feature; variables are captured “by reference”.

x = [1..4].map (i) -> (x) -> x*i

y = (((x) -> x*i) for i in [1..4])

for f in x
  alert f 1 # expected behavior

for f in y
  alert f 1 # surprising behavior

As mentioned in the comment to the original post, generator is proposed as one solution to this problem. To be honest, it seems quite good, syntactically, but this generator syntax is too similar to list comprehension. It’s a matter of taste.