Pitch: make class initialization complexity more progressively disclosed


(Chris Lattner) #1

Forward: This isn’t a concrete proposal, this an observation (originally from Joe Groff) of a problem that we hoped to have time to discuss and design in the Swift 3 timeframe, but which the core team won’t have time to drive. If anyone is interested in picking up this as a project to scope, design, and drive, that would be great. :-)

Class initialization in Swift support a wide array of knobs and concepts, including things like designated initializers, required initializers, convenience initializers, etc. These are all required by various common patterns in Cocoa and other OO systems, but has an unfortunate side effect: all of the complexity is foisted on you at once. This typically happens because you subclass a system framework and start getting errors about not fulfilling the requirements that may not be fully defining the behavior that would be required if another class comes along and derives from you.

The simplifying observation here is that many classes (particularly in gui apps) are leaf classes that are not further derived from. Wouldn’t it be great if you could freely define a new class and not have to know about required and convenience initializers? It seems that we should only have to enforce these requirements if you a) further derive from this class within your module, or b) mark the class publicly-derivable-from.

This isn’t a full pitch because I haven’t done a survey of all of the simplifications we could offer, and getting the diagnostics messages right for this would take a significant amount of work (e.g. explaining why "class X needs a required init because class Y started deriving from it”).

-Chris


(Erica Sadun) #2

Oh god yes.

On behalf of every descendant of UIViewController and SKScene, I thank you for this idea.

class MyViewController: UIViewController {
    let someNewThing: SomeType

    leaf init(someNewThing: SomeType) {
       // no calls to super, no calls to *anything*
        self.someNewThing = someNewThing
        // blah blah use self here blah
    }
}

@memberwise class MyScene: SKScene {
    let someNewThing: SomeType

    // boom. done. initless.
}

-- E

···

On Feb 29, 2016, at 11:53 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Forward: This isn’t a concrete proposal, this an observation (originally from Joe Groff) of a problem that we hoped to have time to discuss and design in the Swift 3 timeframe, but which the core team won’t have time to drive. If anyone is interested in picking up this as a project to scope, design, and drive, that would be great. :slight_smile:

Class initialization in Swift support a wide array of knobs and concepts, including things like designated initializers, required initializers, convenience initializers, etc. These are all required by various common patterns in Cocoa and other OO systems, but has an unfortunate side effect: all of the complexity is foisted on you at once. This typically happens because you subclass a system framework and start getting errors about not fulfilling the requirements that may not be fully defining the behavior that would be required if another class comes along and derives from you.

The simplifying observation here is that many classes (particularly in gui apps) are leaf classes that are not further derived from. Wouldn’t it be great if you could freely define a new class and not have to know about required and convenience initializers? It seems that we should only have to enforce these requirements if you a) further derive from this class within your module, or b) mark the class publicly-derivable-from.

This isn’t a full pitch because I haven’t done a survey of all of the simplifications we could offer, and getting the diagnostics messages right for this would take a significant amount of work (e.g. explaining why "class X needs a required init because class Y started deriving from it”).

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #3

I think we could avoid an explicit need for initializer decorations in most private or internal (a) cases too, since we have visibility into the entire class hierarchy. We could raise errors when specific subclasses don't provide `required` initializers, and infer the `convenience`-ness of each initializer from whether it `self.init` or `super.init` delegates. For non-publicly-subclassable classes there are no API liabilities to be concerned about.

-Joe

···

On Feb 29, 2016, at 10:53 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

The simplifying observation here is that many classes (particularly in gui apps) are leaf classes that are not further derived from. Wouldn’t it be great if you could freely define a new class and not have to know about required and convenience initializers? It seems that we should only have to enforce these requirements if you a) further derive from this class within your module, or b) mark the class publicly-derivable-from.


(David Hart) #4

Really looking forward to this. Isn't part of the solution to make classes final by default?

···

On 01 Mar 2016, at 07:53, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Forward: This isn’t a concrete proposal, this an observation (originally from Joe Groff) of a problem that we hoped to have time to discuss and design in the Swift 3 timeframe, but which the core team won’t have time to drive. If anyone is interested in picking up this as a project to scope, design, and drive, that would be great. :slight_smile:

Class initialization in Swift support a wide array of knobs and concepts, including things like designated initializers, required initializers, convenience initializers, etc. These are all required by various common patterns in Cocoa and other OO systems, but has an unfortunate side effect: all of the complexity is foisted on you at once. This typically happens because you subclass a system framework and start getting errors about not fulfilling the requirements that may not be fully defining the behavior that would be required if another class comes along and derives from you.

The simplifying observation here is that many classes (particularly in gui apps) are leaf classes that are not further derived from. Wouldn’t it be great if you could freely define a new class and not have to know about required and convenience initializers? It seems that we should only have to enforce these requirements if you a) further derive from this class within your module, or b) mark the class publicly-derivable-from.

This isn’t a full pitch because I haven’t done a survey of all of the simplifications we could offer, and getting the diagnostics messages right for this would take a significant amount of work (e.g. explaining why "class X needs a required init because class Y started deriving from it”).

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #5

I think that that is a separable issue. Even without final-by-default, we can tell if there are no subclasses within the current module.

-Chris

···

On Mar 1, 2016, at 3:10 AM, David Hart <david@hartbit.com> wrote:

Really looking forward to this. Isn't part of the solution to make classes final by default?


(Thorsten Seitz) #6

I actually like the `convenience`-ness being explicit.

-Thorsten

···

Am 01.03.2016 um 21:04 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

On Feb 29, 2016, at 10:53 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The simplifying observation here is that many classes (particularly in gui apps) are leaf classes that are not further derived from. Wouldn’t it be great if you could freely define a new class and not have to know about required and convenience initializers? It seems that we should only have to enforce these requirements if you a) further derive from this class within your module, or b) mark the class publicly-derivable-from.

I think we could avoid an explicit need for initializer decorations in most private or internal (a) cases too, since we have visibility into the entire class hierarchy. We could raise errors when specific subclasses don't provide `required` initializers, and infer the `convenience`-ness of each initializer from whether it `self.init` or `super.init` delegates. For non-publicly-subclassable classes there are no API liabilities to be concerned about.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution