In the below code, I don't understand why I get the said error when using Self()
? The code just works fine if I replace it with Fireman()
.
final class Fireman {
var numOfServices = 0
private init(){}
static var shared = Self() <-------- Here !!!
func extinguishFire() {
self.numOfServices += 1
print("Spraying water...\(self.numOfServices)")
}
}
Also the reason I had to mark the class final
is because, without that the error message was that I had to include a required
initializer (and when I do that I again get an error because my initializer is private
). So just to avoid further subclassing , though against my will I declared the class final
This is pretty similar to Protocol func returning Self, but enough different that it's probably worth answering separately. There are two issues here.
The first issue is why you need final
. As in the above question, the problem issue is that you're making a promise the compiler can't prove you'll keep.
Consider the following subclass:
class LocalFireman: Fireman {
let zipcode: String
init(zipcode: String) { self.zipcode = zipcode }
}
What should LocalFireman.shared
return? It can't return a Fireman. You said it had to return Self (i.e. LocalFireman). And it can't return a LocalFireman
, since it doesn't have a zipcode to init with. So now what?
Swift doesn't let you get into this corner by requiring you to either nail down the specific type of shared
(i.e. it will always be Fireman
, even if you call it on a subclass), or you need to promise there will be no subclasses, or you need to require all subclasses to implement init
:
required init() {}
OK, but you got that far. You marked it final
, and it still complains. Now you're hitting a compiler limitation. The whole point of Self
is covariance; it's the dynamic type at the point of calling, not the static type in context. It's not just a handy way to say "my type" and this was an choice (though it's something that could change I think). It means "my covariant type" even if you're in a situation where there can't be any subtypes.
All that said, given the private
init, I'm confused why you say marking it final
is "against my will." If all init
are private, this can't be subclassed anyway, so it seems you want a final class, and if so, then just put the class name where it goes. Self
is not for that problem (today).
This leaves open the question as to why you can't do this with a required init. Self
as a "type of class" and Self
as "type of thing conforming to a protocol" are treated as the same thing. So you can't think about this only in the class situation; anything can "inherit" (conform to) a protocol. So Self
can potentially refer to a struct. Structs can be any size. So allowing a stored property to be of type Self
creates memory layout problems. (I don't think Swift promises that classes will always be implemented as a pointer, either, so this could cause the same problem for classes, at least in principle.)
You can return a value of type Self
from a function, but you can't put one in a stored property (this is true both of static and non-static properties), and Swift also doesn't allow them for computed properties (I assume this is just for consistency). So the following is allowed (and in fact useful):
class Fireman {
required init() {}
static func make() -> Self { return Self() }
}
And this is what Self
is for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With