Sunday, March 25, 2007

Dynamic Language Weenies?

I saw the linked article and couldn't help but get irritated. I know I shouldn't get this worked up about programming languages, but I did anyway. (Perhaps it was the unnecessarily abrasive tone of the author....) Rather than making you wade through the rather misinformed article, let me summarize and refute some of the author's main points here.


[Edit 3/31/07 @11:58pm - It looks like some of the points I complain about in this article have been changed in the original post. I haven't gone over the article line-by-line, but the article I am responding to was posted on 3/25/07, while the one currently posted is dated 3/26/07, so please take that into account when reading this (3/25/07) article. Some of the main points that were changed in the original post had to do with the use of the confusing terms "weak" and "strong" typing. There may be others.]

[Edit 4/5/07 @5:55pm - I should make it clear that when I refer to "static languages" in the article below, I do so in the same sense that the original author refers to "static languages" -- languages in the style of C, C++, Java, C#, Pascal, etc. I am aware of statically languages such as Haskell and ML which convey many of the productivity benefits of "dynamic" languages in a statically typed environment. ]

Brief aside #1: Non-weenie credentials

I have worked as a commercial hardware and software developer in Real Jobs now for about 15 years. I have used, in production scenarios, C, C++, C#, Dynamic C (embedded programming), VHDL, Verilog, SQL, Javascript, and Python. I have written embedded microcontroller programs, C compilers targeting FPGAs and exotic dataflow (MONARCH) architectures, multiprocessor simulators, enterprise workflow applications, and high-volume web sites. I have implemented digital logic for the StarCore SC140s DSP core, as well as designed various IP digital logic cores, including a Viterbi decoder and an SHA-1 hashing engine. I am not a weenie.

Somewhat less brief aside #2: Muddled thinking about typing

Next, and this gets me every time, the author confuses the (at least) three axes of typing. The first axis is the strong/weak axis, and generally puts languages such as C, perl and rexx on the weak end and most everything else on the strong end. The deciding question here is whether the language implicitly converts unrelated types without warning, allowing you to add the integer 0 to the string "10" and arrive at the result "010" (or is it 11? I forget.). Strongly typed languages will cry foul, where weakly typed will simply do what they think you mean and continue.

The second axis is static versus dynamic typing [Edit 4/3/07], also known as early versus late binding. This has entirely to do with how names (variables) are resolved in the language. In statically typed languages, a name (variable) is associated with a type, and that name (variable) can never reference a value of any other type. In dynamically typed languages, a name may be associated with values of different types over its lifetime. Languages such as C/C++, Java, Pascal, Haskell, OCAML, etc. fall into the static category (with some dynamic capabilities in C++ and Java through runtime dynamic type casting), while languages such as Ruby, Python, etc. fall into the dynamic category. Many languages have support for both, including Lisp and the aforementioned Java and C++.

The third axis is manifest versus implicit typing, and it is a fascinating axis. (Note that this axis is really only applicable to statically typed languages, so it might not really even be an axis in its own right, but I think it's worth looking at here.) Implicitly typed languages such as OCAML, although they are most definitely statically typed and compiled, actually perform quite advanced type inference on the code to determine what types you intended your variables to be, generally by analyzing which operations they participate in. Remarkably, an OCAML compiler is able to produce extremely optimized, statically and strongly typed code, even in the absence of explicit type declarations. RPython (part of the PyPy project) is example of an implicitly typed subset of Python whose compiler is able to produce highly optimized, statically typed code.

The author of the "weenies" article conflates all three axes into strong versus weak, and puts C/C++ and Java on the "strong" side, with Ruby, Python, etc. on the "weak" side, while ignoring other languages such as Haskell, LISP, OCAML, etc. Which hopefully you can see is a gross oversimplification. If you're interested, my current language of choice, Python, is a strongly, dynamically typed language.

Aside #3: Ignorance of other strong advantages of dynamic languages

The author left out what I consider to be two of the most important features, productivity-wise, of my current chosen language, Python: built-in polymorphic containers and high-order functions. (These are also present in most dynamic languages, but I'll discuss them in the context of Python, because that's what I'm familiar with.)

Built-in polymorphic containers

Python has, built into the language, the following containers: lists, tuples, dictionaries ('dicts'), and strings. And when I say that they are built-in, I mean not merely that the language includes facilities to manipulate the structures, but that it also includes a convenient literal syntax to define them. A list of the integers from 1 to 10, for instance, is represented as [1,2,3,4,5,6,7,8,9,10]. Lists have methods that mimic the union of arrays and linked lists in other languages, and even support recursive definition (not that I've used it):

>>> lst = [1,2,3]

>>> lst.append(lst)

>>> lst

[1,2,3,[...]]

>>> lst[3]

[1,2,3,[...]]

>>> lst[3][3]

[1,2,3,[...]]

Tuples are similar to "immutable lists", and are often used to return multiple values from a function:

a,b,c = foo(d,e,f)

This also illustrates a corrolary property of tuples and lists, the "destructuring assignment", that allows you to "unpack" structured data in a very succinct way.

Dictionaries are nice syntactic sugar for hashtables, and allow you to use any "hashable" object as a key to index any Python object: {1:'foo', 2:'bar', 'the third item':'baz', (1,2):'baff'} This also illustrates that all these containers are polymorphic (though in practice the types in a container are usually restricted). Strings need little explanation, except to say that they are built in, unlike C/C++ strings.

Why do all these types make things easier? Mainly because they're already included. To use a list in C++, you have to #include the right header and declare the type of things that go in the list. To use a vector in C++, you also have to #include the right header (a different header, if I remember correctly) and declare the type of things that go in the vector. And good luck if you want to use a hash table. For that, you not only have to #include the header and declare the types of key and object, but you also have to provide a hashing function. Wouldn't it be nice if the language took care of all that for you? (Yes, it is very nice.) If you're using C++, you're also stuck with no literal syntax for specifying anything but the simplest structures, and the enormous pitfall of confusing STL string<>s with char[]s. Dynamic languages (like Python) so significantly lower the bar on creating data structures that you'll often see lists of dicts or tuples where C++ or Java would be littered with utility classes, type declarations (and in pre-generics Java, typecasts). I mean, come on -- do I really need to declare a pair class if I want a list of points? And a separate RGB class if I want color values? Give me a break.

High-order functions

Simply put, this is the ability to treat a function as an object in your code, and the utility of this feature is difficult to overstate. C++ really tries to do this with templates, and Boost::Lambda gets 95% of the way there, but wouldn't it be nice if you didn't have to jump through so many hoops? Python includes features such as map (apply a function to every element in a container), reduce (apply a 2-argument function to every pair of elements in a container until it's reduced to one element), filter (find all elements in a container for which a predicate function returns true), and lambda (define an anonymous function inline). C++ has support for these, but you have to create a functor object (which Boost::Lambda makes mercifully simpler). Actual C++ functions are thus second-class citizens. If you are a C++ or Java language programmer, it may never have occurred to you to write a function that takes a function as a parameter and returns a function as its result. If you are a dynamic language programmer, you probably wrote three of these last week. It's higher-order thinking, and it's simply not supported as well in most static languages.

I should probably pause for a moment and make the point that the C++ templating system is a Turing-complete, dynamically typed, functional programming language that happens to be interpreted at compile time. (I have a compile-time factorial program that I can show you if you don't believe me.) Its syntax leaves much to be desired, but it's semantically much closer to the dynamic language camp than the language onto which it was bolted on, C++.

OK, on to the author's main points, which he presents in a claim/reality format:


Claim: Weak Typing, Interpretation and Reduced Code Volume Increase Development Speed

Reality: No they don't, either individually or together. ....

My reality check: Dynamic typing, interpretation, and reduced code volume do indeed increase development speed.

Dynamic Typing

Have you ever tried to write a really static C++ program? You know, where you actually declare all the methods that don't modify your class as "const" methods? I tried it. Once. Might have tried it again if I didn't have to work with other people. Dynamically typed languages do increase development speed, although their impact is somewhat mitigated in larger projects where enforcement of interfaces becomes more important. Where they really shine, however, is in their "genericity." C++ tried to do generics with templates, and it succeeded to some extent. I'm sure there are other examples in other languages. Dynamic languages give you what are essentially C++ templated functions for every function you write.

Interpretation

Interpretation helps, not so much because compile time is prohibitive in static projects, but because the REPL (read-eval-print loop) is so freaking easy. Want to try out something quickly? Paste it into your interactive shell. Static languages are beginning to understand this, with some IDEs providing a little interactive shell. But how long did it take to "invent" this feature (which was present in Lisp in the 1960s)? Interpretation also facilitates the exploration of new language features in a way that statically compiled languages have a really hard time keeping up with. Take it from someone who has written both interpreters and compilers: it is easier to add a feature to an interpreter than it is to a compiler. OCAML does some amazing things in their compiler. You're going to have a hard time convincing me they can extend the language easier than the PyPy team, however.

Reduced Code Volume

Reduced code volume certainly does reduce development time trivially -- less typing. More importantly, however, it allows you to fit larger concepts onto one screenful of code. The units at which you are programming are larger. Also important to note is the correlation of bug count with source lines of code, independent of language used. That means that, roughly, 1000 lines of assembly has the same bug count as 1000 lines of Lisp. Which one do you think accomplishes more? Reduced code volume is easier and faster to code, debug, and maintain. I can't understand how the author could even imagine this not to be true.


Claim: Support From Major Companies Legitimizes DLs

Reality: No it doesn't. Companies know that fan boys like you are easy marks - an enthusiastic and indiscriminate market segment ripe for exploitation. They also know that you might spread your naive enthusiasms into your workplaces, opening up a corporate market for supporting tools.

My reality check: OK, fine. Companies are driven by profit, so I can accept that corporate profit chasing has little to do with the quality of a language. But this cuts both ways. Java has been pushed by Sun, and C# by Microsoft. Neither would have anywhere near the market share they currently have without their corporate backers.

But let's leave aside corporations "supporting" the languages. Let's look at those who actually get things done. Yahoo! stores was originally written in Lisp. BitTorrent in Python. Google and NASA use Python extensively. The OLPC project is using Python as their core O/S language. 37signals uses (and invented) Ruby on Rails. Reddit is Python (was Lisp). YouTube runs on Python. And tell me, how many thin-client applications use Java applets (static language) versus Javascript (dynamic language)? And that's even with the hellish problem of browser inconsistency.

Claim: As the Problems Change, People Use New Languages

Reality: As languages change, people remain the same. Software development is now, and always has been, driven by an obsession with novelty, and that is what drives language adoption. If there is a new problem to solve, that will simply make for a convenient excuse. Your misplaced enthusiasm simply perpetuates a cycle of self-defeating behaviour that prevents software development maturing into a true profession.
My reality check: Yes, people remain the same. However, the resources we use do not. CPU cycles and memory are relatively cheap today. That's why no one (except some embedded developers) can get away with saying they need to program in assembly language. Runtime performance is objectively less constraining now than it was 10 years ago for the same problems. Which means that all the things we wish we could have done in 1997 are available now. Like dynamic, interpreted languages.

Language is a tool for expressing ideas. Some languages express different ideas more easily, or with greater difficulty, than others. Try saying ninety-nine in French, if you don't believe me (quatre-vingt-dix-neuf, literally four twenty ten nine). Programming languages are no different. Things have been learned about better ways to express yourself since C++, Java, and C# were invented. C++, Java , and C# also chose to ignore certain things that were well-known in programming language research when they were invented due to design decisions that were made in a technological context dissimilar to today.

And for one further reality check, no, language adoption is not driven by novelty. Java introduced nothing whatsoever that was new. It started with known features of C++, removed a bunch of stuff, added a garbage collector that had been understood since the days of the VAX, and threw an ungodly amount of marketing behind it. Java is no longer new, but it is still widespread. C is certainly not new, and its popularity remains astonishingly high. Language adoption is driven by a wide range of factors, including but by no means dominated by novelty.
Claim: You Can Assess Productivity By Feel

Reality: No you can't. You're just trying to justify personal preference by hiding it behind a legitimate but definitionally complex term. If you've never taken measurements, you have approximately no idea what your productivity is like either with or without your favorite dynamic language. You certainly can't assess the difference between the two.
My reality check: The article's author hasn't taken measurements, either. But Lutz Prechelt at least has some data, where the linked article presents none. In fact, without exception, all studies of which I am aware [Ed: 4/5/07] which have compared productivity in languages between compiled, manifestly, statically typed languages and interpreted, dynamically typed languages have the dynamic languages easily winning out.

But what the author ignores is that the "feel" of a language, while not providing objective evidence of its productivity, is an influencing factor in its productivity due to the increased motivation to work in a dynamic language. If I like how a language "feels", I will use it more. I will be a more motivated employee, producing more. If I do open source work, I will work more on it, producing more libraries and facilitating code reuse, which even the most jaded non-weenie must admit is a Good Thing.

Claim: Syntax Can Be Natural

Reality: All programming languages are arcane and cryptic, in different ways and to varying degrees. What is perceived as "natural" varies tremendously between individuals, depending upon their experience and background. Your mischaracterisation of a syntax as "natural" is just an attempt to retro-fit a philosophy to your personal preferences.

My reality check: No syntax is completely natural, but some have more in common with non-programming languages than others. For instance, Haskell invented a wonderful syntax for specifying lists: the "list comprehension":

[x + 2*x + x/2 | x <- [1,2,3,4]]


OK, that looks weird if you've never seen it before. But does it have an analogue outside of programming? How about

{ x + 2*x + x/2 | x in {1,2,3,4} }

That's just about pure mathematical notation for a set. Python took a compromise approach and writes the more "verbal":

[ x + 2*x + x/2 for x in [1,2,3,4] ]

How do I say this in C++?

#include<list>
std::list<int> mklist() {
std::list<int> l;
for(int x = 1; x<= 4; x++)
l.push_back(x + 2*x + x/2);
return l;
}

Which feels more "natural" to you? I see in programming language design two big threads, of equal power but radically different approach, which I will name by certain scientists who inspired the respective approaches. One is the "Chuch" thread, where languages express mathematics. The other is the "Turing" thread, where languages command machines to accomplish tasks. Roughly, this puts languages into "declarative" and "imperative" camps. Dynamic languages pull ideas from both camps. Static languages (at least C/C++, Java, and C#) are heavily imperative, and have little support for declarative concepts. Sure, neither is particularly "natural," but dynamic languages have more expressive capabilities and can approach a "natural" syntax more easily than manifestly static languages.

Claim: A Strength Of My Language Is Its Community

Reality: If it it[sic], then you are in deep trouble, for your community appears to be dominated by juveniles who only take time out from self-gratification long enough to wipe the byproducts off their keyboard, then mindlessly flame anyone who does not share their adolescent enthusiasms.
My Reality Check: The community is a strength, no doubt about it. But communities are made up of all types. For every blithering idiot, there may be five or ten solid programmers pounding out production-quality code. I had to make a choice tonight -- write this article or work on my application. Maybe I made the wrong choice. Many of the juveniles of which you write don't have that choice, being without the requisite skills to create an application. Of course, that raises the question of what you were doing writing the article....
Claim: No Harm, No Foul

Reality: No Brain, No Pain.

And the dynamic languages people are juvenile?....

30 comments:

  1. The original article was so inaccurate that I can only imagine it was written by somebody religious. I like static typing for its guarantees, and I like dynamic typing for its ease.

    Optional static typing is the way to go, to give us the best of both. I just wish I could figure out how it should look.

    ReplyDelete
  2. Laying aside the religious remark, I agree with your points. LISP has, I believe, provided optional static typing for quite some time now, and Python 3.0 will provide "annotations" on parameters wich could provide some of the guarantees you're looking for.

    You might look into LISP if you can stand the ubiquitous parentheses for inspiration on how optional static typing could look. There is also a Python-like language, Pyrex, which provides essentially optional static typing and compilation, through C, into a binary Python extension module. If you're into python, it's worth checking out.

    ReplyDelete
  3. Anonymous11:40 PM

    VisualFoxPro has optional static typing. The default behavior is dynamic. Static typing was added as an option in version 7 or 8 mainly to support interfaces.

    ReplyDelete
  4. Anonymous7:48 PM

    Technology debates remind me of the proverb, "You can never step in the same river twice." That is, languages change as the different communities learn from each other.

    Dynamic languages are demonstrating to the Java community how BADLY things like EJB were designed. In order to create a new function on my EJB, I have to update about 4 different source files plus maybe an XML file.

    EJB 3.0 comes a lot closer to dynamic languages in this area, where for example in TurboGears (Python) you can expose a new Ajax method from your controller with just a single tag:

    @expose(format='json')
    def myFunction
    ...

    I hope Java learns a lot more lessons from dynamic languages; competition is good for everyone. I've given up hope for C++; when I first heard several years ago that the next version of C++ was called 200x because they *thought* they could finish before 2010, I realized that feature-wise, C++ is going nowhere fast. Ten years from now, C++ will still be good at the same things it's good at now, but probably not much else.

    I switched to Python from C++ just two months ago, so both are very fresh in my mind. In addition to Rick's point about being able to define literal arrays and hashes very easily, I really appreciate the flexible iteration tools available in Python like 'zip' and 'enumerate'. I notice this particularly when writing unit tests, where you are often checking object properties against a set of known results. In C++, if I'm feeling energetic, I'll write a helper function to do this. If not, I'll copy and paste, making for some really bloated test code. In Python, I don't need a helper function because the built-in language idioms are more powerful.

    ReplyDelete
  5. Anonymous11:32 AM

    If I may, I recommend you to write Lisp (not in all caps) like everyone else has done since the 70's :-)

    About typing in Lisp: By default Common Lisp has dynamic typing with run-time checks, so that if I try to add together a number and a string, I get an error message with possible restarts. Here is a sample session from the Clisp interpreter.


    [3]> (+ 3 "a sausage")

    *** - +: "a sausage" is not a number
    The following restarts are available:
    USE-VALUE :R1 You may input a value to be used instead.
    ABORT :R2 ABORT
    Break 1 [4]> :r1
    Use instead: 5
    8
    [5]>


    Note that it allowed me to continue execution after supplying a suitable replacement value.

    The optional type declarations are mostly meant to help the compilers. At the cost of type safety the compiler can create faster code (by omitting type checking) if I promise to call my function with only the appropriate types. If I then later break my promise, I won't get any useful restart options or diagnostics, but most likely an ugly crash.

    A good Lisp compiler does not always require excessive type annotations, because it is possible to infer the types in many cases. But there are always situations where it needs all the help it can get.

    So, to sum up, you have strong and dynamic typing by default in Common Lisp, and you can make it weaker and more static for efficiency's sake at the cost of safety.

    These things can be done with the special forms declare, proclaim and declaim if you want to look for more info.

    It will be interesting to see if this is the direction Python will eventually take regarding typing. Of course, Guido's aim is not to make another Common Lisp out of Python, and I'm perfectly sure one is enough ;-)

    ReplyDelete
  6. Anonymous11:50 AM

    CPAN.org is the perfect example that community is important to the use and adoption of a language.

    ReplyDelete
  7. Re: Anonymous

    Point taken about LISP/Lisp spelling -- I can never remember which way is currently accepted, as I don't really do any Lisp right now. But the article now has the "Lisp" spelling, at least.

    I find your point about the dynamic+strong => static+weak change in using Lisp's static type checks intriguing. I think most languages with static type declarations enforce those declarations at compile time (to avoid the ugly crash you mentioned). Of course, the binary code is not type-safe, but the static language compilers can usually guarantee that the correct types will be used. I was not aware that in Lisp, the declarations were merely advisory to the programmer and not compulsory as in, say, Haskell or C++. It sounds like (from my limited experience) the worst of all worlds (weak, manifest, static typing) for the sake of performance. Is this a weakness, perhaps, of mixing static and dynamic typed names together in one program?

    I ask because it seems like Pyrex and ML do something like mixed dynamic/static typing. (I know that ML is statically typed, but sometimes that type is "either A, B, or C".) The more the type inferencer can determine, the faster code can be produced. If the compiler can't guarantee the type of a parameter, however, it will fall back to the "safe" way of executing the code. That seems to me to be a better approach than trusting the programmer to remember all the "promises" made....

    ReplyDelete
  8. Re: Matt M.

    I agree. CPAN, CTAN, PECL, PEAR, PyPI, and RubyGems are other examples. Hard for Sun or Microsoft to keep up with anything like that. And I'm guessing that the open-source nature of all the languages represented by the above repositories attracts programmers who are more interested in sharing their code than your standard Java/C# crowd.

    ReplyDelete
  9. Anonymous1:25 PM

    That isn't a crash. That's a debugger console. Lisp's condition system is far in advance of pretty much anything out there. It was asking if you want to try again with a different value. You could literally continue the program from that point with the new value. You don't need to restart the whole thing.

    You can even recompile code and continue. That's what Lispers mean by dynamic language. Python and Ruby development is primitive by comparison.

    ReplyDelete
  10. I see that the above capture isn't a crash. I was just referring to your statement:

    If I then later break my promise, I won't get any useful restart options or diagnostics, but most likely an ugly crash.

    I have looked into the Lisp condition system enough to be awed by it, but not enough to really use it (or comment on it) in a competent manner. I do realize that there's a big difference in power between Python's exception system and Lisp's condition system.

    Of course, a debugger console is most likely not what you want in deployed code, but it's nice to have the option to find a bug, fix a bug, continue with the test where you left off. I know of no other language with that ability. I really do need to learn Lisp one day....

    ReplyDelete
  11. Anonymous2:56 PM

    Don't mean to criticize but some French use nonante-neuf which is literaly ninety-nine. I'll go back to reading the rest of the article now.

    ReplyDelete
  12. Both "Invasion Of The Dynamic Language Weenies" and your response here are so long that it's difficult to comment without seeming to pick on small things so I'll try to stay with main themes.


    1) Show me the evidence!
    afaict the big theme of "Invasion Of The Dynamic Language Weenies" is simply that extravagant claims are being made without evidence to back them up (aka BS aka Snake Oil). I don't think you addressed that at all.


    2A) Muddled thinking about typing
    The terms we use to describe programming languages are somewhat muddled - different people have their own definitions.

    The author of "Invasion Of The Dynamic Language Weenies" seems to acknowledge that - There is no canonical definition of a Dynamic Language, but some generalizations are possible.

    afaict you don't actually address his description of dynamic languages at all but just list your own distinctions (axes).

    And then you write "The author ... conflates all three axes into strong versus weak".
    No! - the author never mentions strong typing or weak typing.


    2B) Muddled thinking about typing
    Here's what one programming languages textbook says: 'So what is “strong typing”? This appears to be a meaningless phrase, and people often use it in a nonsensical fashion. To some it seems to mean “The language has a type checker”. To others it means “The language is sound” (that is, the type checker and run-time system are related). To most, it seems to just mean, “A language like Pascal, C or Java, related in a way I can’t quite make precise”.

    2C) Muddled thinking about typing
    "The second axis is static versus dynamic typing, also known as early versus late binding."
    Do you think when people say static typing and dynamic typing they might mean static checking and dynamic checking?


    3) selective examples
    "Ignorance of other strong advantages of dynamic languages ... built-in polymorphic containers and high-order functions"
    You also accuse the author of ignoring other languages such as Haskell, ..., OCAML
    Don't static languages like Haskell and OCaml and ... provide built-in polymorphic containers and higher-order functions?

    not so much because compile time is prohibitive in static projects, but because the REPL (read-eval-print loop) is so freaking easy
    Isn't there an OCaml REPL?
    Have you Googled for c repl? Tried cint or ch?


    4) Show me the evidence! (Again)
    The article's author hasn't taken measurements, either. But Lutz Prechelt at least has some data, where the linked article presents none. In fact, without exception, all studies which have compared productivity in languages between compiled, manifestly, statically typed languages and interpreted, dynamically typed langauges have the dynamic languages easily winning out.

    The article's author doesn't need to take measurements to show that the extravagant claims made by others are not supported by evidence - he just needs to show that those others do not provide evidence for their claims. The burden is on the others to show their claims are true.

    The author discusses Prechelt's study.

    Writing "In fact, without exception, all studies ..." is another example of what the author is objecting to - it's an extravagant unsupported claim - show us the reference list of "all studies" so we can check that what you say is correct!

    ReplyDelete
  13. Rick, great article. nice rebuttal, and very informative.

    thanks,
    -Corey

    ----
    www.goldb.org

    ReplyDelete
  14. Anonymous4:38 PM

    I think people get pissed off with the hype surrounding dynamic languages (I know I do) because sometimes it does seem to be driven by 'weenies' (ok, novices) that don't have the experience to evaluate it, and like it purely because its new, cool and allows them to work without discipline (thats not saying everyone uses them to work without discipline..). Of course its not new, e.g. ideas of functions as first class composable concepts is approx 100 years old.

    I think you do Java (yes, its one of my favorites..) a disservice by saying it didn't introduce anything new. The delegating classloader model is something that the VM authors claim was novel for instance. As an aggregation of existing techniques, it also broke new ground - i.e. what they carefully discriminated what to put in, and what to put out, has turned out, even over a decade later, to have been quite astoundingly balanced and preciently cautious.

    The current interest in languages that experiment with typing (python, ruby, kawa, javascript) feels to me like the mini explosion in imperative languages at the start of home computing. None of them seem to have got a good balance so far, they feel more driven by experiment - which is fine as no-one yet has the benefit of hindsight thats necessary.

    I think in summary my message is, give it more time, and ignore the mudslinging.

    ReplyDelete
  15. Anonymous9:42 PM

    Good article. I agree with you mostly but the following myth is Just Plain Wrong (TM)

    Language is a tool for expressing ideas. Some languages express different ideas more easily, or with greater difficulty, than others. Try saying ninety-nine in French, if you don't believe me (quatre-vingt-dix-neuf, literally four twenty ten nine)

    That is the Sapir-Whorf hypothesis which has been quite thoroughly debunked by linguists. See "Language Instinct" by Steven Pinker for details which are explained in lay-terms.

    However, the theory could be valid for programming languages. (A programmer who does not have functional programming is almost never going to think to use them.) But it has been proved that all natural languages are exactly equivalent to each other.

    ReplyDelete
  16. Anonymous10:01 PM

    Another "best of both worlds" language like Groovy is Boo (boo.codehaus.org). It's a CLI language with syntax copied from Python. Variables default to statically typed, but with type inference so you don't have to repeat yourself. You can explicitly declare variables as "duck" typed to get fully dynamic lookup.

    So you get the speed and safety of static typing, with the convenience of type inference, and the convenience of fully dynamic types when that isn't enough, and nice clean Pythonish syntax (only better, because unlike Guido the Boo folks don't have a hate on for anonymous functions and higher-order-programming), and full interop with the enormous suite of .NET libraries.

    ReplyDelete
  17. Re: Isaac

    First off, thanks for your insightful comment. I'll try to respond to each of your points, but due to my sleepiness I probably won't give them the attention they deserve ;-)

    1) Show me the evidence!
    afaict the big theme of "Invasion Of The Dynamic Language Weenies" is simply that extravagant claims are being made without evidence to back them up (aka BS aka Snake Oil). I don't think you addressed that at all.


    I think that the Prechelt study stands as evidence. It may have some flaws which may or may not affect the conclusions of the study, but absent evidence presented from the C/C++/Java camp, it is at least something. And of course, there is the subjective "evidence" of the "converts" to dynamic languages. I think that the original author (on Hacknot) brushed off the Prechelt study much too quickly.

    2A) Muddled thinking about typing
    The terms we use to describe programming languages are somewhat muddled - different people have their own definitions.

    The author of "Invasion Of The Dynamic Language Weenies" seems to acknowledge that - There is no canonical definition of a Dynamic Language, but some generalizations are possible.

    afaict you don't actually address his description of dynamic languages at all but just list your own distinctions (axes).


    Sorry if I wasn't as clear as I'd intended to be. I would describe most dynamic languages as strongly typed, where the Hacknot author would describe them as weakly typed.

    [Actually, I just went back to the original article and it doesn't seem to have any reference to strong/weak typing at all. I could have sworn that the original had "weak" for the current "dynamic", and "strong" for the current "static." If I remember it wrong, or if it's been corrected, you can throw out my typing rants. ;-)]

    That's what I was trying to get at. I also think he missed most of the productivity-enhancing features of dynamic languages over C/C++/C#/Java.

    And then you write "The author ... conflates all three axes into strong versus weak".
    No! - the author never mentions strong typing or weak typing.


    You may be right. I either misread, or the article has changed.

    2B) Muddled thinking about typing
    Here's what one programming languages textbook says: 'So what is “strong typing”? This appears to be a meaningless phrase, and people often use it in a nonsensical fashion. To some it seems to mean “The language has a type checker”. To others it means “The language is sound” (that is, the type checker and run-time system are related). To most, it seems to just mean, “A language like Pascal, C or Java, related in a way I can’t quite make precise”.


    Agreed. That's why I prefer to be a lot more explicit than say "strong/weak." And I may have misread the original article.

    2C) Muddled thinking about typing
    "The second axis is static versus dynamic typing, also known as early versus late binding."
    Do you think when people say static typing and dynamic typing they might mean static checking and dynamic checking?


    They might -- both as kinds of type safety, one check performed before runtime and one at runtime. In the case of Python, what I mean by dynamic typing is that objects have types, names (variables) do not. Names may be re-bound at runtime to objects of any type.

    3) selective examples
    "Ignorance of other strong advantages of dynamic languages ... built-in polymorphic containers and high-order functions"
    You also accuse the author of ignoring other languages such as Haskell, ..., OCAML
    Don't static languages like Haskell and OCaml and ... provide built-in polymorphic containers and higher-order functions?


    Absolutely! I think that these static languages provide development environments that may be significantly more productive, produce higher-performing code, and provide greater assurance of correctness. But my response (and the original article) was really more about comparing static languages of the C/C++/C#/Java type (imperative, no type inferencing, etc.) with dynamic languages of the Ruby/Python type (mainly imperative, no type inferencing, etc.).

    Isn't there an OCaml REPL?
    Have you Googled for c repl? Tried cint or ch?


    I haven't tried cint or ch, and have only fiddling-around experience with OCaml, so I can't comment on these. I know that my REPL in Python (IPython) has great introspection abilities, debugger integration, etc. While I'd expect that from OCaml (since so much of what they do impresses me already), I'd be surprised to find introspection in a C/C++ REPL, simply because the language support isn't there (RTTI doesn't even come close).

    4) Show me the evidence! (Again)
    The article's author doesn't need to take measurements to show that the extravagant claims made by others are not supported by evidence - he just needs to show that those others do not provide evidence for their claims. The burden is on the others to show their claims are true.

    The author discusses Prechelt's study.


    And dismisses it unfairly (IMO) without providing any evidence to counter his conclusions.


    Writing "In fact, without exception, all studies ..." is another example of what the author is objecting to - it's an extravagant unsupported claim - show us the reference list of "all studies" so we can check that what you say is correct!


    OK, that was probably overreaching on my part. What I meant was, "Here, we have this Prechelt study. What do you have? Nothing? Well, I guess that means all the studie(s) (however weak you may hold them or it to be) favor(s) our conclusion." I was basing my argument on the fact that all studies of which I know (Prechelt's) support the dynamic language productivity hypothesis, while I have seen none to refute it. I'll admit that's weak, but it's something.

    Plus on a less persuasive, subjective note, it agrees with the experience of myself and the incredibly unscientific sampling of "people I know who have programmed professionally in both." ;-)

    ReplyDelete
  18. Re: anonymous (on the linguistics issue)

    Good article. I agree with you mostly but the following myth is Just Plain Wrong (TM)

    "Language is a tool for expressing ideas. Some languages express different ideas more easily, or with greater difficulty, than others. Try saying ninety-nine in French, if you don't believe me (quatre-vingt-dix-neuf, literally four twenty ten nine)"

    That is the Sapir-Whorf hypothesis which has been quite thoroughly debunked by linguists. See "Language Instinct" by Steven Pinker for details which are explained in lay-terms.


    Surely linguists are not saying that all languages express all ideas with identical concision and precision, right? I provide a simple counter-example in the French above (and yes, I know some French use the word for ninety). Of course all languages can express the same ideas, but one has only to look at the relative number of words in translations of various works to see that they do not express them all equally succinctly.

    Additionally, glancing over at the Wikipedia entry on Sapir-Whorf, it doesn't appear to be what I'm saying at all. Sapir-Whorf says that language affects the ability of the speaker to formulate ideas, not that it affects his efficiency in expressing them. So I don't think I'm supporting the Sapir-Whorf hypothesis at all with my natural language comment at all. (Though I may tend to agree with it when it comes to programming languages.)

    ReplyDelete
  19. In what way, Perl goes in the weak side of your first strong/weak axis ?

    ReplyDelete
  20. Re: pierre

    I'm not a Perl expert, but I believe that the following confusion can apply to Perl:

    The deciding question here is whether the language implicitly converts unrelated types without warning, allowing you to add the integer 0 to the string "10" and arrive at the result "010" (or is it 11? I forget.).

    But as a previous commenter pointed out, everyone has their own definition of strong/weak, so mine may not apply. IMO, any language that implicitly converts strings and integers is weakly typed because of ambiguities like the above.

    ReplyDelete
  21. Thanks for the quick reply. I believe you would use the '.' operator to do the operation you are talking about. There is no real ambiguity here, is it ?

    ReplyDelete
  22. rick wrote I think that the Prechelt study stands as evidence. It may have some flaws which may or may not affect the conclusions of the study, but absent evidence presented from the C/C++/Java camp, it is at least something.
    You are mistaken - if the Prechelt study has flaws which seriously undermine the conclusions then it's value as evidence disappears. (As-soon-as they discover your $100 bill is fake you lose $100.)


    rick wrote If I remember it wrong, or if it's been corrected, you can throw out my typing rants.
    If you want readers to pay attention to the other points you make, then maybe you should throw out those wrong or out-of-date typing rants.


    rick wrote But my response (and the original article) was really more about comparing static languages of the C/C++/C#/Java type (imperative, no type inferencing, etc.) with dynamic languages of the Ruby/Python type (mainly imperative, no type inferencing, etc.)
    It seems a little strange that you both put forward higher-order functions as a strong advantage of dynamic languages and then characterize dynamic languages as "mainly imperative".

    (And there's a simple answer to this rhetoric - "I mean, come on -- do I really need to declare a pair class if I want a list of points? And a separate RGB class if I want color values? Give me a break" - if you don't need those classes, you can stick with a list of float arrays. But I'm digressing into details so I'll try and get back to a theme.)


    rick wrote I think that the original author (on Hacknot) brushed off the Prechelt study much too quickly. ...
    And dismisses it unfairly (IMO) without providing any evidence to counter his conclusions.

    You are mistaken, the author did provide evidence, the author directed us to "read the paper [Prechelt's] carefully" - read section 3.6 "Validity: Are these programs comparable?" and you will find that Prechelt admits the very problems that the author complains about.

    All the problems admitted by Prechelt gave advantage to the "script" programmers.


    Let suspend disbelief for just a moment, take the results at face value, and use them as evidence for Stephen Deibel's comment "Python would use 10 to 20 percent of the amount of code that Java or C++ would use to write the same application."?
    Prechelt wrote "We see that non-scripts are typically two to three times as long as scripts."
    That's 30 to 50 percent not 10 to 20 percent.


    rick wrote all studies of which I know (Prechelt's) support the dynamic language productivity hypothesis
    Consider this -
    a) we measure how long it takes you to satisfactorily complete a programming task
    b) Joe satisfactorily completes the same task and we ask him how long he took
    Joe says he took 2 hours and we measured that you took 5 hours - is it reasonable to say that Joe is more productive than you?


    Prechelt measured how long the Java,C,C++ programmers took as part of a controlled experiment. He didn't measure how long the Perl,Python,Rexx,Tcl programmers took.

    A year or two after the Java,C,C++ controlled experiment he did a newsgroup request for Perl,Python,Rexx,Tcl programs and asked the programmers how long they took to write the programs.

    Does that really seem like a fair comparison to you?

    ReplyDelete
  23. Re: isaac

    As to the Prechelt study, I think that it contributes a data point that is not completely valueless (as in, equivalent in value to having never been performed, which is what the Hacknot article seems to believe.) It may have some methodological flaws, but without evidence to refute its conclusions, it's the best we've got. I think we understand each other here and just disagree on the value of the study. [Forrest Gump voice] And that's all I have to say about that. [/Forrest Gump voice]

    As to the typing rants, I have put a disclaimer into the top of my article. The Hacknot author did indeed change his essay after I posted my response (at least once), and I don't particularly care to perform diffs every few days to let people know what he previously said. That's the danger to responding to something on the Internet, I suppose.

    It seems a little strange that you both put forward higher-order functions as a strong advantage of dynamic languages and then characterize dynamic languages as "mainly imperative".

    Higher-order functions are a feature of functional programming languages. Declarative programming is a style many or most functional programming languages use. This does not mean that HOFs are always declarative in nature (IMO).

    ReplyDelete
  24. Rick, I think it's telling that you didn't try to answer these questions
    - "is it reasonable to say that Joe is more productive than you?"
    - "Does that really seem like a fair comparison to you?"

    rick wrote I think we understand each other here and just disagree on the value of the study.
    It seems more than that.
    It seems like you chose truthiness.

    ReplyDelete
  25. Rick, I think it's telling that you didn't try to answer these questions

    Just getting tired of a discussion going nowhere, but here goes....

    - "is it reasonable to say that Joe is more productive than you?"

    It's reasonable to say that Joe is likely to be more productive than me (especially if the difference is consistently and strongly tilted in one direction), although I can't make a blanket statement that he is. It is more reasonable given that Joe was asked before completing the task to time himself (so we're not basing the results strictly on his memory). And without any objective evidence that refutes this iffy data, my bias is to accept it, at least in the general sense that scripting language programs tend to be shorter, slower to run, and faster to write than programs written in C, C++ and Java.

    - "Does that really seem like a fair comparison to you?"

    Fair comparison? No, there are a few things that are unfair. One major one is that the scripting languages had an unfair chance to advance in that time period. In fact, due to advances in all the languages studied (I know about some advances in Java and Python and assume there have also been improvements in C/C++, Rexx, and Tcl), the relevance today of the conclusions is questionable. It wasn't a paragon of scientific research, but then again, it's better than the zero studies that refute it. And from my perspective as someone who has achieved some level of mastery in both C++ and Python, and written similar applications in each, the productivity disparity between a competent C++ programmer and Python programmer, whether it be 2-3x improvement or 5-10x improvement (as it obviously would vary by programming task) does not seem extravagant to me.

    In my opinion, take it or leave it, the improvement for dynamic languages will actually increase as projects get larger due to a) smaller team size (more done in less time means fewer coders are needed) leading to b) fewer interfaces, where interfaces between modules tend to increase development time and system complexity in a non-linear way. I would expect the "type safety" advantages of static languages to be mitigated by competently written unit tests which would, in the course of testing for functional bugs, automatically find most typing errors. It is, as I stated at the beginning of this paragraph, an opinion, but it is the opinion of a practitioner in both C++ and Python. Again, take it or leave it. And no, I don't think that this is "truthy," but I am tired of debating the point.

    ReplyDelete
  26. I happened to see the last sentence first, you're tired of debating this - I'll bite my tongue.

    ReplyDelete
  27. Anonymous9:42 PM

    Don't confuse static/dynamic typing with early/late binding. If you are defining static/dynamic typing to mean early and late binding, well, OK, I can't argue with that (although I will disagree the definition). C++ is statically typed, in the sense that the type of all variables are known at compile-time, but is late-bound via virtual methods, so that the method invoked is the one defined by the most derived subclass.

    No virtual keyword: static typing, early binding. Virtual keyword: static typing, late binding.

    ReplyDelete
  28. @andre:

    Thanks for your comment. Of course, you're absolutely right. I was getting muddled myself when complaining about someone else's muddled thinking. ;-) My mental model was correct, but my vocabulary left much to be desired. Static typing is binding a variable name to a particular type, dynamic typing is tying the name only to the object (which likely has a "strong type"), and generally at runtime.

    Late binding is kind of in-between, as you've tied a name to a hierarchy of types. I guess that's why the "safe" way to downcast in C++ is "dynamic_cast". But you're right that it falls into the static language camp.

    ReplyDelete
  29. Anonymous9:37 PM

    Surely linguists are not saying that all languages express all ideas with identical concision and precision, right? I provide a simple counter-example in the French above (and yes, I know some French use the word for ninety). Of course all languages can express the same ideas, but one has only to look at the relative number of words in translations of various works to see that they do not express them all equally succinctly.

    We are in agreement mostly, however ...

    Put a little technically, linguists agree that all natural languages can be expressed with the exact same grammar. Hence, anything expressed in one language is equally easily expressed in other languages (a matter of words more at most).

    Sapir-Whorf (and here we are in agreement) is probably valid for programming languages because the grammars of programming languages are different. And quite significantly. To take an extreme example, consider the Java grammar (which is at least Context-Free) and the instruction-set of some processor (which is not even a grammar but merely a collection of constant strings).

    ReplyDelete
  30. Anonymous10:46 PM

    I enjoy these debates, but part of me doesn't see the point. Is language X better than language Y? The language I happen to use at a given time is the one that--hopefully--will be best suited to the nature of the task at hand, and the constraints that will be imposed on me by the production environment.

    It seems to me that the productivity gain one might experience with one language over another is dependent entirely on the nature of the problem. If I need to write to a socket, for instance, please don't make me use Java. Accessing memory directly is horribly painful in such a language.

    Likewise, if I need to multithread, I need a language that doesn't mutex-protect the whole heap. That pretty much rules out all garbage collected languages.

    Speaking of multithreading: in ten years' time, when there will be somewhere between 64 and 1024 cores on a chip that is tightly constrained by memory bandwidth, multithreading is going to be the only way to get performance out of it.

    ReplyDelete