9

When working out the design for a new system, is it better to start with a statically-typed language (like Haskell), or a dynamically-typed language (like Ruby)?

Arguments I can think of:

  • With a static language, you can quickly create a specification and scope for what the program will do. With a dynamic language, you can quickly create a working demo to present to the customer for review.

  • With a dynamic language, you often avoid having to rearrange data structures and refactor code when you change your design. With a static language, you can define types before implementation, keeping the code to maintain very small.

  • With a static language, you have to figure out in advance what your program will do. With a dynamic language, you can start writing code, and let the design grow organically. As Paul Graham says in Hackers and Painters:

    A programming language is for thinking of programs, not for expressing programs you've already thought of.

  • With a static language, the compiler can help identify many types of bugs. With a dynamic language, you can begin testing and finding bugs sooner.

Static and dynamic typing both have advantages and disadvantages as far as prototyping is concerned. However, they both seem to me like equally valid approaches. Based on your experiences, which one is ultimately better?


Notes

Prototyping in natural language

A third type of language to consider: natural language. Instead of prototyping in code, one can prototype in writing. The customer can then read your documentation and critique your design early on, but cannot toy around with a working demo. If well-written, the documentation can make implementation in any language straightforward. Caveats:

  • The documentation may be tedious to read through, and difficult to digest without being able to see it. I speculate that a customer would rather experiment with something that works rather than read a wall of text (and images).

  • Prototyping an application in English rather than in type definitions is more verbose and less concrete.

Haskell types are descriptive

Note that types are particularly descriptive in Haskell, more so than in many static languages like C++ and Java. For example, suppose I have a function with this type signature in Haskell:

foo :: forall a. [a] -> a

A function that, for any type a, takes a list of items of type a and returns a value of type a.

Even without knowing the function's name, I know for a fact that:

  • It does not perform input/output or modify any values (well, unless it uses unsafePerformIO incorrectly), because Haskell is purely functional.

  • It cannot treat the items as, say, integers, because it has to support any type.

  • It has to use the input list (that, or throw an exception or go into an infinite loop). Otherwise, where would it get a value of type a from?

Therefore, the only thing this function could possibly do (other than fail) is extract an item out of the input list and return it. Although I still do not know which item it will use, [a] -> a tells me just about everything else.

3
  • 4
    Whichever one you are more expressive with.
    – snakehiss
    Sep 5, 2011 at 0:09
  • 1
    You mentioned natural languages, but you forgot programming with Powerpoint (or Photoshop). Many people find this very useful too.
    – sylvanaar
    Sep 5, 2011 at 3:44
  • I think a number of arguments about dynamic languages versus static languages are misguided. For example I don't believe it is true at all that you avoid having to re-arrange data structures and refactor code when you change your design in a dynamic language. Dynamic languages do save some time in not having to make variable declarations. But you also have to debug more type errors. Similarly with static languages programs grow organically as well. You might specify concrete types for a data structure but that does not equate with instantly specifying the design for the program....
    – Cervo
    Sep 5, 2011 at 15:18

6 Answers 6

8

I'm going to side with Paul Graham on this one: dynamic typing is most useful for creating programs organically, which is exactly what prototyping ought to be. The point is to get something done quickly that demonstrates the functionality of the final product, not the final product itself. Static typing is about formal correctness—well, ostensibly; at least it should be (as in Haskell or Agda)—but dynamic typing is about practical correctness, which is what matters more when you're prototyping.

In the right language, static type hints can be provided after the fact as an optimisation (and to provide added safety for future changes), or the prototype can be rewritten in a statically typed language once the requirements have been elucidated and solidified by the prototype.

1
  • 2
    A dynamic language omits type info; this makes it very terse. You can easily inspect whatever structures you have, because compiler never tried to optimize them heavily. When I need to write an algorithmically complex piece of code, I start with Python; it's far easier to get a slow but correct implementation on it. Then I port it to Java, using optimal data structures, etc. With Haskell, I'd probably use Clojure as a pair.
    – 9000
    Sep 5, 2011 at 13:20
6

