Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Swift disallow assignment to self in class init, but not in protocol init?

I often find myself liking how, in the initializers for structs, enums, and protocols, I can write something like self = someValue. This is great when I have some predefined values or am cloning an existing value.

However, this syntax doesn't work for classes. I can't really figure out why, either.

Cannot assign to value: 'self' is immutable

If the concern is double-initialization, the Swift compiler knows if, when, and where I call designated super or self initializers, so it knows whether I'm done initializing this instance. If the concern is that I haven't yet called a designated initializer, then it should be fine because I'd just be making this instance a reference to the other one (2 vars 1 pointer). If the concern is that concurrent access might have caused self to already be initialized... well that's nonsense because we're in the initializer and Swift initializers are not susceptible to that.

And after all that I discovered I can get around this with a single-use protocol:

class MyClass {
    let content: String
    
    init(content: String) {
        self.content = content
    }

    convenience init(from1 other: MyClass) {
        self = other // Cannot assign to value: 'self' is immutable
    }
}



protocol MyProto {}

extension MyClass: MyProto {}



extension MyProto {
    
    init(from2 other: Self) {
        self = other
    }
}



let foo = MyClass(content: "Foo")

print(MyClass(from1: foo)) // Never would've compiled in the first place
print(MyClass(from2: foo)) // Perfectly OK!

So why is this denied in common usage, but allowed in protocol-extensions?

like image 838
Ky. Avatar asked Oct 17 '22 08:10

Ky.


1 Answers

It seems this currently behaves as expected.

The whole problem has been discussed on the swift forums: Assigning to Self in Protocol Extensions

The last time this quirk came up in internal discussions, the thought some of us had was that it might be worthwhile to prohibit classes from conforming to protocols with mutating requirements altogether. If you think about it, this makes some amount of sense — it seems like it would be quite hard to write code that can operate on both mutable values and mutable references generically, since the latter do not have value semantics:

var x = y
x.mutatingProtocolRequirement()
// did y change too?

However the discussion sort of fizzled out.

like image 145
Sulthan Avatar answered Oct 21 '22 05:10

Sulthan