views:

79

answers:

3

Imagine two languages which (apart from the type information) do have exactly the same syntax, but one is statically typed while the other one uses dynamic typing. Then, for every program written in the statically typed language, one can derive an equivalent dynamically typed program by removing all type information. As this is not neccessarily possible the other way around, the class of dynamically typed programs thus is strictly larger than the class of statically typed programs. Let's call this dynamically typed programs, for which there is no mapping of variables to types making them statically typed "real dynamically typed programs".

As both language families are definitly turing-complete, we can be sure that for every such real dynamically typed program there exists a statically typed program doing exactly the same thing, but I often read that "experienced programmers are able to write very elegant code in dynamically typed languages". I thus ask myself: Are there any good examples of real dynamically typed programs, for which any equivalent statically typed programm clearly is much more complex / much less "elegant" (whatever that may mean)?

Do you know of any such examples?

A: 
  1. Groovy and XML
  2. Groovy and Domain-specific language
amra
It seems to me like this is a great deal of advertising the groovy language, but I indeed found 2 arguments for dynamic typing in there:1. DSLIt seems many dynamically typed languages also have a very flexible syntax catering for the creation of DSLs with a very high information-to-structure ratio. However, with many features listed (like the omission of semicolons, braces, etc.), I do not see any reason why this should not be possible in a statically typed language.
2501
The argument thus boils down to the well known "less typing, because no type information is needed"-argument. In fact, there are statically-typed languages (like scala) using type inference to reduce the amount of redundant type information in their syntax and claim to be very well-suited for creating DSLs as well - I myself have not used scala in this way. Does anyone have experience with this sort of thing? Is there any notable benefit when creating a DSL in a dynamically-typed language?
2501
2. dynamic methodsThe XMLSlurper framework mentioned in this article seems to dynamically add methods to XML-elements allowing the access of subelements of that name. For instance the method Element.age() is automatically created if the element in question has a subelement named "age". This definitly would not be possible in a statically-typed setting, as it is impossible to typecheck a method-call whose name is not known at compilation time.Now the interesting question is:
2501
What benefit is derivable from dynamically-added methods apart from saving some keystrokes when typing person.age instead of person.subNode("age")?
2501
Yes, the main benefit is reduced amount of code and its higher readability. For (dis)advantages just search on this server 'dynamic language advantage'. It just depends what you need to achieve. When you use groovy you will have less code and you need more Unit test. Here is one nice presentation about groovy experience: http://darkviews.blogspot.com/2008/06/jazoon-one-year-of-groovy.html
amra
+1  A: 

Yes, check out Eric Raymonds Python Success Story. Basically, it is about how much easier reflection-type tasks are with dynamically typed programming languages.

Daren Thomas
Correct - but that is because reflection-type tasks are so ill-understood that there are currently no good ways to deal with them in a typed setting. Which is great, lots of fodder for my own research.
Jacques Carette
thank you for your answer. This is a really nice story and strongly resembles by experiences when learning ruby, but it does not mention dynamic typing even once. Eric Raymond just states that Phython in his opignion is of a much cleaner design than Perl or Tcl, but he does not mention any specific language features. Thus, the only way to make this text an adequate answer for our question is to claim that a clean language design is only possible in dynamically typed languages.
2501
Keeping in mind that, in our case, the dynamic/static typing is the only difference between our two languages, any other language feature (like a clean design) would apply to both of them.Eric Raymond uses reflection in his last example, but I do not see any reason why this should not be possible in a statically typed language. If that is your point, could you be more specific about this, please?
2501
I guess, once you start creating types on the fly (like `Reflection.Emit`) and using them in a statically typed language, you're not really using a statically typed language anymore, since the types cannot be known at compile time. But I'm going to give up arguing here, since I obviously don't know enough about what I'm talking about ;)
Daren Thomas
+1  A: 

I am sure that for many "elegance" problems of static languages, static type checking itself isn't to blame, but the lack of expressiveness of the static type system implemented in the language and the limited capabilities of the compiler. If this is done "righter" (like in Haskell for example), then suddenly the programs turn out to be terse, elegant .. and safer that their dynamic counterpart.

Here's an illustration (C++ specific, sorry): C++ is so powerful, that it implements a metalanguage with it's template class system. But still, a very simple function is hard to declare:

template<class X,class Y>
? max(X x, Y y)

There is an astounding amount of possible solutions, like ?=boost::variant<X,Y> or computing ?=is_convertible(X,Y)?(X:is_convertible(Y,X):Y:error), none of them really satisfiying.

But now imagine a preprocessor, that could transform an input program into it's equivalent continuation passing style form, where each continuation is a callable object which accepts all possible argument types. A CPS version of max would look like this:

template<class X, class Y, class C>
void cps_max(X x, Y y, C cont) // cont is a object which can be called with X or Y
{
 if (x>y) cont(x); else cont(y); 
}

The problem is gone, max calls a continuation which accepts X or Y. So, there is a solution for max with static type checking, but we can't express max in it's non-CPS form, untransform(cps_max) is undefined, so to speak. So,we have some argument that max can be done right, but we don't have the means to do so. This is lack of expressiveness.

Update for 2501: Assume there are some unrelated types X and Y and there is a bool operator<(X,Y). What shouldmax(X,Y) return? Let us further assume, that X and Y both have a member function foo();. How could we make it possible to write:

void f(X x, Y y) {
    max(X,Y).foo();
}

returning either X or Y and invoking foo() on the result is no problem for a dynamic language, but close to impossible for most static languages. However, we can have the intended functionality by rewriting f() to use cps_max:

struct call_foo { template<class T> void operator(const T &t) const { t.foo(); } };

void f(X x, Y y) {
 cps_max(x,y,call_foo());
}

So this can't be a problem for static type checking, but it looks very ugly and does not scale well beyond simple examples. So what is missing from this static language that we can not provide a static and readable solution.

Luther Blissett
I have to admit I do not fully understand your point (that may be due to me not knowing C++'s boost:variant, or is_convertible functions). What exactly is the benefit of having to statically check the parameter-type of the Continuation C instead of having to statically check the return-type of the function max? Is C++ really able to deal with continuations (I know this only from functional languages)?
2501
@2501: Updated for you
Luther Blissett