Allow `self = x` in class convenience initializers

In a non-final class, a designated initializer can be called as part of a super.init delegation from a derived class. The "self" value is going to be a partially initialized instance of the derived class in this case, with the derived class's stored properties already initialized but nothing else. It wouldn't make sense to replace "self" with a fully initialized instance while it is in this state.

10 Likes

I have a prototype implementation here: [awaiting evolution] Allow convenience initializers to reassign self. by jckarter · Pull Request #19311 · apple/swift · GitHub

11 Likes

I am quite glad there is movement on this! It will definitely help swift-corelibs-foundation be not only more efficient but also work more in-line with the objc implementation for factory style initializers.

Per the designated initializer case it would be nice to allow this if and only if the type of self == the type that was allocated (e.g. a runtime check for the non-final case that Slava brought up). That change would allow SCLF to implement every case that should be a factory pattern.

1 Like

Supporting that would require some fancier control-flow-sensitive analysis than we current do for definite initialization, since we'd have to ensure that a self = assignment only occurred in a context where it was known that Self == ConcreteClass. Maybe if we a type-refining cast feature like like what @grego proposes here we could confine self-assignments in a designated initializer to if <Self == C> condition blocks.

Slightly off-topic, but would it make sense to add a similar feature to Swift like instancetype from Objective-C. That type should bound the currently unconstrained Self to something that you just mentioned Self == C. This is really a missing feature for factory initializer in the context of designated initializers and it would also allow new and safe generic patterns to be expressed in Swift. What do you think @Joe_Groff?

1 Like

Self is instancetype. Factory initializers are interesting in that they do not always return instancetype.

3 Likes

What's the update on this proposal? Anything blocking it?

I haven't had time to finish the implementation. There are still a few issues with the implementation in [awaiting evolution] Allow convenience initializers to reassign self. by jckarter · Pull Request #19311 · apple/swift · GitHub that need to be fixed to get the tests passing.

5 Likes

This would be particularly helpful for classes that represent Core Data entities, as it would allow you to define initializers that use NSFetchRequests to retrieve information.

3 Likes

I guess I'm way too impatient, but I'd love to see this feature so I was just wondering when it will be merged :sweat_smile:

2 Likes

Me too!

1 Like

The implementation needs to be completed for the feature to be considered for review. I got a start in Proposal: Allow convenience inits to assign `self` by jckarter · Pull Request #910 · apple/swift-evolution · GitHub but there is more work to be done.

1 Like

Just needed this one today :slight_smile:

import Contacts

extension CNPostalAddress {
    convenience init(_ apiAddress: API.Address) {
        let address = CNMutablePostalAddress()
        address.city = ...
        self = address // Cannot assign to value: 'self' is immutable
    }
}