Are Dynamically Typed Languages The Next Big Thing?
by Zef Hemel- Published:October 4th, 2004
- Comments:15 Comments
- Category:General
I’ve been thinking for months about dynamically typed languages (languages like Perl, Python and PHP) and how they compare to the traditional statically typed languages (such as C, C++, Java and C#). In a way you get the feeling dynamically typed languages are so much more simple and productive than the statically typed ones, on the other hand you see their problem: tooling.
First I’ll define what dynamically typed languages and statically typed languages are. Statically typed languages are languages that that force you to explicitly state the (return) types of your variables, functions and parameters. For example, like in C:
int mult(int a, int b) {
return a * b;
}
With dynamic languages, on the other hand, you don’t have to define types at all. The same piece of code in Python would look like this:
def mutl(a, b): return a * b;
The good
What’s clear is that with dynamic languages you have to write less code. Also, because of their dynamic nature, some typing problems static languages have are non-existant. For example, if you try to use a hashtable within a hashtable (a double-layered hashtable). In C# 1.0 that would look something like this:
Hashtable ht = new Hashtable(); ht["something"] = new Hashtable(); ((Hashtable)ht["something"])["someObj"] = new SomeObj(); ((SomeObj)((Hashtable)ht["something"])["someObj"]).SomeMethod();
Now, let’s do the same thing in Python:
ht = {}
ht["something"] = {}
ht["something"]["someObj"] = SomeObj()
ht["something"]["someObj"].SomeMethod();
Sure, you would say generics would solve this problem. But initially it just stacks up on the typing. In C# 2.0 the same code would look like this:
Hashtable> ht = new Hashtable >(); ht["something"] = new Hashtable (); ht["something"]["someObj"] = new SomeObj(); ht["something"]["someObj"].SomeMethod();
It’s easier to read than the C# 1.0 code, but admit it, it ain’t as pretty as the Python version.
If you wonder if you’d ever need a double-layered hashtable, yes, in a project I did last year we needed one. And yes, we used the C# 1.0 code I showed you. Not a pretty sight.
So, obviously, dynamically typed languages won’t let you deal with complex typing stuff. One tradeoff is speed. Usually code can be more optimized if it knows the variable types in advance. The good thing is that the code you write is simpler, it’s closer to what your pseudo code algorithm would look like. There’s less “formality” to deal with, less coding overhead. Personally I think this is the direction in which programming language should develop. We started out writing bits, then “abstracted” that to assembly code, on to C, C++ and other 3GLs (3rd Generation Languages). In a way I think dynamically typed languages feel right, they seem to be a logical next step, the fourth generation of programming languages.
So, are dynamically typed languages really the next big thing?
My problem with dynamically typed languages
If all we’d use were plain text editors to write our code, I’d definately answer that with a firm “Yes”. However, good developers do not use simple text editors to write their code. They use IDEs like Visual Studio and Eclipse. These tools not only colour highlight your code, but often can assist you in many other ways. Two important ones are code completion and refactoring.
Code completion works as follows. In Eclipse, you start writing some code:
void doSomething(ArrayList ar) {
The IDE will now know that when I’m talking about ar within the scope of this method, I mean an ArrayList. So, when I would now type:
ar.
The IDE will know what could follow after that, and a list of methods and fields would pop up. The IDE can do this because it knows the type of ar. However, now let’s try to do the same thing in Python:
def doSomething(ar):
what would an IDE know about ar? Nothing. Nothing useful at all. If we’d be at runtime, we’d know, but we’re not. People don’t develop at runtime. Some dynamically typed languages have an interactive shell, like Python, where this information could be supplied, but again, you don’t develop your applications in an interactive shell. So, code completion like IDEs like Eclipse and Visual Studio does is per definition impossible with dynamically typed languages like Python. Some Python IDEs try to guess the type, for example by reading other code to see what kind of values are assigned to it, but this doesn’t work well in many occasions and it can never be fully accurate.
Same goes for refactoring. One refactoring I use a lot is renaming a method. Let’s look at this piece of Java code:
class SomeClass {
public void DoIt() {
// ...
}
}
class Caller {
public void call(SomeClass d) {
d.DoIt();
}
}
Now, when I ask Eclipse to rename the method DoIt to DoItNow it will, beside renaming the method, also find all occurences of that method being called on an object of the type SomeClass. So the resulting code would be:
class SomeClass {
public void DoItNow() {
// ...
}
}
class Caller {
public void call(SomeClass d) {
d.DoItNow();
}
}
Now, let’s see why this won’t work in Python:
class SomeClass: def DoIt(self): pass def call(d): d.DoIt()
If I want to rename the method DoIt of the SomeClass class to DoItNow, do I have to change the call in the call function aswell? You can’t possibly tell. I’m not sure what type d is of, it could be SomeOtherClass with a method with the same name.
Another difference between the interpreters/compilers of dynamically typed languages and statically typed languages are the errors they detect on “compile” time (or in case of interpreters, before something gets actually run). A compiler like Java’s or C#’s will immediately detect errors like not defined variables, wrong values assigned to variables, non-existant methods called on objects and many other things. However, all a dynamically typed language “compiler” can do is see if the code is syntactically correct. None of the things mentioned can be checked because of the language’s dynamic nature. These problems only pop-up at runtime. So a way to find them is doing whitebox testing, which basically involves testing every possible path through your code. In a perfect world you’d do such testing anyway, but in real world applications it’s too much work.
Some people argue that you’d never be able to check everything on compile time anyway, so why not just move everything to runtime, when you’re for certain. It’s true that you can’t check everything upfront, but I think that the more errors you detect as quickly as possible, the better. When I hit save in Eclipse my code is compiled. When those errors pop-up they’re easier to fix then when I just start running my code and wait for it to crash.
Conclusion
Sigh. All my life I hoped to find the ideal kind of language for everything. But once again it shows that such a thing does not exist. If we’d use dynamically typed languages, we’d be able to produce code faster, as we have to type less. But by doing that we’d also abbandon the opportunities statically typed languages offered, such as automated refactoring and perfect code completion. Not having to switch to documentation all the time, to see which objects had what methods, saved so much time and allowed your brain to be used for something else than holding all the classes and their methods. But with dynamically typed languages we would be back to that, in that respect it’s a step backward. But in many projects this won’t be a concern, particulary in scripting. If you quickly want something done, want to parse a file do something with it, it’s far more convenient to use a language like Python or Perl.
Another application for dynamically typed languages could be teaching. In the beginning it’s important to primarily focus on what your program should do and how it should do it. That’s why people pick pascal over C. Pascal helps you detect errors (for example array index out of bounds errors) and doesn’t let you use pointers as much as C. Using Python would simplify it a bit more. You no longer have to be aware of typing issues, those are things that you will learn to deal with later, let’s first focus on the fundamentals.


15 Commenti
I (and many other people) would argue that there are much better IDE’s for value/dynamically typed languages then for variable/static type languages.
See http://www.cincomsmalltalk.com/blog/blogView?showComments=true&entry=3274170251 for example.
Reading your post I could not help but think that smaltalk would give you everything you want and more.
Btw. since when are statically typed languages traditional? Lisp and Fortran (both the first of their family) where only separated 1 year from each others release. Both systems share a long common history and static languages tend to ”borrow” more and more from the dynamic languages then vise-versa.
I find static typed languages easier to maintain (espacially when reading code of someone else with not so much comment), they do optimize better, and ARE faster.
I agree with Bas. I like static typed languages better. Java programming in Eclipse works extremely smooth because of the arguments you mentioned.
One advantage to dynamically typed languages you seem to have missed is something Ruby (which I’m most familiar with) calls Duck Typing. To cite the Pickaxe II [1]:
“In Ruby, the class is never (OK, almost never) the type. Instead, the type of an object is defined more by what that object can do. In Ruby, we call this duck typing. If an object walks like a duck and talks like a duck, then the interpreter is happy to treat it as if it were a duck.”
Which brings us to the advantage of this: say you first designed a function to work on a string, but later on find out (when your system grows bigger) that this causes performance issues, you could easily give it, for instance, an array and as long as the array supports the same functions you use for the string, you won’t have to change anything except the call to the function.
When you would want to do this on a statically typed language, much more refactoring would be involved.
And error-detection up-front (compile-time) is largely overrated. Before generics, people have been stuffing objects into hashtables and the like, and cast them later to what they really were. Yet, a lot of programmers never see any exceptions occurring there. Why? Because nobody even thinks about stuffing Duck in a hashtable called list_of_swans.
And things like checking for typos… in dynamically typed languages that’s something unit testing helps you with, instead of a compiler. But that’s ok, since you should implement those anyhow
[1]: Which is what Ruby programmers call the “Pragmatic Programmers Ruby book”:http://pragprog.com
Dynamic does not have to be slow!
What they mean is that compiled code is faster then interpreted code. Dynamic of static does not change that or influence that. Interpreted Lisp is slower then compiled Lisp. Compiled Lisp is as fast as compiled C. Interpreted Java bytecode is slower then compiled C, and both are static typed.
When we would ever have a situation that would ever require different stuff like ducktaping, than we would use Interfaces with dynamic languages.
The issue with dynamic languages too is that they tend to give you ‘well.. it is dynamic, it will work out fine’-aditude.
Therefor I prefer (espacially when working on a library) to create my own strong typed hashtable, wrapping a hashtable in a strong typed class…
This may seem to be a performance issue, but it ain’t (I am very lucky with c# utilizing inline functions :))
The common used dynamic languages are not compiled to assembly, though the most used static language (still c++) does compile to assembly.. guess which one of those is quicker.
I do program dynamic languages (php, python), and I do like them at their dynamic nature, but I find it real hell to find out how to do something, where to find a function, how that code works, etc.. etc..
Adding the inconsistency of the use of upper cases, and lower cases in python, it really does make it suck.
Usually you don’t need dynamic languages, for static languages will do their job just as good, and way more maintainable.
However, I really like playing with the dynamic stuff in Python
One of the main avantages (to me) of dynamic languages like lisp and smalltalk is that you get to redefine the language: if you need a new concept then you can just add it and use it and it feels like every other part of the language.
http://www.artima.com/weblogs/viewpost.jsp?thread=4639
- Robert C. Martin misses dynamically typed languages being back in Java-land.
I agree completely on the author’s complains about what he doesn’t like about dinamically typed languages. The real problem is programming something big with them (I know, slash is written in Perl… so what, I’m not a masochist). If typing errors only show up the moment they are executing it takes away gobs of time. I am heavily geared towards C++, when it compiles you know for sure that only ‘runtime’ errors in the classic sense, can occur. That frees my brain from expecting stupid errors too that force me to correct a typo and the re-run the whole thing again. When I learned Perl it drove me mad that only when the control passed over the wrong line I saw the error, and then it was late. Depending on the type of application, if it needs 5 or 15 minutes to gather data (say from the Net), and properly initialize itself, and you can’t cache that, it can kill your productivity. I strongly feel that some people jump into the problem right away and then when the design mistakes they made show up they say they need dynamic typing. Rather I’d design my application and classes well and never need dynamic typing. Does anyone care to show me one single case of needing dynamic typing and it not be a case of bad design choices from the start?
Personally, I would prefer a language that gives the programmer a choice. The first ‘programming’-language I learned was PHP (which has dynamic typing). When I started on C++ it took some getting used to the static typing and on occasion, I really hated it because it is so inflexible. But when I went back to PHP (I used it for a while) I kind of missed the ‘elegancy’ sometimes.
So what I would really like, is to have a choice. Sort of like a static typed programming language with a ‘wildcard’ of sorts. This way you could have the benefits from both approaches.
But there is probably something obvious I’m not seeing that prevents this from being implemented in new languages.
Well, Jordi, it’s easier to build one or the other as opposed to both. For a long time, I worked on a programming language called Paradox. And the original idea for Paradox (I just call it PX) was it was completely dynamic. Then I added the ability to declare types so I could give the choice you speak of. A variable could be declared an int and be stuck as an int for the rest of the scope. But you could declare a variable by saying “x=5″ if x is undeclared like any other dynamically typed language. Then I change it again so you had to declare like “variant x” which took any types. I also made a “scalar” type which stored any int, float, or string. And int, float, string, complex, etc could all be declared. And the problem is when you have a variant type, you have to a lot of checking. For example, let’s say we have a variant called v set to the integer value 99. Then the expression (v + ” bottles”) requires looking at both types in the operation during runtime and determine which version of + to use (string’s or int’s). So while you can get the look and feel of a static language, it still ran like a dynamic language. It’s not a language you would want to use if you want to use purely static code because it was still real slow for a static language. Then I created another version of PX that was entirely static. The speed increase was phenominal but i lost the variant type. I really want to go back to having a “static” language with a variant type and I might, but I would need to find a way to seriously improve it. (I thought of some ideas while writing this so maybe I’ll take a look at it tonight).
It seems to me that if you were writing a static typed language and you would want a variant type, it would indeed take a lot of extra checking. But if you are writing a dynamic typed language, you would already have to check which ‘+’ to use in your example. So to me it doesn’t seem that hard to incorporate the static types into something like that.
But hey, I basically have no idea what I’m talking about, because I don’t even have the slightest clue about how you would write a programming language in the first place? I don’t suppose there are any good tutorials for this?
No, Jordi, you’re making a good point. The problem was mostly me: I’m stubborn. I wanted a nice types API so whenever the virtual machine was told to add two operands, it found a way regardless of either of their types. Even adding two int variables required type checking and then a function call to the correct type’s add function. So like I said before, even though my language looked static and enforced types when it could, it was still a dynamic language behind the scenes and I didn’t want that. Now, I’ve given in to what needs to be done. There is no longer just 1 add instruction. There is 1 add instruction for each basic type (4 basic types in all, maybe a 5th later) and then there will be a seperate instruction for adding when a variant is involved. This has eliminated all type checking and function calls for the 4 basic add instructions and then i can do the type checking required when a variant is involved.
As to your question as to whether there’s a tutorial on writing programming languages, the answer is not really. The tutorial I started out with and later built the original PX interpreter off of was a chapter in a C++ book that taught you how to parse and evaulate string expressions like “(4 * (7 - (21 % 5))”. It only took ineteger expressions and supported 1 letter variables but it was a good start. There should tutorials and code for that sort of thing and if you want to build a language off of that, that’s a good way to go.