The bit that annoys me about this type of discussion is that most dynamic languages give you less flexibility and choice than statically typed languages to do what you want.

In C#, for instance, if you want values rather than variable-sites to have types, use the "object" keyword, or just use an interface:

object Add(object a, object b)
{
  return a.GetType().Invoke("op_add", a, b);
}

If you do that Add(1, 2) and Add("cat", "dog") will now work without complaining at you. If you write Add(new object(), "string") you'll end up with a runtime error, not a compile time one.

So the thing is that you can program dynamically in most static languages. What you can't do is program statically in dynamic languages. Yes, you can add code to test for types like this in PHP:

function add($var1, $var2) { assert(isint($var1)); assert(isint($var2)); }

but if you do that you still don't get a compile time or immediate IDE feedback when you write add("2", "3") - meaning that it makes the time between when you make a silly mistake and when you have an opportunity to fix it longer. It also ups the barrier to refactoring your code, since when you change internal stuff it's now much harder to quickly see where the error was caused because errors can now happen further from your typo.

The static versus dynamic debate is a debate about choice, and a debate about whether some forms of basic error checking (which is itself a rudimentary form of unit testing) is a first-class citizen in the language. In Spec# they take this further and build proper unit tests with algebraic solvers into the language - to the improvement rather than to the detriment of programmer productivity, because in Spec# the cost of writing unit tests shrinks yet further to just those tests that are too complex to write as requires/ensures contracts.

Dynamically typed languages pull the other way. They say that variable sites shouldn't be able to "ensure" or "require" features of the thing that sits inside them. This means that a greater burden is put on the compiler to infer the type and ensure type-safety internally (assuming the langauge is even compiled - most are interpreted, taking a double hit on speed).

Increasingly C# is giving you the most flexibility of all of the languages to program how you like. Use imperative programming if you want, or functional programming if you prefer. Use compiler-based assertions to pick up common typos and logic errors, and have a dynamic keyword for when it's useful.

Indeed, with Spec#, you can bring more of your testing into your code - making it possible for your compilation to "know" that you've tested for and proved that certain code paths can't take place - and since in real life hardly anyone unit tests their code, this is a way of bringing testing to normal developers, and stopping testing from being "the thing you do get someone else to do just before you launch the product"..

The future of languages is having static types where possible and dynamic types for the few times when it's actually needed.

http://research.microsoft.com/en-us/um/people/emeijer/Papers/RDL04Meijer.pdf