Abstract methods

How many "subclass must override" assertions or comments in base class methods do we need to see, to want to add "abstract" to the Swift language? 5? 50? 500?

It's a not uncommon idiom in Objective-C.

I'm about to port a substantial amount of C++ code to swift, and compiler help to enforce abstract classes would be very useful.

···

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

Abstract methods and classes seem like they will introduce a fair amount of complexity in the type checker, particularly around metatypes and constructors, because now we have this new concept of a class that cannot be directly instantiated. I’m not sure the cost is worth the benefit.

Slava

···

On Nov 2, 2017, at 12:45 PM, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

How many "subclass must override" assertions or comments in base class methods do we need to see, to want to add "abstract" to the Swift language? 5? 50? 500?

It's a not uncommon idiom in Objective-C.

I'm about to port a substantial amount of C++ code to swift, and compiler help to enforce abstract classes would be very useful.

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

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

Swift architectures use much less inheritance (and class types) in general than equivalent c++ architectures. personally i have never been in a situation where i didn’t need a pure abstract method that was better declared as a protocol requirement.

···

On Nov 2, 2017, at 2:45 PM, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

How many "subclass must override" assertions or comments in base class methods do we need to see, to want to add "abstract" to the Swift language? 5? 50? 500?

It's a not uncommon idiom in Objective-C.

I'm about to port a substantial amount of C++ code to swift, and compiler help to enforce abstract classes would be very useful.

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

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

1 Like

Swift does still have inheritance, though. A language with inheritance and not abstract is frustrating to use, as evidenced by the hacks people resort to for Objective-C.

If we wanted to steer people away from inheritance then maybe we shouldn’t have supported it at all, but it’s a bit late for that.

···

On Nov 2, 2017, at 1:57 PM, Taylor Swift via swift-evolution <swift-evolution@swift.org> wrote:

Swift architectures use much less inheritance (and class types) in general than equivalent c++ architectures. personally i have never been in a situation where i didn’t need a pure abstract method that was better declared as a protocol requirement.

On Nov 2, 2017, at 2:45 PM, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

How many "subclass must override" assertions or comments in base class methods do we need to see, to want to add "abstract" to the Swift language? 5? 50? 500?

It's a not uncommon idiom in Objective-C.

I'm about to port a substantial amount of C++ code to swift, and compiler help to enforce abstract classes would be very useful.

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

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

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

1 Like

If a class partially implemented a protocol, it also would not be instantiatable, but a subclass can supply the missing method(s). Doesn’t the compiler already handle that? How are abstract classes harder?

C. Keith Ray
https://leanpub.com/wepntk <- buy my book?
http://agilesolutionspace.blogspot.com/
twitter: @ckeithray
http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

···

On Nov 2, 2017, at 2:22 PM, Slava Pestov <spestov@apple.com> wrote:

Abstract methods and classes seem like they will introduce a fair amount of complexity in the type checker, particularly around metatypes and constructors, because now we have this new concept of a class that cannot be directly instantiated. I’m not sure the cost is worth the benefit.

Slava

On Nov 2, 2017, at 12:45 PM, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

How many "subclass must override" assertions or comments in base class methods do we need to see, to want to add "abstract" to the Swift language? 5? 50? 500?

It's a not uncommon idiom in Objective-C.

I'm about to port a substantial amount of C++ code to swift, and compiler help to enforce abstract classes would be very useful.

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

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

I think we should beef up protocols a little bit so that they can serve the role of abstract classes. That would make for a nice, clean separation: anything abstract is a protocol, while anything concrete is a class (or struct or enum).

What would protocols need in order to support everything abstract classes can do? First, we'd probably need to extend class constraints to allow a protocol to require you to subclass a given base class:

  // Hypothetical replacement for UIControl.
  protocol UIControl: UIView {
    func sendAction(_ action: Selector, to target: Any?, for event: UIEvent)
  }

  extension UIControl {
    func sendAction(_ action: Selector, to target: Any?, for event: UIEvent) {
      UIApplication.shared.sendAction(action, to: target, from: self, for: event)
    }
  }

Maybe allow them to declare automatically-added storage, perhaps even private to the protocol:

  protocol UIControl: UIView {
    @automatic
    private var actions: [UIControlEvents: [(target: Any?, action: Selector)]] = [:]
    
    func sendAction(_ action: Selector, to target: Any?, for event: UIEvent)
  }

  extension UIControl {
    func sendActions(for controlEvents: UIControlEvents) {
      for (event, pairs) in actions where event.contains(controlEvents) {
        for pair in pairs {
          sendAction(pair.action, to: pair.target, for: UIApplication.shared.currentEvent)
        }
      }
    }
    
    func sendAction(_ action: Selector, to target: Any?, for event: UIEvent) {
      UIApplication.shared.sendAction(action, to: target, from: self, for: event)
    }
  }

