What is the Never return type? - swift

What does a func with return type Never do?
For example:
func addNums() -> Never {
//my code
}
What will be the difference if I kept the return type as Void like this?
func addNums() -> Void {
//my code
}
Suppose I wish to handle a fatalError (as said by dpassage); the below code will be sufficient:
print("its an error")
return
Apple documentation says:
The return type of functions that do not return normally, that is, a type with no values.
Source: Developer
This was not a duplicate question of When and how to use #noreturn attribute in Swift?, as I wish for a more detailed answer which needs details like:
Practical examples on the difference between both Never and Void as return types
Condition by which we should adopt these return types.
Also there is a chance the return type can be nil; I need a comparison of that feature too
The answer should focus on the differences.

Never return type was introduced in Swift 3 to substitute #noreturn key.
See justification in this proposal:
SE-0102 Remove #noreturn attribute and introduce an empty Never type
As official documentation explains:
The return type of functions that do not return normally; a type with
no values.
Use Never as the return type when declaring a closure,
function, or method that unconditionally throws an error, traps, or
otherwise does not terminate.
Source: https://developer.apple.com/documentation/swift/never
Basic illustration:
// The following function is our custom function we would use
// to manually and purposefully trigger crash. In the logs,
// we can specify what exactly went wrong: e.g. couldn't cast something,
// couldn't call something or some value doesn't exist:
func crashApp() -> Never {
fatalError("Something very, very bad happened! Crash the app!")
}
Usage specifics and advantages over #noreturn, as referenced by Erica Sadun:
Never allows a function or method to throw: e.g. () throws -> Never. Throwing allows a secondary path for error remediation, even in functions that were not expected to return.
As a first class type, Never works with generics in a way that the #noreturn attribute could not.
Never proactively prevents a function from claiming both a return type and no-return at the same time. This was a potential issue under the old system.
First note (regarding secondary error remediation) is probably particularly important. Never function can have complex logic and throw – not necessarily crash.
Let's see some interesting use cases and comparison between Never and Void
Never
Example 1
func noReturn() -> Never {
fatalError() // fatalError also returns Never, so no need to `return`
}
func pickPositiveNumber(below limit: Int) -> Int {
guard limit >= 1 else {
noReturn()
// No need to exit guarded scope after noReturn
}
return rand(limit)
}
Example 2
func foo() {
abort()
print("Should not reach here") // Warning for this line
}
Example 3
func bar() -> Int {
if true {
abort() // No warning and no compiler error, because abort() terminates it.
} else {
return 1
}
}
abort() is defined as:
public func abort() -> Never
Void
These examples would not have been possible with it returning Void:
public func abortVoid() -> Void {
fatalError()
}
func bar() -> Int {
if true {
abortVoid() // ERROR: Missing return in a function expected to return 'Int'
} else {
return 1
}
}
And to pack it up with abort() returning Never:
func bar() -> Int {
if true {
abort() // No ERROR, but compiler sees it returns Never and warns:
return 2 // Will never be executed
} else {
return 1
}
}
We use Void to tell compiler there is no return value. Application keeps running.
We use Never to tell compiler there is no return to caller site. Application runloop is terminated.

