[swift-evolution] [Draft] Allow declaration of abstract functions and properties on classes

Evan Maloney emaloney at gilt.com
Thu Feb 25 16:04:16 CST 2016


> On Feb 25, 2016, at 4:03 PM, Brent Royal-Gordon <brent at architechies.com> wrote:
> 
>> How can the compiler enforce that the developer supplies a delegate?
> 
> By making the delegate/closure property non-optional, the compiler can ensure that there is always a valid delegate/closure set. The property would have to be initialized, so presumably the initializer would have to take the delegate/closure as a parameter.

That way would work if you forced every initializer in the class to accept a parameter representing each and every function you want to declare abstract. And it just gets messier from there, since if you wanted to do the same for get/set abstract properties, you'd need to model both the getter and setter separately, so for those you have 2 parameters.

If you have 2 abstract functions and 3 abstract get/set properties you want to model, you've just added 8 new parameters that you must pass to each one of your class's initializers.

> (If you're willing to accept a little less compile-time safety to get more convenience, the property could be either an implicitly unwrapped optional or be marked @deferred using the upcoming behaviors feature. That would, for instance, make it possible to set this up entirely in Interface Builder without making a subclass just to override the initializer.)

Once you go with an implicitly unwrapped optional, you don't get less compile-time safety, you get none. All bugs are surfaced at runtime.

It's one of the reasons we don't use Interface Builder with our Swift codebase. IB is an end-run around many of the compile-time safety features that make Swift great.

>> Show me how to do that in a way that enforces the developer supply an implementation. I don't see how it can be done, and if it can, it's certainly going to be far more convoluted than an abstract class.
> 
> I showed an outline of it a couple paragraphs down:

Sorry, you did; my response was a bit imprecise because I failed to describe the exact scenario I was talking about.

>> 	protocol ActivityViewControlling: class {
>> 		func retrieveText() -> String
>> 	}
>> 	extension ActivityViewControlling where Self: UIViewController {
>> 		...
>> 	}
>> 	class MyActivityViewController: UIViewController, ActivityViewControlling {
>> 		func retrieveText() -> String { ... }
>> 	}

Obviously, by explicitly stating conformance to a protocol, you must provide an implementation of whatever is declared in that protocol. As long as you remember to explicitly declare conformance to that protocol. What I'm looking for adds safety by removing the requirement that the developer remember to explicitly declare conformance to a protocol and then supply an implementation.

Now that I think about it, what I'm talking about is pretty much the same behavior as the 'required' keyword with classes, but for things that aren't initializers.

What I want is:

- By virtue of a class being an abstract class of type Foo, you (or a superclass that descends from Foo) must supply an implementation of the abstract interface

Protocol-based solutions give you:

- By virtue of something being a class, if you explicitly conform to protocol Foo you must supply declarations for that protocol's interface

The other problem with the protocol-based solution is that it leads to conceptual leakage. The protocol you need to declare lives outside the class(es) that need it.

The ActivityViewControlling protocol is now available universally, even though it's interface is only relevant to a certain portion the class hierarchy.

> You're right that this is currently somewhat convoluted (and someone else mentioned that the extension members may not override the inherited ones, which is obviously another problem). But I think protocols are actually pretty close to what you want already, and we're better off extending them to cover abstract class use cases than extending classes.

All the gymnastics above could be solved with a simple keyword.

Don't get me wrong, I love protocols. When I saw Dave Abraham's Protocol-Oriented Programming talk, it was an eye-opening experience, like when I finally understood C++ after coming from C.

For anyone who hasn't watched it, here it is:

https://developer.apple.com/videos/play/wwdc2015/408/

But the fact is, classes exist in Swift, too. And some of the solutions classes require might be orthogonal from protocols, which solve a different problem.

In this particular case, I think trying to use protocols for something that's inherently tied to class inheritance leads to more convoluted, more confusing, and less clear code. It's a square peg/round hole problem.

I think the fundamental question is: do we see classes as first-class citizens in Swift? Or were classes merely added to placate existing Objective-C developers and/or ensure interoperability with legacy code?

If classes are first-class citizens, then I think a class-based solution to a class-only use-case is warranted.



More information about the swift-evolution mailing list