Probably something like `super` for when you want to override a default implementation but still call it:
    
  class MyButton: UIControl {
    func sendAction(_ action: Selector, to target: Any?, for event: UIEvent) {
      print("Sending \(action) to \(target)")
      super(UIControl).sendAction(action, to: target, for: event)
    }
  }

These are all solid features that would be great additions to protocols, even when they're *not* replacing abstract classes.

···

On Nov 2, 2017, at 1:57 PM, Taylor Swift via swift-evolution <swift-evolution@swift.org> wrote:

Swift architectures use much less inheritance (and class types) in general than equivalent c++ architectures. personally i have never been in a situation where i didn’t need a pure abstract method that was better declared as a protocol requirement.

--
Brent Royal-Gordon
Architechies

How would a class partially implement a protocol? That’s a compile error.

···

On Nov 2, 2017, at 2:30 PM, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

If a class partially implemented a protocol, it also would not be instantiatable, but a subclass can supply the missing method(s). Doesn’t the compiler already handle that? How are abstract classes harder?

C. Keith Ray
https://leanpub.com/wepntk <- buy my book?
http://agilesolutionspace.blogspot.com/
twitter: @ckeithray
http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

On Nov 2, 2017, at 2:22 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Abstract methods and classes seem like they will introduce a fair amount of complexity in the type checker, particularly around metatypes and constructors, because now we have this new concept of a class that cannot be directly instantiated. I’m not sure the cost is worth the benefit.

Slava

On Nov 2, 2017, at 12:45 PM, C. Keith Ray via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

How many "subclass must override" assertions or comments in base class methods do we need to see, to want to add "abstract" to the Swift language? 5? 50? 500?

It's a not uncommon idiom in Objective-C.

I'm about to port a substantial amount of C++ code to swift, and compiler help to enforce abstract classes would be very useful.

--
C. Keith Ray
Senior Software Engineer / Trainer / Agile Coach
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

2 Likes

That would be great.

Back in the day, the proposal SE-0026 "Abstract classes and methods" was deferred, with the following rationale: https://lists.swift.org/pipermail/swift-evolution-announce/2016-March/000056.html

This rationale is great because it lists a few use cases for abstract class that protocols can't mimic today.

Gwendal

···

Le 3 nov. 2017 à 04:29, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> a écrit :

I think we should beef up protocols a little bit so that they can serve the role of abstract classes.

Swift architectures use much less inheritance (and class types) in general than equivalent c++ architectures. personally i have never been in a situation where i didn’t need a pure abstract method that was better declared as a protocol requirement.

I think we should beef up protocols a little bit so that they can serve the role of abstract classes. That would make for a nice, clean separation: anything abstract is a protocol, while anything concrete is a class (or struct or enum).

What would protocols need in order to support everything abstract classes can do? First, we'd probably need to extend class constraints to allow a protocol to require you to subclass a given base class:

  // Hypothetical replacement for UIControl.
  protocol UIControl: UIView {
    func sendAction(_ action: Selector, to target: Any?, for event: UIEvent)
  }

This is planned, and in fact was part of the “subclass existentials” proposal that was otherwise implemented in Swift 4. The absence of this feature should be considered a bug, and something I’d like to fix eventually.

Maybe allow them to declare automatically-added storage, perhaps even private to the protocol:

I’m not sure this really fits with the conceptual model of what a protocol is. Protocols define requirements, they don’t “add” things to the conforming type. It seems that allowing protocols to declare stored properties would bring many of the complications of multiple inheritance from an implementation standpoint. Also how would retroactive conformance work? Would you just be able to change the size of any public type in any other framework? This would have major implications for code generation and the optimizer.

In general I’m not convinced this is a useful feature.

Probably something like `super` for when you want to override a default implementation but still call it:

This is a good idea. I think it would be pretty straightforward to implement, and it’s something that keeps coming up. We haven’t come up with a nice unambiguous syntax for it yet.

Slava

···

On Nov 2, 2017, at 8:29 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 2, 2017, at 1:57 PM, Taylor Swift via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

1 Like

If protocols can (1) store data (2) implement methods (3) force "subclasses" to implement methods, then I'm ok that it isn't spelled "abstract". And yes, I know 2 and 3 done.

···

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Nov 2, 2017, at 10:07 PM, Gwendal Roué via swift-evolution <swift-evolution@swift.org> wrote:

Le 3 nov. 2017 à 04:29, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> a écrit :