Void
Void is itself a return type which is a tuple with zero elements. You can use Void and () interchangeably.
Look at these examples,
func yourFunc() {} This is a function without a return type, which basically returns a tuple with zero elements, that can be written as ()
func yourFunc() -> Void {} Function which is explicitly informing the compiler about return type of void
func yourFunc() -> () {} This return type of () displays the same as void type. () indicates a tuple with zero elements
Never
Never return-type informs the compiler that no need exists to return an empty tuple (). Also, function with the never return type is used for the exit point of the current execution like a crash, fatal error, abort or exit.
For a detailed understanding of never, let's have a look at an abort() example :
1.
func yourFunc() {
abort()
print("Will not reach at this point") //Warning for this line
}
2.
func yourFunc() -> Int {
if true {
abort()
} else {
return 1
}
}
From the above code snippets, we can see when we call abort() (which doesn't return a value) as the last statement in a function that expects a value to be returned (in our case Int). The compiler doesn't generate a warning.
abort()
public func abort() -> Never
Similarly for exit():
public func exit(_: Int32) -> Never
The apple documentation says: "Use Never as the return type when declaring a closure, function, or method that unconditionally throws an error, traps, or otherwise does not terminate."
So if you want to write a custom function that logs a catastrophic error, you should use the return type Never to signal to the compiler:
func catastrophicErrorDisplay(error: String) -> Never {
DisplaySomeCustomLogFacility(error)
}
In short "Never is used for sudden and total failure from which recovery is impossible."

To better understand Never and Void, and how Never is useful in more contexts than the old #noreturn was, let's first look at what the two types actually are defined as:
Never is defined here as:
public enum Never {}
Since there is no way to instantiate a value of an empty enum, the type system guarantees that no instance of Never can exist. This means functions that specify their return type as Never are prevented by the type system from actually returning under any circumstances.
The compiler takes this into account when doing control-flow analysis. For example, these two functions both compile without error, whereas they would fail if a function that returns Void was substituted for fatalError:
func foo(fail: Bool) -> String {
if fail {
fatalError()
} else {
return "foo"
}
// notice there is no return statement here
}
func bar(fail: Bool) -> Void {
let s: String
if fail {
fatalError()
// the compiler doesn't complain s is not initialized here
} else {
s = "bar"
}
print(s)
}
Void is defined here as:
public typealias Void = ()
There are no two different instances of an empty tuple. Thus, the return value of functions returning Void holds no information.
You can actually write return () or return Void(). You can also use the "value" returned, like this:
func empty() -> Void {}
let v = empty()
print(type(of: v)) // prints "()"
although the compiler will warn "Constant 'v' inferred to have type 'Void', which may be unexpected".
Defining both Never and Void in terms of the type system rather than as special language features enables us to do some pretty clever things with generics. Let's look at an example of a Result type, generic over both the success and failure type.
enum Result<R, E> {
case success(R)
case failure(E)
}
A possible specialization of this would be Result<Void, MyError>. This would mean you have a result that, on success, does not hold any information beyond the fact it succeeded.
Another possibility could be Result<String, Never>. This result is guaranteed by the compiler to never be the failure case.
Optionals interact with Never and Void in a similar way. Never? can only ever be nil, and Void? only holds the information wether it is nil or not, nothing more (it's basically a more complicated Bool). Both of these are not very useful on their own, but might appear when Never or Void are used as generic parameters somewhere.
In practice, you will rarely write functions returning Never. I have personally used it to wrap fatalError to create a function I use to mark functions that are not implemented yet:
func unimplemented(f: String = #function) -> Never {
fatalError("\(f) is not implemented yet")
}
Another example of a function returning Never is dispatchMain(), which can be used in command-line utilities to start the DispatchQueue.main. Since this queue then waits for new blocks, dispatchMain() never returns.

Never indicates that the function will never return. It's intended to be used for things like fatalError which cause your program to crash intentionally, often after logging an error. You probably shouldn't use it unless you're doing something like making a handler for catastrophic errors in your application.
This is different from a function which just doesn't return a value, as in your second snippet. You could also write that as func addNums() -> Void.

Related

Throwing an error from a stored throwing function

I have an array of throwing completion block handlers:
typealias CompletionBlock = (MyType) throws -> Void
private var handlers: [CompletionBlock] = []
I want to be able to recall them later on and throw an error like this:
for handler in handlers {
handler(throw myError)
}
However, that doesn't work because it's expecting me to pass MyType to the handler, not an error. How can I do this?
Your question is a bit vague, but I'm going to assume you mean that you want the handlers to accept the result of a throwing function. That's possible, and I'll show how, but it's not quite what you want.
"The result of a throwing function" can be expressed by calling a function that calls a throwing function:
typealias CompletionBlock = (() throws -> MyType) -> Void
Throwing an error in the way you've described like this:
let result: () throws -> MyType = { throw MyError() }
for handler in handlers {
handler(result)
}
A handler would then look like:
func h(result: () throws -> MyType) {
do {
let myType = try result()
// ...
} catch {
// ...
}
}
But this is not a great design. Most importantly it executes result many times. Instead you want to pass the Result of a throwing function:
typealias CompletionBlock = (Result<MyType, Error>) -> Void
let f: () throws -> MyType = { throw MyError() }
let result = Result(catching: f)
for handler in handlers {
handler(result)
}
The more common look for this is along these lines:
let result = Result {
// Do various operations that might throw
return value
}
You can also convert back from Result to a throws using try result.get(). So you can easily move between Result and throws wherever you like. Result is best for storing. Throws is best for calling. You can have both.
(And of course, you should also be looking to the future and exploring replacing completion handlers with async/await, but there are many reasons you might not do that right away, so Result will be an important tool for quite some time.)
You are trying to change the behaviour of a stored closure by forcing it to throw an error regardless of its input. You cannot do that.
The fact that you marked CompletionBlock as throws only means that the closure itself might throw. However, you cannot force it to throw, since you can only pass an input argument of type MyType to it.
Moreover, there's no point in enforcing a closure to throw, since you need to handle the error thrown from the call-site anyways. So you can just simply throw the error from the call site.
Alternatively, if you need the closure itself to handle an error, you should change the closure to accept a Result and in case .failure in injected, the closure itself could throw.
typealias CompletionBlock = (Result<MyType, MyError>) throws -> Void
private var handlers: [CompletionBlock] = []
for handler in handlers {
handler(.failure(myError))
}

Generic type not preserved when called within another generic function

[Updated with a less contrived example]
I'm trying to extend a generic function to provide different behavior for a specific type. This works as expected when I call the function directly. But If I call it from within another generic function, the original generic type is not preserved and I get the default behavior. I'm a bit new to Swift, so I may be missing something obvious here.
My code looks something like this:
protocol Task {
associatedtype Result
}
struct SpecificTask: Task {
typealias Result = String
// other taks related properties
}
enum TaskRunner<T: Task> {
static func run(task: T) throws -> T.Result {
// Task not supported
throw SomeError.error
}
}
extension TaskRunner where T == SpecificTask {
static func run(task: T) throws -> T.Result {
// execute a SpecificTask
return "Some Result"
}
}
func run<T: Task>(task: T) throws -> T.Result {
// Additional logic related to running the task
return try TaskRunner.run(task: task)
}
print(try TaskRunner.run(task: SpecificTask())) // Prints "Some Result"
print(try run(task: SpecificTask())) // Throws SomeError
I need the top-level run function to call the SpecificTask version of the lower-level run() function, but the generic version of the function is called instead
You're trying to reinvent class inheritance with generics. That is not what generics are for, and they don't work that way. Generic methods are statically dispatched, which means that the code is chosen at compile-time, not runtime. An overload should never change the behavior of the function (which is what you're trying to do here). Overrides in where clauses can be used to improve performance, but they cannot be used to create dynamic (runtime) dispatch.
If you must use inheritance, then you must use classes. That said, the problem you've described is better solved with a generic Task rather than a protocol. For example:
struct Task<Result> {
let execute: () throws -> Result
}
enum TaskRunner {
static func run<Result>(task: Task<Result>) throws -> Result {
try task.execute()
}
}
let specificTask = Task(execute: { "Some Result" })
print(try TaskRunner.run(task: specificTask)) // Prints "Some Result"
Notice how this eliminates the "task not supported" case. Rather than being a runtime error, it is now a compile-time error. You can no longer call this incorrectly, so you don't have to check for that case.
If you really want dynamic dispatch, it is possible, but you must implement it as dynamic dispatch, not overloads.
enum TaskRunner<T: Task> {
static func run(task: T) throws -> T.Result {
switch task {
case is SpecificTask:
// execute a SpecificTask
return "Some Result" as! T.Result // <=== This is very fragile
default:
throw SomeError.error
}
}
}
This is fragile because of the as! T.Result. If you change the result type of SpecificTask to something other than String, it'll crash. But the important point is the case is SpecificTask, which is determined at runtime (dynamic dispatch). If you need task, and I assume you do, you'd swap that with if let task = task as? SpecificTask.
Before going down that road, I'd reconsider the design and see how this will really be called. Since the Result type is generic, you can't call arbitrary Tasks in a loop (since all the return values have to match). So it makes me wonder what kind of code can actually call run.

In Swift, can you write an extension which returns a typed instance of the class the extension is on?

This is one of those things that seems simple enough, but doesn't work as you'd expect.
I'm working on a 'fluent/chaining'-style API for my classes to allow you to set properties via functions which can be chained together so you don't have to go crazy with initializers. Plus, it makes it more convenient when working with functions like map, filter and reduce which share the same kind of API.
Consider this RowManager extension...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> RowManager
{
self.isVisible = isVisible
return self
}
}
This works exactly as one would expect. But there's a problem here... if you're working with a subclass of RowManager, this downcasts the object back to RowManager, losing all of the subclass-specific details.
"No worries!" I thought. "I'll just use Self and self to handle the type!" so I changed it to this...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization representing the type, not instance
{
self.isVisible = isVisible
return self // Note the lowercase representing the instance, not type
}
}
...but that for some reason won't even compile giving the following error...
Command failed due to signal: Segmentation fault: 11
UPDATE
Doing more research, this seems to be because our code both is in, and also uses, dynamic libraries. Other questions here on SO also talk about that specific error in those cases. Perhaps this is a bug with the compiler because as others have correctly pointed out, this code works fine in a stand-alone test but as soon as the change is made in our code, the segmentation fault shows up.
Remembering something similar with class functions that return an instance of that type, I recalled how you had to use a private generic function to do the actual cast, so I tried to match that pattern with the following...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization
{
self.isVisible = isVisible
return getTypedSelf()
}
}
private func getTypedSelf<T:RowManager>() -> T
{
guard let typedSelfInstance = self as? T
else
{
fatalError() // Technically this should never be reachable.
}
return typedSelfInstance
}
Unfortunately, that didn't work either.
For reference, here's the class-based code I attempted to base that off of (className is another extension that simply returns the string-representation of the name of the class you called it on)...
extension UITableViewCell
{
/// Attempts to dequeue a UITableViewCell from a table, implicitly using the class name as the reuse identifier
/// Returns a strongly-typed optional
class func dequeue(from tableView:UITableView) -> Self?
{
return self.dequeue(from:tableView, withReuseIdentifier:className)
}
/// Attempts to dequeue a UITableViewCell from a table based on the specified reuse identifier
/// Returns a strongly-typed optional
class func dequeue(from tableView:UITableView, withReuseIdentifier reuseIdentifier:String) -> Self?
{
return self.dequeue_Worker(tableView:tableView, reuseIdentifier:reuseIdentifier)
}
// Private implementation
private class func dequeue_Worker<T:UITableViewCell>(tableView:UITableView, reuseIdentifier:String) -> T?
{
return tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) as? T
}
}
At WWDC Apple confirmed this was a Swift compiler issue that something else In our codebase was triggering, adding there should never be a case where you get a Seg11 fault in the compiler under any circumstances, so this question is actually invalid. Closing it now, but I will report back if they ever address it.

