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. 

Rundown of how each Effective C++ item relates to Swift

In this post we talked about how some of the items in Effective C++ might apply to Swift.

Many of the entries highlighted some limitations on the part of Swift, so some might think this post was a criticism of Swift.  Actually far from it – many of the items in Effective C++ are pointing out dangers of C++ where you can shoot yourself in the foot if you aren’t careful.  In most cases, when you look at the equivalent issue in Swift, it’s a non-issue.

For completeness, here is a rundown of every item, what kind of article it is, and how it applies to Swift:

Item Danger or benefit? In Swift
1: View C++ as a federation of languages Probably a benefit? Applies the same
2: Prefer consts, enums and inlines to defines Pre-processor dangerous! No preprocessor!  No reflection or lisp-style macros either tho.
3: Use const whenever possible Benefit let and mutating are there, but they only go so far. 
4: Make sure that objects are initialized before they’re used Danger Fully locked down, you have to initialize variables properly.
5: Know what functions C++ silently writes and calls Bit of both Swift writes some init methods automatically, though it’s nowhere near as potentially confusing as C++
6: Explicitly disallow the use of compiler-generated functions you do not want Benefit Doesn’t really apply to Swift
7: Declare destrutors virtual in polymorphic base classes Danger Not an issue, every method is virtual in Swift classes.
8: Prevent exceptions from leaving destructors Danger No exceptions in Swift!
9: Never call virtual functions during construction or destruction Danger Swift’s enforcement of initializing the super and all member variables helps prevent this problem
10: Have assignment operators return a reference to *this More of a convention No assignment (or copy constructors) in Swift
11: Handle assignment to self in operator= Danger No assignment (or copy constructors) in Swift
12: Copy all parts of an object Danger Still dangerous, but without as good tools to fix it (no copy constructors on structs!)
13: Use objects to manage resources Benefit ARC + deinit = same benefit!  So long as you’re careful about variable capture.
14: Think carefully about copying behavior in resource-managing classes Good advice Good advice applies, take it
15: Provide access to raw resources in resource-managing classes Good advice Good advice applies, take it
16: Use the same form in corresponding uses of new and delete Bit of both No need for explicit memory management in Swift.  That’s good, right?
17: Store newer objects in smart pointers in standalone statements Bit of both ARC means every pointer in Swift is a smart pointer, so all good.
18: Make interfaces easy to use correctly and hard to use incorrectly Good advice Good advice applies, take it
19: Treat class design as type design Good advice Good advice applies, take it
20: Prefer pass-by-reference-to-const to pass-by-value Bit of both Doesn’t really apply to Swift, though I wish it had proper const support.
21: Don’t try to return a reference when you must return an object. Danger ARC means every pointer in Swift is a smart pointer, so all good.
22: Declare data members private Benefit No public/private in Swift – yet.  It’s coming apparently.
23: Prefer non-member non-friend functions to member functions Bit of both Seems to apply the same to Swift.
24: Declare non-member functions when type conversions should apply to all parameters Bit of both Type conversion in Swift is very different, and rarely implicit, so this doesn’t really apply.
25: Consider support for a non-throwing swap Bit of both No exceptions in Swift, so your swap will definitely be non-throwing.
26: Postpone variable definitions as long as possible Good advice Good advice applies, take it
27: Minimize casting Danger Swift type casting is a lot safer/saner/more powerful than C++. 
28: Avoid returning “handles” to object internals. Good advice Good advice applies, take it
29: Strive for exception-safe code Danger Swift code is definitely exception-safe.
30: Understand the ins and outs of inlining Danger If compilers aren’t better at humans at inlining these days, something has gone wrong.
31: Minimize compilation dependencies between files Danger No more headers!
32: Make sure public inheritance models “is-a” Good advice Good advice applies, take it
33: Avoid hiding inherited names Danger Swift mandates you override a method if it has the same signature as a parent class version
34: Differentiate between inheritance of interface and inheritance of implementation Good advice Good advice (mostly) applies, take it
35: Consider alternatives to virtual functions Good advice I need to research this one…  It probably applies.
36: Never redefine an inherited non-virtual function Danger No non-virtual functions in Swift
37: Never redefine a function’s inherited default parameter value Danger Swift behaves the same right now but this has been declared a bug in the compiler
38: Model “has-a” or “is-implemented-in-terms-of” through composition. Good advice Good advice applies, take it
39: Use private inheritance judiciously Danger Private inheritance is a weird C++ thing, don’t sweat it.
40: Use multiple inheritance judiciously. Danger No multiple implementation inheritance in Swift.  Most people think this is the right idea.
41: Understand implicit interfaces and compile-time polymorphism Benefit Swift has compile-time polymorphism through generics much like C++ templates but they differ a lot (C++ templates are crazy powerful crazy complicated)
42: Understand the two meanings of typename Confusing, if not dangerous You know how I said C++ templates got crazy complicated?  This is part of that.
Item 43: Know how to access names in templatized base classes Confusing, if not dangerous I need to research this one… probably doesn’t apply.
Item 44: Factor parameter-independent code out of templates Danger Is it possible Swift generics use could result in code bloat?  Would really need some serious LLVM digging to find out.
Item 45: Use member function templates to accept “all compatible types.” Benefit Swift generics provide much of the same features.  Needs a bit more research.
Item 46: Define non-member functions inside templates when type conversions are desired Benefit Swift is not very implicit type-conversion friendly (opinion probably divided on whether this is a good or bad… I think bad, most probably think good)
Item 47: Use traits classes for information about types Benefit I need to research this one… Associated types and type constrains in Swift seem related to this.
Item 48: Be aware of template metaprogramming A bizarre C++ rabbit hole Probably best not to think about it.
Items 49-52: New and delete Various Swift does have UnsafePointer and malloc so maybe these are kind of topics are not as much of a non-issue as you might think at first.
53: Pay attention to compiler warnings Good advice Good advice applies, take it
Item 54: Familiarize yourself with the standard library, including TR1 Benefit Objective-C, like C++, has a huge library behind it, all of which can be used from Swift.  Question is, how much will be ported to a more Swift-like form?  Time will tell
Item 55: Familiarize yourself with Boost Beneft Boost is fantastic.  But early indications are, there’s a huge community of Swift developers looking to do similar things.