Why 'Self.Self' Compiles and Run in Swift

Why this code capturing self inside this block compile in swift?

The compiler has never complained about this. But it should (and I have filed a bug on this point), because the code you've written won't work: the button will not actually do anything when tapped. (The app might even crash, but then again it might not.)

The reason (for both phenomena) is that the compiler misinterprets the term self here to mean the class — which does exist before initialization of the instance.

The solution is to replace let by lazy var. That does work, because now the code will not actually be called until some later, when the instance does exist.

What is self used for in Swift?

You will also use self a lot when creating your extensions, example:

extension Int {
func square() -> Int {
return self * self
}

// note: when adding mutating in front of it we don't need to specify the return type
// and instead of "return " whatever
// we have to use "self = " whatever

mutating func squareMe() {
self = self * self
}
}
let x = 3
let y = x.square()
println(x) // 3
printlx(y) // 9

now lets say you want to change the var result itself
you have to use the mutating func to make change itself

var z = 3

println(z) // 3

now lets mutate it

z.squareMe()

println(z) // 9

// now lets see another example using strings :

extension String {
func x(times:Int) -> String {
var result = ""
if times > 0 {
for index in 1...times{
result += self
}
return result
}
return ""
}

// note: when adding mutating in front of it we don't need to specify the return type
// and instead of "return " whatever
// we have to use "self = " whatever

mutating func replicateMe(times:Int){
if times > 1 {
let myString = self
for index in 1...times-1{
self = self + myString
}
} else {
if times != 1 {
self = ""
}
}
}
}

var myString1 = "Abc"
let myString2 = myString1.x(2)

println(myString1) // "Abc"
println(myString2) // "AbcAbc"

now lets change myString1

myString1.replicateMe(3)

println(myString1) // "AbcAbcAbc"

Why Self.self print Self

This is the bug SR-14564 ""\(Self.self)" causes issue on Xcode 12.5 when Swift is optimized", and it has already been fixed in Swift 5.5. You are probably using Xcode 12.5, which uses Swift 5.4. Try updating to the Xcode 13 Beta. You can download it here.

Using type as a value, why is the self keyword required here?

Self-answering, with help of comments, I was able to find out the reason:


Using .self after the type name is called Postfix Self Expression:

A postfix self expression consists of an expression or the name of a
type, immediately followed by .self. It has the following forms:

expression.self
type.self

The first form evaluates to the value of the expression. For example, x.self evaluates to x.

The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument.

Thus, the .self keyword is required to consider the type as a value capable of being passed as an argument to functions.

What is `self` in swift?

self is a keyword and normally you cannot use keywords and reserved words in places outside their context. However, that sometimes creates problems. For that reason there is a special syntax to make the keyword to be a normal identifier, e.g.:

enum MyEnum: String {
case `default`
}

(also see Swift variable name with ` (backtick))

Historically self was not allowed as as a constant name inside guard-let-else and therefore backticks were commonly (ab)used.
They are no longer needed since Swift 4.2.

The code will still work correctly since you can wrap any identifier in backticks and it will just be a normal identifier.

Why does Swift give me a compiler error when my convenience initializer runs self.init inside if an if-let statement?

The error message is perhaps misleading. You must explicitly return nil if the initialization fails, as stated in
the documentation "Failable Initializers":

You write return nil within a failable initializer to indicate a point
at which initialization failure can be triggered.

Which means in your case that you have to add an else case
if the optional binding fails:

convenience init?(data: [String: String]) {
if let name = data["name"], region = data["region"] {
self.init(name: name, season: region)
} else {
return nil
}
}

Alternatively with guard:

convenience init?(data: [String: String]) {
guard let name = data["name"], region = data["region"] else {
return nil
}
self.init(name: name, season: region)
}

Using useless object.self.self.. or Class.self.self.. is ever need?

This is a Postfix Self Expression according to the Swift reference:

A postfix self expression consists of an expression or the name of a type, immediately followed by .self

The first form evaluates to the value of the expression. For example, x.self evaluates to x.

The fact that you can write .self indefinitely is just a side effect of this definition. Since x.self is an expression itself, you can add .self to it too. And you can do this forever.

That doesn't mean you should though.

These do the same thing:

let x                         =                          10
let x = 10

Hopefully you'd agree that the second one reads better. Similarly, .self is generally redundant. According to this discussion, it seems like .self is really just a legacy from Objective-C. IMO it also makes syntaxes like the identity key path (\.self) "make more sense".

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

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.

Property initializers run before 'self' is available

As correctly pointed out by vadian you should create an init in such scenarios:

class MyOwn {
let myUser: User
var life: Int

init() {
self.myUser = User(name: "John", age: 100)
self.life = myUser.age
}
}

You can't provide a default value for a stored property that depends on another instance property.



Related Topics



Leave a reply



Submit