"Closure cannot implicitly capture a mutating self parameter" - after updating to Swift 3 [duplicate]

I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.

Swift: Overriding Self-requirement is allowed, but causes runtime error. Why?

I just started to learn Swift (v. 2.x) because I'm curious how the new features play out, especially the protocols with Self-requirements.
The following example is going to compile just fine, but causes arbitrary runtime effects to happen:
// The protocol with Self requirement
protocol Narcissistic {
func getFriend() -> Self
}
// Base class that adopts the protocol
class Mario : Narcissistic {
func getFriend() -> Self {
print("Mario.getFriend()")
return self;
}
}
// Intermediate class that eliminates the
// Self requirement by specifying an explicit type
// (Why does the compiler allow this?)
class SuperMario : Mario {
override func getFriend() -> SuperMario {
print("SuperMario.getFriend()")
return SuperMario();
}
}
// Most specific class that defines a field whose
// (polymorphic) access will cause the world to explode
class FireFlowerMario : SuperMario {
let fireballCount = 42
func throwFireballs() {
print("Throwing " + String(fireballCount) + " fireballs!")
}
}
// Global generic function restricted to the protocol
func queryFriend<T : Narcissistic>(narcissistic: T) -> T {
return narcissistic.getFriend()
}
// Sample client code
// Instantiate the most specific class
let m = FireFlowerMario()
// The call to the generic function is verified to return
// the same type that went in -- 'FireFlowerMario' in this case.
// But in reality, the method returns a 'SuperMario' and the
// call to 'throwFireballs' will cause arbitrary
// things to happen at runtime.
queryFriend(m).throwFireballs()
You can see the example in action on the IBM Swift Sandbox here.
In my browser, the output is as follows:
SuperMario.getFriend()
Throwing 32 fireballs!
(instead of 42! Or rather, 'instead of a runtime exception', as this method is not even defined on the object it is called on.)
Is this a proof that Swift is currently not type-safe?
EDIT #1:
Unpredictable behavior like this has to be unacceptable.
The true question is, what exact meaning the keyword Self (capital first letter) has.
I couldn't find anything online, but there are at least these two possibilities:
Self is simply a syntactic shortcut for the full class name it appears in, and it could be substituted with the latter without any change in meaning. But then, it cannot have the same meaning as when it appears inside a protocol definition.
Self is a sort of generic/associated type (in both protocols and classes) that gets re-instantiated in deriving/adopting classes. If that is the case, the compiler should have refused the override of getFriend in SuperMario.
Maybe the true definition is neither of those. Would be great if someone with more experience with the language could shed some light on the topic.
Yes, there seems to be a contradiction. The Self keyword, when used as a return type, apparently means 'self as an instance of Self'. For example, given this protocol
protocol ReturnsReceived {
/// Returns other.
func doReturn(other: Self) -> Self
}
we can't implement it as follows
class Return: ReturnsReceived {
func doReturn(other: Return) -> Self {
return other // Error
}
}
because we get a compiler error ("Cannot convert return expression of type 'Return' to return type 'Self'"), which disappears if we violate doReturn()'s contract and return self instead of other. And we can't write
class Return: ReturnsReceived {
func doReturn(other: Return) -> Return { // Error
return other
}
}
because this is only allowed in a final class, even if Swift supports covariant return types. (The following actually compiles.)
final class Return: ReturnsReceived {
func doReturn(other: Return) -> Return {
return other
}
}
On the other hand, as you pointed out, a subclass of Return can 'override' the Self requirement and merrily honor the contract of ReturnsReceived, as if Self were a simple placeholder for the conforming class' name.
class SubReturn: Return {
override func doReturn(other: Return) -> SubReturn {
// Of course this crashes if other is not a
// SubReturn instance, but let's ignore this
// problem for now.
return other as! SubReturn
}
}
I could be wrong, but I think that:
if Self as a return type really means 'self as an instance of
Self', the compiler should not accept this kind of Self requirement
overriding, because it makes it possible to return instances which
are not self; otherwise,
if Self as a return type must be simply a placeholder with no further implications, then in our example the compiler should already allow overriding the Self requirement in the Return class.
That said, and here any choice about the precise semantics of Self is not bound to change things, your code illustrates one of those cases where the compiler can easily be fooled, and the best it can do is generate code to defer checks to run-time. In this case, the checks that should be delegated to the runtime have to do with casting, and in my opinion one interesting aspect revealed by your examples is that at a particular spot Swift seems not to delegate anything, hence the inevitable crash is more dramatic than it ought to be.
Swift is able to check casts at run-time. Let's consider the following code.
let sm = SuperMario()
let ffm = sm as! FireFlowerMario
ffm.throwFireballs()
Here we create a SuperMario and downcast it to FireFlowerMario. These two classes are not unrelated, and we are assuring the compiler (as!) that we know what we are doing, so the compiler leaves it as it is and compiles the second and third lines without a hitch. However, the program fails at run-time, complaining that it
Could not cast value of type
'SomeModule.SuperMario' (0x...) to
'SomeModule.FireFlowerMario' (0x...).
when trying the cast in the second line. This is not wrong or surprising behaviour. Java, for example, would do exactly the same: compile the code, and fail at run-time with a ClassCastException. The important thing is that the application reliably crashes at run-time.
Your code is a more elaborate way to fool the compiler, but it boils down to the same problem: there is a SuperMario instead of a FireFlowerMario. The difference is that in your case we don't get a gentle "could not cast" message but, in a real Xcode project, an abrupt and terrific error when calling throwFireballs().
In the same situation, Java fails (at run-time) with the same error we saw above (a ClassCastException), which means it attempts a cast (to FireFlowerMario) before calling throwFireballs() on the object returned by queryFriend(). The presence of an explicit checkcast instruction in the bytecode easily confirms this.
Swift on the contrary, as far as I can see at the moment, does not try any cast before the call (no casting routine is called in the compiled code), so a horrible, uncaught error is the only possible outcome. If, instead, your code produced a run-time "could not cast" error message, or something as gracious as that, I would be completely satisfied with the behaviour of the language.
The issue here seems to be a violation in contract:
You define getFriend() to return an instance of receiver (Self). The problem here is that SuperMario does not return self but it returns a new instance of type SuperMario.
Now, when FireFlowerMario inherits that method the contract says that the method should return a FireFlowerMario but instead, the inherited method returns a SuperMario! This instance is then treated as if it were a FireFlowerMario, specifically: Swift tries to access the instance variable fireballCount which does not exist on SuperMario and you get garbage instead.
You can fix it like this:
class SuperMario : Mario {
required override init() {
super.init()
}
override func getFriend() -> SuperMario {
print("SuperMario.getFriend()")
// Dynamically create new instance of the same type as the receiver.
let myClass = self.dynamicType
return myClass.init()
}
}
Why does the compiler allow it? It has a hard time catching something like this, I guess. For SuperMario, the contract is still valid: the method getFriend does return an instance of the same class. The contract breaks when you create the subclass FireFlowerMario: should the compiler notice that a superclass might violate the contract? This would be an expensive check and probably more suited for a static analyzer, IMHO (Also, what happens if the compiler doesn't have access to SuperMario's source? What happens if that class is from a library?)
So it's actually SuperMario's duty to ensure that the contract is still valid when subclassing.