Developer Aspirations

YAPB - Yet Another Programming Blog



August 2012

An argument against Python

by Colin Miller, on Languages, Python, Scala

I think Python is a bad language that is hard to use (correctly), should be avoided as a language for teaching new programmers, and should be relegate to simple tasks and shunned for most projects.

Many people at this point would think that I'm an idiot. Who associates Python with hard to use? And avoiding it as a learning language? Isn't that it's primary role today?

Well I think when you get over the glitter that surrounds any dynamic language you'll see the offal such a shiny coating was applied over. A well polished turd, is in fact, still a turd. No matter how much light it reflects.

This animosity exists for not only Python, but Ruby, Perl, PHP, and JavaScript. And I believe with good reason. A non-compiled, late-binding, duck-typed language like Python creates an environment that is harder to develop in by removing your safety nets. And whitespace as part of syntax is just a stupid idea.

The main problem with a non-compiled, late-binding, duck-typed language like Python is that there is no easy way to verify that a particular method or function is being called with the correct parameters and of the correct type. You are not even supplied with if the method returns anything or what type of values it returns. In order to truly verify that your code is going to work, you must have extensive unit tests (which isn't bad in itself), and up-to-date documentation. Two things that a typical program written in Python, which is often considered a fast and dirty language to get things done in, distinctly lack. In addition, in order to truly play it safe with a function, each attribute must be tested for existence due to the lack of types associated with any calling parameters. If a method or function is designed to take an object of type Person, which is a class with a name, age, and gender attributes, there is no way to know outside of runtime if the supplied object will have these properties.

One of those reasons is the reliance on duck-typing. Duck-typing is a type of typing system where "if it looks like a duck, quacks like a duck, it's a duck". So if an object has a name, age, and gender.. then even if it's an object of class Dog, it's still a Person as far as your method is concerned. You can act upon it like you would a Person because the attributes you're using are the same in both objects.

The lack of a compiler is the main detriment of the language. Python claims to come with a compiler which will create compiled python interpretive code in the form of .pyc files when it's run. However, the "compiler" will merely verify that there are no language syntax errors which is an incredibly low bar. If I did the following:

a = "Some string"

Python would compile just fine. When run however, an exception will be thrown because a string does not have a 'functionThatDoesNotExist()" (go figure). This may seem like a natural thing and one might think that avoiding dealing with types directly frees a developer to work on the logic rather than ensuring that the types match up correctly. However, that view would be a reversal of reality. In fact, the developer has to worry more about types in a loosely typed language than in a statically typed language. For safety, each input to a function needs to be checked for the existence of each property that is accessed (and each property of those if there are nested access calls). The developer is now responsible for manually reviewing each changed line of code for what would be compile-time syntax erros in other languages. Simple typos that result in invalid statements can reach production which is not the case in a compiled language.

Refactoring is also a very large problem in Python. If a method needs to be modified to accept a different set of parameters or if the name needs to be changed to reflect it's usage more accurately, finding all of the users of that method is a terrible ordeal. A developer is relegated to using grep to search for a string on the name of the method itself! If there are more than one function with the same method name, you now need to manually verify that you only change the correct one. Since some of these usages could be on objects passed in to methods that have no types attached, there could be no way of knowing which type of object a function is accepting and which instances need to be modified for a refactoring and which do not. Unacceptable.

So I propose that languages like Python actually reduce developer productivity by hoisting off tasks that could have easily been accomplished by a compiler onto the developer in a manual and error-prone process. The speed increase by utilizing duck typing is more than negated by these concerns. Further, it has been shown that a strongly-typed, statically compiled language like Scala can still reap many of the benefits of a language like Python such as function passing while still retaining the safety of compile-time type checking.

In essence, I would recommend a strongly-typed compiled language such as Scala for both learning and production usage over a dynamic, duck-typed, interpreted language such as Python.

Ok, now for some quick rants!

Whitespace as part of your syntax? Come on! Now we have to agree on tabs vs spaces and how many spaces we use for standard indent as part of our syntax? Not to mention there are tools such as Review Board that (rightfully so in my opinion), ignore white-space only changes as not being a significant syntax change. Are we children that we can't just indent our code properly on our own without being shackled by syntactically significant tabs and spaces?

Oh and not being able to do Threading is stupid. The GIL is dumb. Use a real language that can do concurrency.

And no such thing as private variables? Everything public all the time? Why bother calling yourself an object-oriented language if you can't even handle real encapsulation?

Ok, rant over. Back to coding in Python. sigh


comments powered by Disqus