> On Dec 21, 2017, at 2:06 PM, John McCall <rjmcc...@apple.com> wrote:
> 
> 
>> On Dec 21, 2017, at 2:41 PM, Matthew Johnson <matt...@anandabits.com 
>> <mailto:matt...@anandabits.com>> wrote:
>> 
>> 
>>> On Dec 21, 2017, at 1:26 PM, John McCall via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>>> 
>>>> On Dec 21, 2017, at 2:03 PM, Jordan Rose via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> 
>>>> 
>>>>> On Dec 20, 2017, at 12:35, Karl Wagner <razie...@gmail.com 
>>>>> <mailto:razie...@gmail.com>> wrote:
>>>>> 
>>>>> 
>>>>> 
>>>>>> On 20. Dec 2017, at 19:54, Jordan Rose <jordan_r...@apple.com 
>>>>>> <mailto:jordan_r...@apple.com>> wrote:
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Dec 20, 2017, at 05:36, Karl Wagner via swift-evolution 
>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>>> On 19. Dec 2017, at 23:58, Ted Kremenek via swift-evolution 
>>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>>>>> 
>>>>>>>> The review of "SE 0192 - Non-Exhaustive Enums" begins now and runs 
>>>>>>>> through January 3, 2018.
>>>>>>>> 
>>>>>>>> The proposal is available here:
>>>>>>>> 
>>>>>>>> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
>>>>>>>>  
>>>>>>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md>+1,
>>>>>>>>  it needs to happen (and ASAP, since it _will_ introduce 
>>>>>>>> source-breaking changes one way or the other).
>>>>>>> 
>>>>>>> I think non-exhaustive is the correct default. However, does this not 
>>>>>>> mean that, by default, enums will be boxed because the receiver doesn’t 
>>>>>>> know their potential size?
>>>>>> 
>>>>>> It's not always boxing, but yes, there will be more indirection if the 
>>>>>> compiler can't see the contents of the enum. (More on that below.)
>>>>>> 
>>>>>> 
>>>>>>> That would mean that the best transition path for multi-module Apps 
>>>>>>> would be to make your enums @exhaustive, rather than adding “default” 
>>>>>>> statements (which is unfortunate, because I imagine when this change 
>>>>>>> hits, the way you’ll notice will be complaints about missing “default” 
>>>>>>> statements).
>>>>>> 
>>>>>> Yep, that's going to be the recommendation. The current 
>>>>>> minimal-for-review implementation does not do this but I'd like to 
>>>>>> figure out how to improve that; at the very least it might be a sensible 
>>>>>> thing to do in the migrator.
>>>>>> 
>>>>>>> 
>>>>>>> I do have some thoughts about how we could ease the transition (for 
>>>>>>> this and other resilience-related changes), but it’s best to leave that 
>>>>>>> to a separate discussion.
>>>>>>> 
>>>>>>> The one thing I’m still not overly fond of is the name - I would like 
>>>>>>> us to keep the set of resilience/optimisation related keywords to a 
>>>>>>> minimum. “exhaustive” for enums feels an awful lot like 
>>>>>>> “fixed_contents” for structs - couldn’t we come up with a single name 
>>>>>>> which could be used for both? I don’t think anybody’s going to want to 
>>>>>>> use “exhaustive” for structs.
>>>>>> 
>>>>>> The core team was very focused on this too, but I contend that 
>>>>>> "exhaustive" is not about optimization and really isn't even about 
>>>>>> "resilience" (i.e. the ability to evolve a library's API while 
>>>>>> preserving binary compatibility). It's a semantic feature of an enum, 
>>>>>> much like 'open' or 'final' is for classes, and it affects what a client 
>>>>>> can or can't do with an enum. For libaries compiled from source, it 
>>>>>> won't affect performance at all—the compiler still knows the full set of 
>>>>>> cases in the current version of the library even if the programmer is 
>>>>>> forced to consider future versions.
>>>>>> 
>>>>>> I'm working on the fixed-contents proposal now, though it won't be ready 
>>>>>> for a while, and the same thing applies there: for structs compiled from 
>>>>>> source, the compiler can still do all the same optimizations. It's only 
>>>>>> when the library has binary compatibility concerns that we need to use 
>>>>>> extra indirection, and then "fixed-contents" becomes important. (As 
>>>>>> currently designed, it doesn't affect what clients can do with the 
>>>>>> struct at all.) This means that I don't expect a "normal" package author 
>>>>>> to write "fixed-contents" at all (however it ends up being spelled), 
>>>>>> whereas "exhaustive" is a fairly normal thing to consider whenever you 
>>>>>> make an enum public.
>>>>>> 
>>>>>> I hope that convinces you that "fixed-contents" and "exhaustive" don't 
>>>>>> need to have the same name. I don't think anyone loves the particular 
>>>>>> name "exhaustive", but as you see in the "Alternatives considered" we 
>>>>>> didn't manage to come up with anything significantly better. If 
>>>>>> reviewers all prefer something else we'd consider changing it.
>>>>>> 
>>>>>> Thanks for responding!
>>>>>> Jordan
>>>>>> 
>>>>> 
>>>>> When you say “libraries compiled from source”, what do you mean?
>>>> 
>>>> - Other targets in your project
>>>> - Source packages built through SwiftPM / CocoaPods / Carthage / other
>>>> 
>>>> And I was being imprecise with the terminology, but also
>>>> 
>>>> - Libraries built by someone else but designed to be embedded into an app, 
>>>> so that there's no chance of a different version showing up at run-time.
>>>> 
>>>>> 
>>>>> As for whether its a resilience feature: actually it is completely a 
>>>>> resilience feature. The effects on switching are only side-effects; 
>>>>> really what “exhaustive” or “nonexhaustive” are saying is literally that 
>>>>> cases may be added later. Even if we added private cases, you wouldn’t 
>>>>> need to mark those enums as specially exhaustive or not; that would be 
>>>>> implied. It’s an accommodation for things which don’t exist yet, so 
>>>>> really, it is all about resilience IMO.
>>>> 
>>>> "Resilience", as an admittedly fuzzily-defined term in the Swift project, 
>>>> specifically refers to what changes can be made without breaking binary 
>>>> compatibility 
>>>> <https://github.com/apple/swift/blob/master/docs/Lexicon.rst>. It does not 
>>>> refer to every change you can make to a library. (For comparison, adding a 
>>>> field to a struct is not source-breaking in Swift. We would like to make 
>>>> it not ABI-breaking either; that proposal's coming soon.)
>>>> 
>>>> 
>>>>> 
>>>>> Anyway, as I see it, library authors in general ought to be happy about 
>>>>> this:
>>>>> + Their libraries become safer by default, so they can make changes in 
>>>>> the future without having to worry about breakage
>>>>> + It doesn’t affect your code inside of a module, so it only affects 
>>>>> types they already explicitly marked “public”
>>>> 
>>>> That's the intent.
>>>> 
>>>>> 
>>>>> The only people who lose are multi-module App developers, because they 
>>>>> are “library authors” who don’t need to care about evolution, and now 
>>>>> need to add attributes to things they wouldn’t have to before, or suffer 
>>>>> language and performance penalties. Their libraries become less reusable 
>>>>> and not resilient-by-default.
>>>>> 
>>>>> For example, I have an App for which I wrote a cross-platform model 
>>>>> framework in Swift. When I compile it as a framework inside my App, it is 
>>>>> bundled there forever. However, I use the same code to build libraries 
>>>>> for Linux, which I would like to ship in binary form to 3rd-parties. Am I 
>>>>> supposed to litter my code with annotations to mark those types as final, 
>>>>> just to make the App fast and convenient to code? What happens when I 
>>>>> need to fix a bug and distribute an updated copy, this means the 
>>>>> 3rd-parties need to recompile (which they won’t do…).
>>>>> 
>>>>> Typically, for such a problem, I would recommend using a static library 
>>>>> instead. But we don’t have those, and anyway they’re not always the best 
>>>>> thing these days. So that’s why I started a new thread about creating a 
>>>>> “@static” import, so App developers can go back to all the conveniences 
>>>>> they had before.
>>>> 
>>>> There won't be a perf penalty, but yes, I do expect multi-module apps to 
>>>> use 'exhaustive' on most of their enums, because they don't need the 
>>>> futureproofing. Maybe this should have been mentioned more explicitly in 
>>>> the proposal.
>>> 
>>> As a perhaps more long-term design note, I think modules ought to have the 
>>> ability to version-lock themselves to one or more of their dependencies.  
>>> They would still be required to obey access control as if they were outside 
>>> those dependencies, but we would suppress some of the semantic consequences 
>>> of being outside the module, such as the need to assume non-exhaustiveness 
>>> by default.
>>> 
>>> That is, there would be two independent axes of library dependency: source 
>>> vs. binary and version-compatible vs. version-locked:
>>>   - a source dependency allows the compiler to take advantage of the 
>>> implementation of public entities when generating code
>>>   - a version-locked dependency allows the compiler to take advantage of 
>>> the implementation of public entities when enforcing semantics
>>> 
>>> Apps would generally elect to primarily use version-locked source 
>>> dependencies because they're just pulling down source libraries (e.g. from 
>>> github) and are comfortable with updating their code if the library changes.
>>> 
>>> Source libraries on github would generally want to use version-compatible 
>>> source dependencies because version-locking would put their clients in 
>>> "library hell" if the locking didn't all agree.
>>> 
>>> Binary dependencies could reasonably use either.
>> 
>> This model aligns pretty well with what I would like to see.  It prevents us 
>> from paying a penalty when we don’t need the benefits provided by a 
>> restriction.  
>> 
>> Relating this back to the current proposal, would you expect an app to have 
>> the ability to switch over an enum provided by a version-locked dependency 
>> that is not annotated with @exhaustive without requiring a default clause?
> 
> Yes, and as we find other places where program semantics depend on knowing 
> the implementation, I would expect them to follow suit.
> 
> My guess is that enum exhaustiveness is probably more prominent than any 
> other such feature, and maybe even more prominent than all of them put 
> together, but possible examples include:
>   - automatically deriving protocol conformances, which we hope will 
> eventually be something you can do for an arbitrary protocol
>   - any other kind of structural metaprogramming we might add
>   - maybe memberwise struct initialization if there are no explicit 
> initializers, although this is arguably an access control question (just as 
> public/open is)
>   - ownership-related features that might make sense to restrict to stored 
> properties, like expecting a struct property to have a stable address, or 
> destructuring a struct with pattern-matching
> 
> Now, some of these things might be nice to allow even for resilient types.  I 
> know Joe has suggested adding some way of resiliently describing a structural 
> decomposition of a type, which you could then use to derive conformances, 
> etc.  But since the basic motivation for restricting any of them is 
> source/binary compatibility, and since version-locking would tell us that the 
> programmer doesn't care about that, it seems sensible that version-locking 
> ought to suppress the restrictions.
> 
>> Relating to @inlinable proposal also under review, would everything in a 
>> source dependency be automatically inlinable whether they were annotated as 
>> such or not (at least when version-locked)?
> 
> Yes, and regardless of being version-locked.  Inlining isn't semantically 
> visible: it's observable in various low-level ways, but it's not supposed to 
> affect basic program semantics except in incidental ways, e.g. by lowering 
> the memory requirements so that programs start working that didn't before.  
> So the compiler is generally always allowed to inline when the call is direct 
> and the callee has a known implementation; that's just standard "as if" 
> behavior.  The fact that we can't do this today is just an unfortunate 
> consequence of our current build model.

This is all exciting to hear (as a long term direction)!  Thank you for the 
elaboration.

> 
> John.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to