Duck typing and dynamic typing are not quite the same thing. Duck typing goes by the principle, “if it quacks like a duck and walks like a duck, it’s probably a duck”. This can be done statically too, except that errors will be reported at compile time instead of at runtime. Static duck typing is formally referred to as structural typing. Scala has some rudimentary support for structural typing, but it’s primarily a nominally typed language.
I assume that in your question when you use the term duck typing, you mean dynamic typing. So rest of my answer will explain what you can do with dynamic typing which you cannot with Scala’s type system.
One of the advantages that dynamically typed languages have over a type system like Scala’s is that, since getting things typed is out of the way, it’s easier or more plausible to first-class more and more constructs.
Let us take an example of Python. In Python, classes themselves are objects, i.e. first class entities. You can write class decorators, i.e. functions that take classes, and return modified classes. Python has extensible records/objects. The labels in dynlangs are inherently first class.
def label(name): return lambda obj: getattr(obj, name)
You can write a function to concatenate classes quite easily. Local name bindings are first class in Python, and can be put to good use at times. e.g. See how I can get string interpolation for free by passing local name bindings as a keyword argument:
'hello my name is {fname} {lname}'.format(**locals())
Even method resolution order, something that’s used for linearization in object hierarchies, is first class, and can be fiddled with to your pleasing.
If I am talking of first-class things, I cannot not mention Manuel Simoni’s Wat programming language (currently in works) which takes the first-classing to extreme. Syntax, control, data - everything is first class in Wat. You can see the project page here - wat-js on GitHub.
Another noticeable advantage I can think of is that it’s quite easy to abstract over arity and use collections of heterogeneous elements. In Python I can write a function compose that takes any number of functions, and composes them together (provided their argument types, return types conform).
>>> from functools import reduce
>>> def compose(*funcs): return reduce(lambda f, g: lambda x: f(g(x)), funcs)
>>> compose(lambda x: x + ' hello', str, lambda x: x + 1)(3)
Please note that probably none of the things I mentioned are intrinsically impossible to type but most of them are very hard. Let me go over them one by one. Classes as first class entities - It’s hard enough that OOHaskell is the only one that does this. Transforming classes - Scala would soon have macro types that will let you do this at compile time. Similar things are possible with OCaml’s camlp4 and Haskell’s TemplateHaskell. First class labels and extensible records - Ur and Morrow do this, can be emulated in Scala and Haskell with the use of HLists. (Check out shapeless, a Scala library that provides such records.) First class local name bindings, MRO, syntax - Not aware of any typed languages that do these.
Apropos abstracting arity, things are a bit hairy here. There are heterogeneous collections such as HList and HMap, Shapeless, the Scala library I mentioned before, implements these, and goes a long way in reducing the pain involved (but it still does not meet my personal criteria of simplicity). The compose function I mentioned before can probably be written with Shapeless but I wouldn’t attempt it, you may try it yourself as an exercise. This similar example might help you get there - Applying an argument list to curried function using foldleft in Scala.
Another note: Scala also has a trait named Dynamic which provides some rudimentary dynamic typing support in the language, and it’ll probably get better over time. Since Scala is a typed functional language, use of this construct is very limited.
Edit (Sept 8th, 2014)
Matthias Felleisen here (Bellman Confirms A Suspicion) provides the best defence that I have come across for untyped languages. To quote him:
The hidden blessing is that DT programmers can import, super-impose, and integrate many different static type disciplines — informally — and use them to design their code and to reason about it. The result are programming idioms that no one ordinary static type system can uniformly check
Also, here (Page on shenlanguage.org) is a paper by Mark Tarver that talks a bit about this:
A type checker for a functional language is in essence, an inference engine; that is to say, it is the machine embodiment of some formal system of proof. What we know, and have known since Godel’s incompleteness proof , is that the human ability to recognise truth transcends our ability to capture it formally. In computing terms our ability to recognise something as correct predates and can transcend our attempt to formalise the logic of our program.