I’ve spent a long time programming, for money, in static languages like C# and ML, and also a lot of time programming in dynamic languages like Common Lisp. Many times I’ve been involved in discussions about the trade offs between the two approaches. Dynamic languages make some things really easy – typically there’s a REPL so you can quickly try out ideas and explore your way towards a solution to the problem you are working on. Static languages have their moments too – when I programmed ML, usually the program would work first time, though it often took a lot of debugging to get the code to type check in the first place. Type checking is basically a primitive form of theorem proving, and this goes to show that static typing is really about proving properties about your program. Some type systems like those of C# are too weak to ensure you won’t get a runtime error, whereas the type system of ML and it’s emphasis on algebraic datatypes is often strong enough to avoid runtime errors.
This blog post gives a really good contrast between the two systems, pointing out several of the common misconceptions about static and dynamic languages.