I think the static vs. dynamic type issue isn't as important as many people make it out to be.

  1. I use both. Sometimes one is simply more useful than another in a given situation. This is most often caused by needing to use some specific tool/library/technology. So I chose what works well with the other components I have.

  2. I think that one of the things that people like about dynamic languages is that many are interpreted; You can modify them while they are running in an interactive manner using a REPL console. Any language with an eval function or something equivalent can do this. So, at least for this one aspect the type system is actually irrelevant.

  3. You can build prototypes using things that have no formal type system at all like shell scripts. (They do have REPL though...)

1
  • +1 for libraries, I don't use Python because it's dynamic, but because it comes batteries included. Sep 5, 2011 at 17:57
5

Do what works best for you and for what you are trying to do. I find that I currently prototype best in a static language. Prototyping with an expressive type system lets you do some cool things:

  • Write function signatures without corresponding implementations. My early stage Haskell code often has statements like:

    foo :: Foo -> Bar
    foo _ = error "not defined"

This is because I want an idea of what foo does when I write code that uses it, without having to actually have a working copy of foo. In other languages this is accomplished with something like throw new Exception(), which is something you would never do in real code, but helps a ton at early stages.

  • Write code without writing the types first, and use type inference to learn things about your code. I frequently call :t in the GHCi (Haskell REPL) to discover what it was that I just wrote. For example, this can tell you how generic a piece of code is, thus revealing the requirements of different pieces of your code and corresponding structure.

Conal Elliot described his view of Haskell to help with iPhone development this way:

"Once I was writing Haskell, the imperative machinery faded from view and I couldn’t help but start seeing essential patterns. Tinkering with those patterns led me to new insights ... I am grateful to have this higher-order lazy language with rich static typing as a thought tool, to help me gain insights and weed out my mistakes. It’s a bonus to me that the language is executable as well." Source

That's right. One of the gods of functional programming thinks that Haskell's primary worth is a modeling language, rather than a implementation language. Other guru's think similar things: Erik Meijer uses Haskell to help clarify underlying algebra and patterns that eventually go into object oriented frameworks.

The most important reason though for prototyping in a strict language, is that much of the time the things one wants to "prototype" are not the nifty early stage web apps that Paul Graham wants to fund. Often you need to prototype:

  1. Extensions to current infrastructure
  2. APIs for a specific language
  3. Architecture, not just new features

In each of these cases you really want to use a language that is close to the eventual implementation language in meaningful ways.

One nitpick though

 foo :: forall a. [a] -> a

has no "correct" (always terminates without producing an error or undefined) instances. That is because

[] :: forall a. [a]

But no function from [] to a could exist for a that have no instances.

4

Do you mean feature or design prototypes?

Feature prototypes are about showing a feature to the client before starting development of that feature from scratch in the final implementation language, so the point is to write that feature as fast as possible without concern for bugs or maintainability. Dynamic languages allow a correctness-productivity trade-off by allowing ugly hacks that no statically typed language would accept, which makes them, in theory, better suited for writing quick throw-away prototypes. Of course, in practice, the skill of the developer is more important than the language, but a coder equally skilled in both Haskell and Ruby would probably create a prototype faster in Ruby, and the resulting code would be a mess.

Design prototypes are about finding an appropriate program design through trial and error. Ugly hacks are useless — only the ability to refactor designs quickly matters. A fundamental requirement for massive refactoring is a suite of automated tests. In dynamic languages, this is usually a suite of developer-written unit tests, which takes a fair amount of time to write. In statically typed languages, the type signatures serve as automated tests and let the compiler detect any inconsistencies caused by code changes. Statically typed languages shine at refactoring in ways that no dynamically typed language can achieve.

0

Dynamic, especially if you know that the actual product would have to be in one of several popular static languages to be fast enough to solve the real problem in the wild. Doing this will automatically protect you from making the mistake of using the prototype as the end product.

0

Whatever language which you're most familiar with.

Dynamic vs static really doesn't matter. Functional vs OO really doesn't matter. Best fit, features or whatever they are usually all meaningless.

The only point of prototyping is speed of implementation (code-writing) because you need to change program a lot. And you should be fastest with your best language.

If you have two best languages in both of dynamic and static, I would bet on static one. Because static one usually can handle complexity, while dynamic one fails at some point. And nobody really know how large prototype will grow up.

Not the answer you're looking for? Browse other questions tagged or ask your own question.