views:

456

answers:

7

I have always worked on staticly typed languages (c/c++,java). For the poast months i have been playing with clojure and i really like it. One thing i am worried about is, say that i have a windows that takes 3 modules as arguments and along the way requirements change and i need to pass another module to the function. I just change the function and compiler complains everywhere i used it. But in clojure it wont complain until the function is called. I can just do a regex search and replace but it seems there is a chance to miss a call and it will go unnoticed until that function is actually called. How do you guys deal with this?

+7  A: 

This is one of the reasons automated testing/test driven development is even more important in dynamically typed languages. I haven't used Clojure (I mostly use Ruby), so unfortunately I can't recommend a specific testing framework.

zgchurch
+1. essentially, the static type system is just an auto-generated set of unit tests (as one of my dynamic-evangelist friends loves to point out). You need to code those by hand in the dynamic language, which gives you greater flexibility but also greater effort. It's up to you and your particular design to decide if that tradeoff is in favor of a dynamic or static language.
rmeador
you gloss over the fact that dealing with the static type system requires effort. The question is, which is greater?
jshen
@jshen: but how much effort? In a *good* statically typed language, you can pretty much forget that it is statically typed. It's only in junk like the C-family of languages that you have to constantly remind the compiler of the types of everything.
jalf
A: 

You lose some level of refactoring and type safety when you move to dynamic languages. The more information the compiler has, the more it can do at compile time for you.

Vitali
Excuse my ignorance but how dynamic typing makes you lose some level of refactoring?
khelll
He probably means "automated refactoring" here.
Pavel Minaev
I believe the sentence means "refactoring safety".
DigitalRoss
dynamic languages also require less refactoring because you don't have to get the class ontology right upfront.
jshen
A: 

Tim Bray discusses it here,critique of which by Cedric is here,and a post on artima discussing it at length.

prateek urmaliya
+2  A: 

The first thing I'd like to mention is that Bruce Eckel has written a very interesting article called Strong Typing vs Strong Testing (the link is down at the moment, unfortunately, but hopefully it will be up soon).

His idea is that when dealing with compiled languages, the compiler is just acting as the first, automatic step of automatic testing. When making the move to a dynamic language, you lose this first level of automatic testing. But in both cases, this first, automatic level is just one part of testing, and not even a very important part.

His point is that if you're developing programs properly, i.e. doing some form of tests and regression tests, the lack of a compiler will only force you to add some more, somewhat basic tests anyways, which is why it's no big loss.

So I guess the first answer I'd give you is, focus on your testing, something you should be doing anyway, and such changes shouldn't affect you too badly.

The second thing I'd like to mention is many dynamic languages that I've seen (for example, Python) have much better abilities to change what methods/classes do without breaking existing code.

For example, with Python, if your method used to accept two parameters but now requires a third one, you can always add a default parameter without breaking any existing code, but that you can now utilize. This is a very basic technique, but in Python's case (and I assume most other dynamic languages as well), these techniques can get much more interesting; since they're dynamic, you can pretty much change the implementation of functions for specific modules, change what variables mean, etc.

I'd suggest looking at which techniques Clojure has that allow similair things, and deciding if they apply in your situation.

Edan Maor
A: 

Test coverage is definitely important. But a dynamically typed language will allow you to work in a different way. In a strongly typed language (like Java), a change in the interface needs to modify all the callers. In Ruby, you could do this-- but probably won't. Instead, you'll probably add flexibility to the method on one of a few ways. Namely:

  • you tend to have very few methods that take as many as three parameters in Ruby (as opposed to Java). Because you don't have strong typed interface of Java, you break the problem down into smaller pieces and steps. It's much more common to write methods that take just 1 parameter, and then refactor when it becomes more complex.
  • it's possible-- and common-- to leave the old behavior in place while adding more arguments. For example, if you have to add a third argument to a two argument method, you will set its default value to preserve the old behavior (and save you a refactor). If you are familiar with Javascript libraries like jQuery, they take advantage of this everywhere with "optional" arguments.
  • similar to optional arguments, methods can grow to take a flexible parameter list. With solid test coverage, you can quite easily add a new behavior to an existing method and safely know you haven't broken the existing code. In Rails, methods like "render" take a wide range of options.
ndp
+2  A: 

You do the same thing you did if the method was part of a public interface that you weren't the only user of.

You add a new method with the extra module and and change the old one to call the new one with a suitable default.

Oh and if your program is that big, make sure you have good tests (test-is should make it simpler than Java)

tomjen
A: 

You're not completely without compiler support in Clojure. In the specific example you give, it's the arity of the function that changed, which would be picked up by compiling the Clojure code. I'm still making the strong -> dynamic typing transition and find this comforting!

Jim Downing