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

Pierre Monod-Broca pierre at monod-broca.fr
Thu Feb 25 06:08:37 CST 2016


+1 to Brent

> Le 25 févr. 2016 à 02:27, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> a écrit :
> 
>> Unfortunately, the protocol does not cover all of the cases where a developer might want to specify an interface to be implemented by another entity.
>> 
>> For example, consider the class, which allows the creation of an inheritance hierarchy. Often, a class in a hierarchy exists merely to provide a common implementation to subclasses. Such classes aren't ever intended to be instantiated directly; only subclasses will be instantiated.
>> 
>> To illustrate the point, imagine a view controller class that:
>> 
>> 	• Places an animating UIActivityIndicatorView onscreen
>> 	• Performs some operation to retrieve some text
>> 	• Puts the text in a UITextView and places it onscreen
>> 	• Hides the UIActivityIndicatorView
>> Now imagine you had many cases in your application where you could benefit from such a view controller, and each case differed only in the operation required to retrieve the text (represented by Step 2 above).
>> 
>> Ideally, you would be able to achieve this by declaring the interface for a function without needing to specify an implementation, the same way you would with a protocol:
>> 
>> func retrieveText() -> String
>> In other languages, such as C++, this concept exists in the form of an abstract class. However, Swift does not support this, so developers are forced to provide useless implementations such as:
>> 
>> func retrieveText() -> String
>> 
>> {
>>    fatalError(
>> "Subclasses must implement retrieveText()"
>> )
>> }
>> 
>> The idea here is that subclasses should always provide a retrieveText() implementation, and therefore the call to fatalError() should never be hit.
>> 
>> This has a few significant downsides:
>> 
>> 	• It forces the developer to write code that should never be executed under normal conditions. This seems like a waste.
>> 
>> 	• Because a default implementation is provided--the one that calls fatalError()--the compiler has no way of knowing that the subclasses are supposed to provide an implementation, too.
>> 
>> 	• If a subclass implementor forgets to provide a retrieveText() function, the error will not be caught until runtime, and not until a user navigates to the affected portion of the application. This may not occur until the application has shipped.
> 
> That's one alternative, yes. Others include:
> 
> 1. Having a delegate provide the `retrieveText()` method.
> 
> 2. Having a closure property implement the `retrieveText()` method.
> 
> 3. Declaring a protocol `ActivityViewControlling` that requires `retrieveText()` and adding the other logic in an `extension ActivityViewControlling where Self: UIViewController`.
> 
> I think that 1 or 2 are usually the best way to handle something like this, but let's explore 3 for a minute, because that's a place where Swift could probably be improved.
> 
> Currently, Swift allows you to constrain a protocol to only class types:
> 
> 	protocol ActivityViewControlling: class {
> 		func retrieveText() -> String
> 	}
> 	extension ActivityViewControlling where Self: UIViewController {
> 		...
> 	}
> 	class MyActivityViewController: UIViewController, ActivityViewControlling {
> 		func retrieveText() -> String { ... }
> 	}
> 
> But when you do that, Swift permits you to use any class type, which is a bit weird semantically—ActivityViewControlling can be applied to any class, but it's really only meant to be applied to subclasses of UIViewController. An ActivityViewControlling type which isn't a view controller is kind of meaningless.
> 
> 	// Why can I do this?
> 	class PossibleButUseless: ActivityViewControlling {
> 		func retrieveText() -> String { ... }
> 	}
> 
> Suppose instead we allow a protocol to require that the conforming class inherit from another class. We could then omit the `where` clause and possibly even make the inheritance itself implicit in conforming to the protocol:
> 
> 	protocol ActivityViewControlling: UIViewController {
> 		func retrieveText() -> String
> 	}
> 	extension ActivityViewControlling {
> 		...
> 	}
> 	class MyActivityViewController: ActivityViewControlling {
> 		func retrieveText() -> String { ... }
> 	}
> 
> This would also relieve some of the pressure on us to support class-plus-protocol typed variables. In many of these cases, *all* types conforming to the protocol should be subclasses of a particular class, but there's no way to express that in the type system. Subclass-only protocols would correct that shortcoming.
> 
> Subclass-only protocols would cover most, if not all, of the use cases of abstract classes, but I think they would be a less dramatic change to Swift, because protocols are already types which can't be instantiated and impose requirements on their subtypes. I therefore believe they would be a better, more Swift-like approach to the problem abstract classes are trying to solve.
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list