I think we should beef up protocols a little bit so that they can serve the role of abstract classes.

That would be great.

Back in the day, the proposal SE-0026 "Abstract classes and methods" was deferred, with the following rationale: https://lists.swift.org/pipermail/swift-evolution-announce/2016-March/000056.html

This rationale is great because it lists a few use cases for abstract class that protocols can't mimic today.

Gwendal

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

self.P::method() ?

It could be used for calling a specific implementation from superclasses too...

Thanks,
Jon

···

On Nov 3, 2017, at 10:26 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

Probably something like `super` for when you want to override a default implementation but still call it:

This is a good idea. I think it would be pretty straightforward to implement, and it’s something that keeps coming up. We haven’t come up with a nice unambiguous syntax for it yet.

Protocols define requirements, they don’t “add” things to the conforming type

I agree with this, but then this warrants a change for protocol extensions too. Would you be happy with the restriction that default method implementations are only available for value types and not for classes (as structs cannot share code any other way, it is the argument for that I seem to recall)?

···

Sent from my iPhone

On 4 Nov 2017, at 05:26, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

I mostly miss this (a.k.a. protected methods):

"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.“

-Thorsten

···

Am 03.11.2017 um 06:07 schrieb Gwendal Roué via swift-evolution <swift-evolution@swift.org>:

Le 3 nov. 2017 à 04:29, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> a écrit :

I think we should beef up protocols a little bit so that they can serve the role of abstract classes.

That would be great.

Back in the day, the proposal SE-0026 "Abstract classes and methods" was deferred, with the following rationale: https://lists.swift.org/pipermail/swift-evolution-announce/2016-March/000056.html

This rationale is great because it lists a few use cases for abstract class that protocols can't mimic today.

Gwendal

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

(Though calling "super" and Implementing non-public methods would round out "protocol as abstract class" functionality.)

···

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Nov 3, 2017, at 8:33 AM, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

If protocols can (1) store data (2) implement methods (3) force "subclasses" to implement methods, then I'm ok that it isn't spelled "abstract". And yes, I know 2 and 3 done.

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Nov 2, 2017, at 10:07 PM, Gwendal Roué via swift-evolution <swift-evolution@swift.org> wrote:

Le 3 nov. 2017 à 04:29, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> a écrit :

I think we should beef up protocols a little bit so that they can serve the role of abstract classes.

That would be great.

Back in the day, the proposal SE-0026 "Abstract classes and methods" was deferred, with the following rationale: https://lists.swift.org/pipermail/swift-evolution-announce/2016-March/000056.html

This rationale is great because it lists a few use cases for abstract class that protocols can't mimic today.

Gwendal

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

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

An abstract base class can expose private or internal abstract requirements to its implementation subclasses while exporting a different interface for external users.

I think what you want for this is real orthogonality of access rights (being able to declare a method that can’t be called, but just overridden) — but I fear this option died with „open“, and the topic is scorched earth for the next years

Sent from my iPhone

Protocols define requirements, they don’t “add” things to the conforming type

I agree with this, but then this warrants a change for protocol extensions too. Would you be happy with the restriction that default method implementations are only available for value types and not for classes (as structs cannot share code any other way, it is the argument for that I seem to recall)?

Protocol extensions are in some sense just syntax sugar for defining new functions. Having a protocol conformance add storage to the conforming type is fundamentally different.

Slava

···

On Nov 4, 2017, at 1:32 AM, Goffredo Marocchi <panajev@gmail.com> wrote:

On 4 Nov 2017, at 05:26, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

