Beyond Java - Bruce Tate [35]
Java forces you to work the opposite way: to make things compile, you must deal comprehensively with typing, which involves dominantly finishing issues. Also, many of the compiler errors in Java might not even be problems at all in a dynamically typed language.
Code/Compile Cycle
Dynamic typing comes into play especially when you need to experiment. Remember, you must declare variables in statically typed languages. In Java, that means you need to start each application with a class definition, and it snowballs. You can't just jump in and evaluate a single line of code—the compiler just doesn't have enough information. Instead of just simply evaluating statements, you need to blow out a class, type everything, compile, and execute. In Smalltalk, Lisp, Basic, and Ruby, you can just start typing. For simple experimentation on an initial cut at a Fibonacci sequence, here's the Java version:
class Fib {
public static void main (String args[ ]) {
int x1 = 0;
int x2 = 1;
int total = 1;
for (int i=0; i<10; i++) {
System.out.println(total);
total = x1+x2;
x1 = x2;
x2 = total;
}
}
}
It's 13 lines; 41 words; 226 characters. Keep in mind that Java forces you to declare the class to explore, and that's what we're measuring here. On the command line, you need to save, compile, and run. The Ruby counterpart looks like this:
x1 = 0
x2 = 1
100.times do
puts x2
x1, x2 = x2, x1+x2
end
It's 6 lines; 16 words; 57 characters. Notice how the code just flows better. Read it in English. But the biggest impact is on experimentation. You just type and go. You can cut and paste right on the console screen. You'll use command retrieval to repeat the lines that you need. And these advantages come into play in IDEs as well. Further, if you need 100 iterations, the Java version breaks because an int is not big enough. Ruby still works fine.
This is a trivial example, and probably not completely fair. After all, the Java version packages up a full class and the Ruby version doesn't need to. But you'll find that as we go on, the examples get more and more compelling, especially for the dynamic, reflective style of programming that leading Java developers seek today.
As you add the Web and other deployment steps, the case for dynamic languages gets more compelling, because you can make changes and immediately see the results, instead of having to compile and deploy, and maybe even bounce your servlet engine. Web-based programming gets very easy. Just make a change, and hit Reload.
From my small forays into Basic (where I made my spending money in high school by writing games) and Smalltalk (where I did marketing demos), I miss the rapid feedback cycle afforded by dynamic typing and an interpreter the most.
Adaptability
If you've been coding in Java for most of your career, you probably don't know that you have to jump through so many hoops just to support static typing, but you do. One of the greatest typing costs comes into play when you refactor. Think of the impact of a simple type change for a member variable. You've got to change the property, the getters and setters, every type cast, and every parameter usage. Dynamically typed languages delay the binding of a type to a variable or a parameter, so you often don't need to make any change at all to support a simple type change. For Smalltalk, for example, you can change a type easily. If the new type supports all of the messages of the old type, you will likely limit the changes to one place in your code.
Generics
The Java architects have traditionally gone to great lengths to ensure type safety, but there's been one particular case that's troubled them. When you take an object from a collection, you need to cast the object:
ArrayList animals = new ArrayList();
animals.add("elephant");
String cat = (String)animals.get(0);
The compiler has just lost the ability to provide compile-time type safety.