Default Parameters in Swift – Dynamically or Statically Bound?

edit: after this post originally went up, the Swift dev team confirmed on the forums that default parameters should be dynamically bound. However, as of Swift 1.1, they’re still statically bound.

Quick quiz. What does the following code do?

class Shape {
  func draw(colour: String = "Red") { 
    println("\(colour) shape")

let s1 = Shape()

It prints Red shape, right? No argument supplied, so the default value of Red is used.

Ok what about this?

class Circle: Shape { 
  override func draw(colour: String = "Blue") { 
    println("\(colour) circle") 

let s2 = Circle()

It should Blue circle. No surprises there. Again no argument, but the overridden function defaults to a different color and prints a different shape.

Ok finally, what about this?

let s3: Shape = Circle()

Blue circle again, right? s3‘s static type is the base class, but it points to an inherited class. Polymorphism means the overridden function runs, so it should be just like the previous example.

If Swift bound default parameters dynamically, sure. But as of Swift 1.1, it behaves like C++,1 and you actually get Red circle. This is because parameters are bound statically not dynamically. Similarly, which overloaded function is chosen is also done statically – as seen in our series on Swift overload resolution

Why is C++ like this? Because default arguments are determined at compile time, not at run time. So while the correct function is applied, the default argument is looked up via the static type of s3, which is a Shape not a Circle. This could lead to some quite surprising behavior, which is why this is Item 37 of the Effective C++ book, which has more info on why it is this way (it’s related to run-time performance) and some workarounds to avoid it.

  1. I wrote the same code in C++ to double-check this and, holy cow, writing some simple C++ was painful after a week of Swift.