I would say that you kind of already entered a slippery slope when the extension to a protocol can add code / not just declare a behavioural contract and how it changes OOP approach (hence: https://bugs.swift.org/plugins/servlet/mobile#issue/SR-302 and https://bugs.swift.org/browse/SR-103 and https://bugs.swift.org/plugins/servlet/mobile#issue/SR-584)

References:
https://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
https://www.raizlabs.com/dev/2016/12/swift-method-dispatch

···

Sent from my iPhone

On 5 Nov 2017, at 01:08, Slava Pestov <spestov@apple.com> wrote:

On Nov 4, 2017, at 1:32 AM, Goffredo Marocchi <panajev@gmail.com> wrote:

Sent from my iPhone

On 4 Nov 2017, at 05:26, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

Protocols define requirements, they don’t “add” things to the conforming type

I agree with this, but then this warrants a change for protocol extensions too. Would you be happy with the restriction that default method implementations are only available for value types and not for classes (as structs cannot share code any other way, it is the argument for that I seem to recall)?

Protocol extensions are in some sense just syntax sugar for defining new functions. Having a protocol conformance add storage to the conforming type is fundamentally different.

Slava

At least SR-103 is a legitimate bug that we would like to fix one day.

Slava

···

On Nov 5, 2017, at 1:27 AM, Goffredo Marocchi <panajev@gmail.com> wrote:

I would say that you kind of already entered a slippery slope when the extension to a protocol can add code / not just declare a behavioural contract and how it changes OOP approach (hence: https://bugs.swift.org/plugins/servlet/mobile#issue/SR-302 and https://bugs.swift.org/browse/SR-103 and https://bugs.swift.org/plugins/servlet/mobile#issue/SR-584)

References:
https://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
https://www.raizlabs.com/dev/2016/12/swift-method-dispatch <https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/>

Sent from my iPhone

On 5 Nov 2017, at 01:08, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

On Nov 4, 2017, at 1:32 AM, Goffredo Marocchi <panajev@gmail.com <mailto:panajev@gmail.com>> wrote:

Sent from my iPhone

On 4 Nov 2017, at 05:26, Slava Pestov via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Protocols define requirements, they don’t “add” things to the conforming type

I agree with this, but then this warrants a change for protocol extensions too. Would you be happy with the restriction that default method implementations are only available for value types and not for classes (as structs cannot share code any other way, it is the argument for that I seem to recall)?

Protocol extensions are in some sense just syntax sugar for defining new functions. Having a protocol conformance add storage to the conforming type is fundamentally different.

Slava

I think there is a legitimate hole around abstract methods.

I don’t think it really matters whether you’re talking about a class hierarchy or a protocol hierarchy. They’re both providing partial implementations of behaviour, predicated on some other method being implemented. The practical difference is really about Objective-C interop, and how easily you can reason about method dispatch.

Out of interest: what makes this so challenging to the type-checker? I imagine a naïve implementation which flags methods as requiring implementation by a subclass, marking which classes in a hierarchy have unimplemented methods, and making those initialisers not visible (except to subclasses). Subclasses would also be prevented from calling ‘super’ on methods which the superclass doesn’t implement. I mean, the way I see it, if it can understand the concept of a private initialiser, inaccessible outside of the same type, it already knows about classes which you can’t instantiate.

So, roughly I picture this as being a combination of a new visibility level (subclasses only - inferred by the presence of unimplemented abstract methods), plus something which checks all calls to “super” (including initialisers) and makes sure they are implemented. Or is it substantially more complex than that?

- Karl

···

On 6. Nov 2017, at 03:43, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

At least SR-103 is a legitimate bug that we would like to fix one day.

Slava

On Nov 5, 2017, at 1:27 AM, Goffredo Marocchi <panajev@gmail.com <mailto:panajev@gmail.com>> wrote:

I would say that you kind of already entered a slippery slope when the extension to a protocol can add code / not just declare a behavioural contract and how it changes OOP approach (hence: https://bugs.swift.org/plugins/servlet/mobile#issue/SR-302 and https://bugs.swift.org/browse/SR-103 and https://bugs.swift.org/plugins/servlet/mobile#issue/SR-584)

References:
https://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
https://www.raizlabs.com/dev/2016/12/swift-method-dispatch <https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/>

Sent from my iPhone

On 5 Nov 2017, at 01:08, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

On Nov 4, 2017, at 1:32 AM, Goffredo Marocchi <panajev@gmail.com <mailto:panajev@gmail.com>> wrote:

Sent from my iPhone

On 4 Nov 2017, at 05:26, Slava Pestov via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Protocols define requirements, they don’t “add” things to the conforming type

I agree with this, but then this warrants a change for protocol extensions too. Would you be happy with the restriction that default method implementations are only available for value types and not for classes (as structs cannot share code any other way, it is the argument for that I seem to recall)?

Protocol extensions are in some sense just syntax sugar for defining new functions. Having a protocol conformance add storage to the conforming type is fundamentally different.

Slava

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

1 Like

Just jumping in here. There’s definitely a limitation here without abstract classes as in current Swift, you can’t force the compiler to throw an error if a subclass of a base class hasn’t implemented a method. Normally of course the answer is to use Protocol-Oriented programming and move that code to a protocol/extension pair, but that doesn’t work in the case where you’re also dealing with an Objective-C protocol as that forces its implementation to be on a concrete subclass of NSObject (i.e. it forces you from a protocol to a class) and once you’re there, there’s no way to make the compiler warn that a subclass hasn’t implemented something.

Check out my SO question with example code showing this limitation here: https://stackoverflow.com/q/49341529/168179

Currently in Swift, there’s no way to make the compiler warn you. You have to use the runtime check, which isn’t very ‘Swifty’ (to use Lattner’s term.)