[Deferred] SE-0026 Abstract classes and methods


(Joe Groff) #1

The review of SE-0026 "Abstract classes and methods" ran from February 26...March 4, 2016. The proposal has been deferred from Swift 3. Discussion centered around whether abstract classes fit in the direction of Swift as a "protocol-oriented" language. Beyond any religious dogmas, Swift intends to be a *pragmatic* language that lets users get work done. The fact of the matter today is that one of Swift's primary target platforms is the inheritance-heavy Cocoa framework, and that Swift 2's protocols fall short of abstract classes in several respects, including:

- Protocols can require conforming types to provide properties, but extensions cannot instantiate storage into conforming types. Every conforming type must today satisfy a protocol's storage requirements itself.
- Type erasure is easier to accomplish using abstract base classes with generic subclasses. Protocol existentials today only support all-or-nothing type erasure, and don't support protocols with associated type or Self constraints at all.
- Protocols don't support language enforcement of separate implementor and user interfaces, since all of a protocol's requirements must be as visible as the conformance. An abstract base class can expose private or internal abstract requirements to its implementation subclasses while exporting a different interface for external users.
- Protocol extensions can provide default implementations, but there's no equivalent to 'super.' today for a concrete implementation to be able to chain up to a default implementation.

Unfortunately, the core team is currently bandwidth-constrained and can't immediately participate to the degree we'd like in the design of this important feature. Furthermore, "completing generics" is one of our primary goals for Swift 3, and proposals for addressing many of the above limitations with protocols are in various stages of discussion and design. We'd like to revisit this feature once the core goals of Swift 3 have been addressed, so we can more accurately consider its value in the context of a more complete generics implementation, and so we can address the finer points of its design.

Some things to consider for future revision:

An abstract class cannot be instanciated.

This can be prevented in cases when `AbstractClass(...)` is statically spelled, but the behavior of abstract class metatypes must be specified. Is `let classObject: AbstractClass.Type = AbstractClass.self` allowed? Does `let classObject = _typeByName("Module.AbstractClass")` work? If not, then the abstract class object cannot be used for metaprogramming or generic argument binding purposes. If it can be, then there's a static safety hole, since `classObject.init(requiredInitializer:)` would have to dynamically fail if `classObject` refers to an abstract class metatype.

When declaring an abstract property, you must specify which methods must be implemented : get, set, didSet, willSet.

If you do not specify anything, only setter and getter are made abstract as below :

    abstract var url : String

Only 'get' and 'set' are of interest for a property's interface. For consistency with protocol requirements, abstract properties should probably require an explicit '{ get }' or '{ get set }' declaration to indicate whether mutation is expected.

-Joe


(Goffredo Marocchi) #2

Hello Joe,

A few quick questions came to mind after reading your answer, if you do not mind. You mention protocols falling short in some areas to provide part of the functionality that abstract classes provide, but is the concern that we may be making protocols harder and harder to pickup and use correctly by giving them so much responsibility?l

Also, do you think the lines between structs, protocols, and classes going to blend even more with these and other similar changes?

(Although only tangentially related perhaps...) Did the core team stated what they planned to do about pitfalls with dispatching and protocol extensions with default method in extensions being statically dispatched and actual method resolution then being dependent on the type of the reference rather than the instance the reference is pointing at? Is this area being addressed in Swift 3 at all?

Thank you in advance for your answers :).

Kind Regards,

Goffredo

···

Sent from my iPhone

On 7 Mar 2016, at 18:00, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

The review of SE-0026 "Abstract classes and methods" ran from February 26...March 4, 2016. The proposal has been deferred from Swift 3. Discussion centered around whether abstract classes fit in the direction of Swift as a "protocol-oriented" language. Beyond any religious dogmas, Swift intends to be a *pragmatic* language that lets users get work done. The fact of the matter today is that one of Swift's primary target platforms is the inheritance-heavy Cocoa framework, and that Swift 2's protocols fall short of abstract classes in several respects, including:

- Protocols can require conforming types to provide properties, but extensions cannot instantiate storage into conforming types. Every conforming type must today satisfy a protocol's storage requirements itself.
- Type erasure is easier to accomplish using abstract base classes with generic subclasses. Protocol existentials today only support all-or-nothing type erasure, and don't support protocols with associated type or Self constraints at all.
- Protocols don't support language enforcement of separate implementor and user interfaces, since all of a protocol's requirements must be as visible as the conformance. An abstract base class can expose private or internal abstract requirements to its implementation subclasses while exporting a different interface for external users.
- Protocol extensions can provide default implementations, but there's no equivalent to 'super.' today for a concrete implementation to be able to chain up to a default implementation.

Unfortunately, the core team is currently bandwidth-constrained and can't immediately participate to the degree we'd like in the design of this important feature. Furthermore, "completing generics" is one of our primary goals for Swift 3, and proposals for addressing many of the above limitations with protocols are in various stages of discussion and design. We'd like to revisit this feature once the core goals of Swift 3 have been addressed, so we can more accurately consider its value in the context of a more complete generics implementation, and so we can address the finer points of its design.

