[swift-evolution] [Review] SE-0159: Fix Private Access Levels

Charles Srstka cocoadev at charlessoft.com
Mon Mar 27 12:47:15 CDT 2017


> On Mar 27, 2017, at 12:00 PM, Ross O'Brien via swift-evolution <swift-evolution at swift.org> wrote:
> 
> I'm considering this from a different angle.
> 
> When we declare a type, we declare properties and functions which that type has.
> When we extend a type, we add functions to the type. (I'm including computed properties in this.)
> It's become an idiom of Swift to declare an extension to a type for each protocol we want it to conform to, for reasons of code organisation and readability. This may be true even if conformance to the protocol was a primary intent of creating the type in the first place.
> 
> The intent of the scoped access level is to allow programmers to create properties and functions which are limited to the scope of their declaration. A protocol conformance can be written, with the aid of helper functions, in the confidence that the helper functions are not visible outside the extension, minimising their impact on other components of the module.
> However, some protocol conformances require the type to have a specific property, which the extension cannot facilitate. Some protocol conformances don't require a property, but it would be really useful to have one, and again an extension can't facilitate.
> 
> Example: we want to be able to write this, but we can't:
> private protocol Bar
> {
>   var integer : Int { get }
>   func increment()
> }
> 
> struct Foo
> {
> }
> 
> extension Foo : Bar
> {
>   var integer : Int
> 
>   private var counter : Int
>   func increment()
>   {
>     counter += 1
>   }
> }
> 
> This leads to a workaround: that properties are added to the original type, and declared as fileprivate. They're not intended to be visible to any scope other than the conforming extension - not even, really, to the type's original scope.
> 
> Continuing the example: we've compromised and written this:
> private protocol Bar
> {
>   var integer : Int { get }
>   func increment()
> }
> 
> struct Foo
> {
>   fileprivate var integer : Int
>   fileprivate var counter : Int
> }
> 
> extension Foo : Bar
> {
>   func increment()
>   {
>     counter += 1
>   }
> }
> 
> This is not a fault of fileprivate (though it's a clunky name), or private. Renaming these levels does not solve the problem. Removing private, such that everything becomes fileprivate, does not solve the problem. The problem is in the extension system.
> (At this point I realise I'm focusing on one problem as if it's the only one.)
> 
> Supposing we approached extensions differently. I think around SE-0025 we were considering a 'nested' access level.
> 
> Supposing we created a 'conformance region' inside a type declaration - a scope nested within the type declaration scope - and that this conformance region had its own access level. It's inside the type declaration, not separate from it like an extension, so we can declare properties inside it. But literally the only properties and functions declared inside the region but visible anywhere outside of it, would be properties and functions declared in the named protocol being conformed to.
> 
> So, visually it might look like this:
> 
> private protocol Bar
> {
>   var integer : Int { get }
>   func increment()
> }
> 
> struct Foo
> {
>   conformance Bar // or conformance Foo : Bar, but since the region is inside Foo that's redundant
>   {
>     var integer : Int // visible because Foo : Bar, at Bar's access level
> 
>     var counter : Int = 0 // only visible inside the conformance scope, because not declared in Bar
> 
>     func increment() // visible because Foo : Bar, at Bar's access level
>     {
>       counter += 1
>     }
>   }
> }
> 
> I've introduced a new keyword, conformance, though it may be clear enough to keep using extension inside a scope for this. Foo still conforms to Bar, in the same file. We've removed 'extension Foo :' and moved a '}' for this, but that's not a breaking change as this is an addition. Readability is compromised to the extent that this conformance is indented one level.
> 
> I've not long had the idea. It's a different approach and may be worth a discussion thread of its own for - or someone might point out some glaringly obvious flaw in it. If it's useful, I don't know the full implications this would have, such as how much this would reduce the use of fileprivate (e.g. to none, to the minimal levels expected in SE-0025, or no effect at all). It's just intended to remove a problem which fileprivate is applied as a bad workaround for.

+1. Creates a mechanism that actually makes sense for what people are using ‘extension’ for, solves the scoping problems, eliminates the need for fileprivate, solves all the problems that people are complaining about.

You could also enforce it by disallowing a ‘conformance’ block from containing any non-private methods that don’t work towards implementing the protocol.

Charles

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170327/17e89c3e/attachment.html>


More information about the swift-evolution mailing list