[swift-evolution] [Pitch] consistent public access modifiers

Matthew Johnson matthew at anandabits.com
Wed Feb 15 13:30:45 CST 2017


> On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon <brent at architechies.com> wrote:
> 
>> On Feb 13, 2017, at 7:45 AM, Matthew Johnson <matthew at anandabits.com> wrote:
>> 
>> If you look closely, when most people say “closed enum” they mean a fixed, complete set of cases that are all public.  But when people say “closed protocol” they don’t actually mean a fixed, complete set of conformances that are all public.  They simply mean clients cannot add conformances.  This is the semantic contract of resilient enums, not closed enums.
> 
> Yes, our traditional terminology here has been a little bit confused.
> 
>>> What I instead suggest is that we think of a closed enum as being like a fragile (non-resilient) struct. In both cases, you are committing to a particular design for the type. So I think we should give them both the same keyword—something like:
>>> 
>>> 	@fixed struct Person {
>>> 		var name: String
>>> 		var birthDate: Date
>>> 	}
>>> 	@fixed enum Edge {
>>> 		case start
>>> 		case end
>>> 	}
>>> 
>> 
>> You omitted public here.  Does that mean you intend for `@fixed` to imply public visibility?  If so, I could get behind this.  But I am curious why you made it an attribute rather than a keyword.
> 
> No, I'm sorry, I meant to say `@fixed public struct` and `@fixed public enum`. I don't think `@fixed` implies public-ness, either, so it would need to be paired with a `public` keyword. There *may* be keywords we could use that would, like `exposed`, but I'm not sure we want to make this feature so prominent, and I'm not sure how that would work with classes you want to both expose and permit subclassing of. (Would that be `exposed open class Foo`?)

I thought of a couple of other possible keywords.  I had previously mentioned `complete` as an alternative to `closed`.  Another option that goes in this direction is `total` - it borrows from the mathematical notion of a total function.  I’m not sure how I feel about this option and it still doesn’t necessarily imply “more public than public” very strongly (only in the sense that its totality is known to all which is a rather weak sense).

Another possibility is `transparent`.  This does imply “more public than public” a some sense that is similar to `open`.  I know `@transparent` (or something like that) has been used as an unsupported(?) attribute hinting to the compiler that a function should be made available for inlining (what is the current status of this?).  The meaning of this attribute is in some ways similar to the meaning you ascribe to `fixed`.  In all cases, this is only meaningful for `public` entities so it feels like a promising direction.  

The one thing that makes me somewhat uncomfortable with this approach is that in the context of structs and functions it has no semantic impact on user code - it is only an optimization, while for enums it wold make a important semantic difference to user code.  I’m not sure we should use the same syntax for something that is sometimes an optimization and sometimes is semantically meaningful.  This concern is relevant regardless of what the keyword is called.

> 
>>> I don't see it mentioned here (maybe I just missed it), but even though we *could* do exhaustiveness checking on non-open protocols, I'm not convinced that's a good idea. Usually when you have several types conforming to a protocol, you should access type-specific behavior through polymorphism, not by switching on the protocol. A protocol is supposed to represent a behavior, not just mark a type in some arbitrary way.
>> 
>> I agree that you should usually be adding polymorphism, but preventing exhaustive switch on what is effectively a style argument seems like an unnecessary restriction to me.  There will be times when it could be used to good effect.  I think the community has done a pretty good job of figuring out how to use Swift’s many features well and don’t believe it would be frequently abused.
> 
> I agree we shouldn't change the language to *prevent* bad style. But this would go beyond that—we'd be putting specific engineering effort solely into *enabling* bad style. At minimum, this should fall so far down our to-do list that we'll probably never get to it.
> 
>>> I still support this general approach. One spelling could simply be `@nonopen`. Although if we don't use `closed`, we could simply use `@closed` like I suggested—here it really *would* be an antonym to `open`.
>> 
>> I like the idea of using `@nonopen` for the transitional attribute.  Both because it “removes the openness” that `public protocol` currently implies.  In that sense it is probably the most accurate term we could find and it’s also pretty concise.
> 
> It also sounds a little bit awkward, which is normally a reason not to use it, but perhaps that's actually a good thing in a temporary, transitional keyword.
> 
>>>> A similar mult-release strategy would work for migrating public enums.
>>> 
>>> What is it that needs migrating here? Lack of exhaustiveness checking? It sounds like we were planning to break that anyway in some fashion.
>> 
>> Public enums are not currently resilient.  Clients are allowed to switch over them without a `default` clause.  This means that client code will fail to compile in a version of Swift where `public enum` has the resilient contract unless the library changes to adopt closed semantics or the client adds a default case.
> 
> My thinking was that, since most existing `public` enums should probably not be `@fixed`, we should just change the behavior and let some switch statements break.  Most `public` protocols, on the other hand, ought to become `open`, so we should flag that change and require an explicit marker like `@nonopen` if you really don't want to change over. But I could be convinced otherwise.
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 



More information about the swift-evolution mailing list