Some things to consider for future revision:

An abstract class cannot be instanciated.

This can be prevented in cases when `AbstractClass(...)` is statically spelled, but the behavior of abstract class metatypes must be specified. Is `let classObject: AbstractClass.Type = AbstractClass.self` allowed? Does `let classObject = _typeByName("Module.AbstractClass")` work? If not, then the abstract class object cannot be used for metaprogramming or generic argument binding purposes. If it can be, then there's a static safety hole, since `classObject.init(requiredInitializer:)` would have to dynamically fail if `classObject` refers to an abstract class metatype.

When declaring an abstract property, you must specify which methods must be implemented : get, set, didSet, willSet.

If you do not specify anything, only setter and getter are made abstract as below :

    abstract var url : String

Only 'get' and 'set' are of interest for a property's interface. For consistency with protocol requirements, abstract properties should probably require an explicit '{ get }' or '{ get set }' declaration to indicate whether mutation is expected.

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


(David Scrève) #3

Regarding the whole discussion about this topic, I think this decision is really a good one.

  Actually, even Swift source code use abstract classes.

  Thanks to all for this really interesting discussion about this proposal.

···

--
David Scrève - DLTA Studio
Gérant - 06 27 69 58 14
david.screve@dlta-studio.com

Le 7 mars 2016 à 19:00, Joe Groff via swift-evolution <swift-evolution@swift.org> a écrit :

The review of SE-0026 "Abstract classes and methods" ran from February 26...March 4, 2016. The proposal has been deferred from Swift 3. Discussion centered around whether abstract classes fit in the direction of Swift as a "protocol-oriented" language. Beyond any religious dogmas, Swift intends to be a *pragmatic* language that lets users get work done. The fact of the matter today is that one of Swift's primary target platforms is the inheritance-heavy Cocoa framework, and that Swift 2's protocols fall short of abstract classes in several respects, including:

- Protocols can require conforming types to provide properties, but extensions cannot instantiate storage into conforming types. Every conforming type must today satisfy a protocol's storage requirements itself.
- Type erasure is easier to accomplish using abstract base classes with generic subclasses. Protocol existentials today only support all-or-nothing type erasure, and don't support protocols with associated type or Self constraints at all.
- Protocols don't support language enforcement of separate implementor and user interfaces, since all of a protocol's requirements must be as visible as the conformance. An abstract base class can expose private or internal abstract requirements to its implementation subclasses while exporting a different interface for external users.
- Protocol extensions can provide default implementations, but there's no equivalent to 'super.' today for a concrete implementation to be able to chain up to a default implementation.

Unfortunately, the core team is currently bandwidth-constrained and can't immediately participate to the degree we'd like in the design of this important feature. Furthermore, "completing generics" is one of our primary goals for Swift 3, and proposals for addressing many of the above limitations with protocols are in various stages of discussion and design. We'd like to revisit this feature once the core goals of Swift 3 have been addressed, so we can more accurately consider its value in the context of a more complete generics implementation, and so we can address the finer points of its design.

Some things to consider for future revision:

An abstract class cannot be instanciated.

This can be prevented in cases when `AbstractClass(...)` is statically spelled, but the behavior of abstract class metatypes must be specified. Is `let classObject: AbstractClass.Type = AbstractClass.self` allowed? Does `let classObject = _typeByName("Module.AbstractClass")` work? If not, then the abstract class object cannot be used for metaprogramming or generic argument binding purposes. If it can be, then there's a static safety hole, since `classObject.init(requiredInitializer:)` would have to dynamically fail if `classObject` refers to an abstract class metatype.

When declaring an abstract property, you must specify which methods must be implemented : get, set, didSet, willSet.

If you do not specify anything, only setter and getter are made abstract as below :

    abstract var url : String

Only 'get' and 'set' are of interest for a property's interface. For consistency with protocol requirements, abstract properties should probably require an explicit '{ get }' or '{ get set }' declaration to indicate whether mutation is expected.

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


(Joe Groff) #4

Hello Joe,

A few quick questions came to mind after reading your answer, if you do not mind. You mention protocols falling short in some areas to provide part of the functionality that abstract classes provide, but is the concern that we may be making protocols harder and harder to pickup and use correctly by giving them so much responsibility?l

There's always a tradeoff between power and complexity. Some discussions have proposed separating "mixins" from protocol extensions as a more clearly delineated feature for composing storage and associated functionality into objects, which would offload some of the responsibility from protocols.

Also, do you think the lines between structs, protocols, and classes going to blend even more with these and other similar changes?

(Although only tangentially related perhaps...) Did the core team stated what they planned to do about pitfalls with dispatching and protocol extensions with default method in extensions being statically dispatched and actual method resolution then being dependent on the type of the reference rather than the instance the reference is pointing at? Is this area being addressed in Swift 3 at all?

It's something we'd like to address, yes. Two options that have been discussed are to provide better diagnostics for the current behavior, or to make extension methods dynamically dispatched themselves.

-Joe

···

On Mar 7, 2016, at 10:10 AM, Goffredo Marocchi <panajev@gmail.com> wrote: