> On Feb 15, 2017, at 5:52 AM, Jeremy Pereira <[email protected]> > wrote: > > >> On 15 Feb 2017, at 02:16, Xiaodi Wu via swift-evolution >> <[email protected]> wrote: >> >> So, perhaps I'm being simplistic here, but-- >> >> At the end of the day, aren't we simply trying to enable a resiliency >> feature? Could it not be said that an enum where future added cases aren't >> source-breaking is a more resilient enum? >> >> Since there is consensus that the status quo is desirable for a lot of use >> cases, couldn't we keep spelling it "public enum" and just spell this >> proposed more resilient enum "@resilient public enum”? > > If it’s got to be done, this is the best solution, but to my mind, it > shouldn’t be done at all. > > There is no way that a library designer can possibly determine what > constitutes “resilient” behaviour on the part of the client software. Maybe > adding a default clause is the right thing, but maybe the default clause does > something that it shouldn’t for some new enumeration cases. As the client > software designer, my only defence is an exhaustive switch statement that > relies on the compiler to tell me the it is no longer exhaustive. Yes, it > means software in the field will crash until I distribute a new version but > that is often preferable to other silent consequences. I really do not want > to be forced to add a default to a switch that might reduce the safety of my > software. > > Adding new cases to any enumeration where the client software is meant to > take different actions based on the different cases is source breaking. End > of story. No point in trying to mark them as resilient. > > Adding cases to enumerations that are meant to be passed in to the library > e.g. an enumeration that specifies a compositing operation or a string > encoding may well not be source breaking (how can you tell in every case?) > but it’s unlikely that the client is going to be testing those enumerations > in a switch statement anyway.
In order to support adding cases to enums meant to be passed in to a library we have to introduce some kind of syntax to distinguish these enums from enums that are not resilient. We’ve been discussing options for how to do this. > > > >> On Tue, Feb 14, 2017 at 10:09 Matthew Johnson via swift-evolution >> <[email protected]> wrote: >> >>> On Feb 14, 2017, at 3:43 AM, Brent Royal-Gordon <[email protected]> >>> wrote: >>> >>>> On Feb 13, 2017, at 7:45 AM, Matthew Johnson <[email protected]> >>>> 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` >> >> I agree that `fixed` (and `closed`) don’t imply `public` in terms of the >> colloquial meaning of the words and there is a reasonable case that `open` >> does. I’m not sure I like `exposed`, but maybe it’s possible to find a >> keyword that would more directly imply `public`. >> >>> , but I'm not sure we want to make this feature so prominent, >> >> I have some trouble getting on board with requiring an annotation *in >> addition* to `public` for the reasons I have already stated, and which led >> to `open` becoming an access modifier rather than an annotation. It’s >> possible I could be convinced otherwise, but I think it would require data >> showing that this really is a rare edge case. If the relatively frequency >> of closed vs resilient enums is reasonably similar to the relative frequency >> of public vs open enums I think there is a strong case to make them carry >> the same syntactic weight, as we did with `open`. >> >>> 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`?) >> >> >> Can you elaborate on what you mean by "classes you want to both expose and >> permit subclassing of”? Do you mean commit to the set of fields being fixed >> like you indicated with a struct? If so, I’m not sure that is a valuable >> combination and my instinct is to ban it. >> >> If we did want to support something like that it points to keeping `closed` >> (as in cases, subclasses and conformances) orthogonal to `fixed` (as in the >> set of stored properties). >> >>> >>>>> 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. >> >> This assumes that switching over conforming types is bad style. One of the >> biggest problems with switching over subclasses or conforming types is the >> fact that you don’t get compiler verification of exhaustiveness. If the >> language supports exhaustive switching for closed classes and protocols this >> becomes a non-issue. >> >> I don’t know of any languages that support a kind of type which supports >> generic and dynamic dispatch as well as exhaustive switch. It may be >> interesting to have the ability to organize some methods by type (i.e. >> protocol requirements) and other methods by function (i.e. a protocol >> extension method with an exhaustive switch). >> >> When you have exhaustive switch these are really just two different ways to >> organize code. Neither one is inherently better. Each has strengths >> different strengths. Why not allow the language to support both and let >> programmers decide which organization of their code is best in a particular >> case? >> >>> >>>>> 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. >> >> I think this hits on the basis of our disagreement. Is it really the case >> that *most* existing `public` enums should probably not be `@fixed`? Have >> you done an analysis to support this? Not just of the standard library, but >> also Apple’s frameworks and open source modules on Github? We might learn >> something interesting by doing an analysis like this. It certainly wouldn’t >> hurt. >> >> If it turns out that closed / fixed is *often* (say 30-40% of the cases or >> more) the desirable contract using an annotation would result in noisy >> boilerplate. >> >> On the other hand, if it turns out to be relatively rare (say 5-10%) it >> would become easier to forget the annotation, making an error of omission. >> Of course that error can be corrected pretty easily so maybe we it wouldn’t >> be a big deal if it really is rare. >> >>> >>> -- >>> Brent Royal-Gordon >>> Architechies >>> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution > _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
