David Jeske
Posts: 1
Nickname: jeske
Registered: Aug, 2003
|
|
Re: Static and Dynamic Languages
|
Posted: Aug 3, 2003 12:06 PM
|
|
I have written on and worked on large programs writtin in static (C/C++/Java), dynamic (Python), and smaller programs written in quasi-dynamic (Objective-C) environments.
I find that the biggest reason I prefer to write some larger software in statically (or declarative) type systems, is the type documentation.
It is very easy to keep every nuance of the typing of a small script in my head. However, when the application grows to a certain number of type patterns, it is hard to remember what concrete type is sitting in the variable I'm working with, or in the hashtable I was just passed, or in the list I just got back from the hashtable. I say "number of type patterns", becuase I have found that reducing the number of object types which pass between files is an effective way to reduce this mental working-set when developing larger software in dynamically typed languages.
You can see this technique in the Python standard libraries, where they choose to use basic datatypes as arguments and return values (i.e. string, list of strings) rather than construct more specific types as is done in Java or C++ (Urls, BufferedString, byte[], etc). Bill Venners commented about the Python API being "somehow designed such that using them also usually requires minimal coding", and I think this is a large part of why he made this statement.
In fact, I agree with Bill wholeheartedly when he asserts that many of the reasons Python is pleasant to develop for are not because of typing, but because of the economy and expressiveness of it's constructs. To his list I would also add the effects of the Python import and scoping semantics. In Python, one imports the module which is the starting point for work. The use of the initial module entry point is still fully qualified with that module name, conveying to the reader the 'start point'. However, any return values which come back can be used directly without additional imports. This provides a clarity and utility to the usage of dependent modules. Java/C# on the other hand, create an import chain-reaction. One has to import not only the module which is called, but every module which declares a type which is returned by that module, and then every module which declares a type returned by that return type, and so on through the functionality accessed from each class type. This is terribly inconvinent, and muddies the entire meaning of the import.
I appreciate developing in dynamic typed languages most when I need to build several complex data relationships inside a function, just to produce a simple result. For example, taking lists of items and building a few hashes, or hashes of hashes, which are all temporarily created for the purpose of providing the same items back in a different order. In Java, Generic Java, or C++, the number of characters in my source code just to declare, allocate, and iterate over these temporary sets of basic datatypes is often larger than the number of characters to perform the re-organization algorithm itself. In Python, the datastructures and manipulation are concise and small, letting the algorithm shine through.
Returning to the benefits of type-declaration documentation. It is convinent when all types used are visible when looking at code. In fact, Java's import system again fails here as a non-fully qualified type declaration still requires hunting to track down. Type-aware completion (i.e. Intellisense) and help systems provided in IDEs are truly amazing, and provide exactly what is needed when it is needed. They are possibly the biggest benefit of using today's static typed languages.
Ironically, understanding available types is not often improved when writing code in systems which make use of type-inference (i.e. ML), because even though the inference system can determine what appears at a type-variable when compliing, it seldom has useful ways to explain that type to the user when editing (i.e. no simple interface names, no types for non-complete programs).
Ultimately, when making a choice I consider the task at hand very central to what type of language is best used. Consider an analogy to sketch drawing. If I want to draw a picture of a scene with trees and flowers, any drawing implements other than the pencil itself mostly get in the way. However, if I am drawing a perspective correct downtown cityscape, the rigid constraints provided by rulers and protractors are a benefit, not a hinderance. The same is true of software systems. If I want the ability to drastically refactor code into another organization, there is nothing so good as my preserved type declarations to help me iterativly work towards the new organization -- while keeping my lines straight.
|
|