Polymorphism with Return Types

The most recent entry in Apple’s Swift blog primarily deals with the REPL, but they also drop an interesting reminder:

Keep in mind that Swift allows function overloading even when two signatures differ only in their return type.

I completely forgot about this, which is a shame because it’s awesome! Take the old Cocoa method of converting between types:

let thing = MyThing(int:42)
let string = thing.stringValue()
let float = thing.floatValue()
let bool = thing.boolValue()

By redefining stringValue()->String, floatValue->Float, and boolValue->Bool to value()->String, value()->Float, and value()->Bool, we’re now using polymorphism to simplify our type’s interface.

let thing = MyThing(int:42)
let string = thing.value() as String
let float = thing.value() as Float
let bool = thing.value() as Bool

Well, maybe I should have put “simplify” in scare quotes. We seem to have just moved the type out of the method name and into a cast. Is this really a win?

Yes, because remember Swift is flat-out magical when it comes to type inference. We don’t actually need to cast the return of these methods to disambiguate them if the thing we’re assigning to has a type:

let thing = MyThing(int:42)
let string:String = thing.value()
let float:Float = thing.value()
let bool:Bool = thing.value()

If, as is often the case, we’re dealing with properties that have been previously defined, this gets even better.

//Earlier…
let string:String
let float:Float
let bool:Bool

//Later…
string = thing.value()
float = thing.value()
bool = thing.value()

And composition is pure win:

writeLog(thing.value())
incrementCount(thing.value())
shouldAnimate(thing.value())

We can take advantage of Swift’s strong types and pervasive polymorphism to do real work. The more of this work we offload, the less cruft we have to write and the more readable our code becomes.