Re: [swift-evolution] Handling unknown cases in enums [RE: SE-0192]

2018-01-12 Thread Matthew Johnson via swift-evolution

> On Jan 12, 2018, at 6:31 PM, Jonathan Hull via swift-evolution 
>  wrote:
> 
> I’m definitely in the error camp, but I will go along with a warning if 
> everyone feels that is better.

I see advantages both ways.  The fact that the error approach generalizes much 
cleaner is definitely a plus.  

The primary downside to that approach is losing the ability to rebuild with the 
same version of a source dependency that has used #unkown when matching a 
non-frozen enum vended by a common dependency to which a case has been added 
since the source dependency was written.  Requiring this behavior can be viewed 
as a pretty significant downside.  It tightens the coupling between versions of 
dependencies.  This can make it difficult to update dependencies in a large 
project.  The warning approach allows people to opt-in to this behavior by 
treating warnings as errors without requiring everyone to make the same 
tradeoff.

It’s really a tough tradeoff.

> 
> Thanks,
> Jon
> 
>> On Jan 12, 2018, at 3:08 PM, Jordan Rose via swift-evolution 
>>  wrote:
>> 
>> Okay, I went back to `unknown case` in the proposal, but mentioned Chris's 
>> point very specifically: if the compiler emits an error, we should go with 
>> `case #unknown` instead. (I'm very strongly in the "warning" camp, though.)
>> 
>> I think the revised proposal is in good shape! 
>> (https://github.com/apple/swift-evolution/pull/777) I think I've addressed 
>> everyone's feedback either in the proposal or on-list, if not necessarily 
>> convinced them. If there are no other major comments I'll let Ted know that 
>> it's ready to re-run on Monday.
>> 
>> Jordan
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [Pitch] Make try? + optional chain flattening work together

2018-01-12 Thread Matthew Johnson via swift-evolution

> On Jan 12, 2018, at 2:00 PM, John McCall via swift-evolution 
>  wrote:
> 
> 
>> On Jan 12, 2018, at 12:53 PM, BJ Homer via swift-evolution 
>> > wrote:
>> 
>> I agree that this behavior is annoying. However, wouldn’t it be 
>> source-breaking to change this now?
> 
> Source compatibility means that we can't change the behavior of Swift 3 / 
> Swift 4 source.  This would be a semantic change when building Swift 5 source 
> (or later).  There is no technical reason we couldn't make this change.  It 
> does need to meet a very high bar, because we are trying to avoid making 
> significant semantic breaks.  My personal sense is that it meets that bar 
> because double-optionals can be very confusing for novices and very annoying 
> for everyone else.
> 
> I think most use sites probably do want the optional-collapsing behavior.  
> 'try?' is already "sugar" syntax and should aim to be as convenient as 
> possible for the majority of use cases.  Much like the collapsing done by 
> optional chaining, I think you can come up with examples where somebody would 
> want the non-collapsing behavior, but it doesn't seem unreasonable to say 
> that they just shouldn't use the sugar.

I think I agree with this.  `try?` already has some implicit optional 
collapsing behavior when it is used in an expression where there is more than 
one call that can throw.  The most intuitive behavior is for this collapsing to 
compose with the collapsing of optional chaining.

> 
> John.
> 
>> 
>> -BJ
>> 
>>> On Jan 12, 2018, at 10:25 AM, Russ Bishop via swift-evolution 
>>> > wrote:
>>> 
>>> Greetings swift-evolution!
>>> 
>>> There is currently a disconnect between optional chaining and try? when it 
>>> comes to optional flattening:
>>> 
>>> 
>>> struct SomeType {
>>> func nonThrow() -> SomeType? { return self }
>>> func doThrow() throws -> SomeType? { return self }
>>> func nonOptional() throws -> SomeType { return self }
>>> }
>>> 
>>> let w = SomeType().nonThrow()?.nonThrow()?.nonThrow()?.nonThrow()
>>> // w has type SomeType?
>>> 
>>> let x = try? 
>>> SomeType().nonOptional().nonOptional().nonOptional().nonOptional()
>>> // x has type SomeType?
>>> 
>>> let y = try! SomeType().doThrow()?.doThrow()?.doThrow()?.doThrow()
>>> // y has type SomeType?
>>> 
>>> let z = try? SomeType().doThrow()?.doThrow()?.doThrow()?.doThrow()
>>> // z has type SomeType??
>>> 
>>> 
>>> We get a double-optional only when combining try? and optional-chaining. 
>>> That is inconvenient and it would be natural to have the compiler do the 
>>> flattening here.
>>> 
>>> 
>>> If anyone is interested in working on the proposal or implementation please 
>>> let me know. It would make a nice self-contained task if you're looking to 
>>> start contributing.
>>> 
>>> 
>>> Russ Bishop
>>>  Simulator
>>> 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] Handling unknown cases in enums [RE: SE-0192]

2018-01-12 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Jan 12, 2018, at 12:25 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> 
> 
>> On Jan 11, 2018, at 23:30, Chris Lattner  wrote:
>> 
>> 
>>> On Jan 11, 2018, at 11:15 PM, Jean-Daniel via swift-evolution 
>>>  wrote:
>>> 
>>> A question about the new #unknown behavior. Is it intended to be used for 
>>> error handling too ?
>>> Will it be possible to use in catch clause ?
>> 
>> If we go with the #unknown approach, then yes of course it will work in 
>> catch clauses.  They are patterns, so it naturally falls out.
> 
> It will not work in catch clauses because you need to have a static type 
> that's an enum. Catch clauses always (today…) have a static type of 'Error'.

Right, although it should work for enum Error types in catch clauses if we add 
typed errors in the future.  That’s worth considering when making this decision.

> 
> 
>> 
>> If we go with the “unknown default:” / “unknown case:"  approach, then no, 
>> this has nothing to do with error handling.
>> 
>> IMO, this pivots on the desired semantics for “unknown cases in enums”: if 
>> you intentionally try to match on this, do we get a warning or error if you 
>> don’t handle all the cases?  If we can get to consensus on that point, then 
>> the design is pretty obvious IMO.
> 
> That's fair. I'm strongly in favor of a warning, though, because again, 
> people don't edit their dependencies.
> 
> Jordan
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [Pitch] Generalized supertype constraints

2018-01-10 Thread Matthew Johnson via swift-evolution

> On Jan 10, 2018, at 2:19 PM, Rex Fenley  wrote:
> 
> Have you found anyone else to help on this one? I would like to dive in 
> myself but I don't have any experience with the compiler and not sure about 
> the size of the workload here.

Hi Rex, thank you for offering to help!  I have not found anyone else to help 
out on implementation but am still extremely interested in seeing this happen 
and willing to help out by drafting the proposal, etc.

Is anyone who is familiar with it able to give Rex an idea of scope and / or 
willing to help Rex get up to speed?

> 
> On Tue, Dec 5, 2017 at 3:34 PM, Rex Fenley  > wrote:
> Huge +1, I've asked for this in the past too.
> 
> Have you also found this limitation frustrating? 
>   - Yes
> 
> In what contexts?
>   - APIs that have this requirement and end up enforcing them through runtime 
> type checking and throws. Shows up in some network data mapping code I have 
> that generalizes over Core Data and Realm (and other databases). The protocol 
> implementer must specify the subtype for the raw mapping of JSON and base 
> type for the DB reading/writing layer. Could see this showing up whenever 
> there's a separation of concerns between what business logic belongs to the 
> base type and subtypes of a more generalized system. I could potentially see 
> the same issue showing up in code generalizing the mapping of data to UI, 
> like UITableView/UITableViewCell.
> 
> Does anyone have reservations about introducing this capability?
>   - I do not
>> One of the most frequent frustrations I encounter when writing generic code 
>> in Swift is the requirement that supertype constraints be concrete.  When I 
>> mentioned this on Twitter 
>> (https://twitter.com/anandabits/status/929958479598534656 
>> ) Doug Gregor 
>> mentioned that this feature is smaller and mostly straightforward to design 
>> and implement (https://twitter.com/dgregor79/status/929975472779288576 
>> ).
>> 
>> I currently have a PR open to add the high-level description of this feature 
>> found below to the generics manifesto 
>> (https://github.com/apple/swift/pull/13012 
>> ):
>> 
>> Currently, supertype constraints may only be specified using a concrete 
>> class or protocol type.  This prevents us from abstracting over the 
>> supertype.
>> 
>> ```swift
>> protocol P {
>>   associatedtype Base
>>   associatedtype Derived: Base
>> }
>> ```
>> 
>> In the above example `Base` may be any type.  `Derived` may be the same as 
>> `Base` or may be _any_ subtype of `Base`.  All subtype relationships 
>> supported by Swift should be supported in this context including, but not 
>> limited to, classes and subclasses, existentials and conforming concrete 
>> types or refining existentials, `T?` and  `T`, `((Base) -> Void)` and 
>> `((Derived) -> Void)`, etc.
>> 
>> Generalized supertype constraints would be accepted in all syntactic 
>> locations where generic constraints are accepted.
>> 
>> I would like to see generalized supertype constraints make it into Swift 5 
>> if possible.  I am not an implementer so I will not be able to bring a 
>> proposal forward alone but am interested in collaborating with anyone 
>> interested in working on implementation.
>> 
>> I am also interested in hearing general feedback on this feature from the 
>> community at large.  Have you also found this limitation frustrating?  In 
>> what contexts?  Does anyone have reservations about introducing this 
>> capability?  If so, what are they?
>> 
>> Matthew
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 
> -- 
> Rex Fenley  |  IOS DEVELOPER
> 
> 
> Remind.com  |  BLOG   |  
> FOLLOW US   |  LIKE US 
> 
> 
> 
> -- 
> Rex Fenley  |  IOS DEVELOPER
> 
> 
> Remind.com  |  BLOG   |  
> FOLLOW US   |  LIKE US 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review] SE-0194: Derived Collection of Enum Cases

2018-01-10 Thread Matthew Johnson via swift-evolution
> What is your evaluation of the proposal?

+1.  I have written plenty of enums with the `allValues` property.  It will be 
nice to have this synthesized.

I do think a small clarification or revision is warranted, however.  I would 
like to see a rationale stated for choosing the `Collection` requirement rather 
than `Sequence` or `RandomAccessCollection`.  The `Sequence` alternative has 
been discussed in some depth on the list and this discussion is not represented 
in the alternatives section.

I bring up `RandomAccessCollection` as an alternative worth discussing because 
I strongly believe the proposal should require the compiler synthesized 
`ValueCollection` types to also conform to `RandomAccessCollection` and further 
have `Int` indices.  One of the leading motivating use cases for this proposal 
is in implementing data sources which requires both `Int` indices and also 
carries an expectation of a constant time subscript operation.  

Placing a stronger requirement on the compiler-synthesized implementation than 
we do on manual conformances is somewhat subtle so we should at least consider 
whether such requirements are acceptable for all conformances or not and 
address that in the proposal.  I don’t know of any use cases for a manual 
conformance where meeting the stricter requirements would be problematic.  On 
the other hand, requiring an `Int` index in particular seems like it is 
probably too strict.  

I support the proposal regardless of the decision but believe additional 
discussion and documentation of the alternative constraints would be healthy.

> Is the problem being addressed significant enough to warrant a change to 
> Swift?
Absolutely.  This is a very common source of boilerplate that is prone to break 
as code changes.

> Does this proposal fit well with the feel and direction of Swift?
Yes.

> If you have used other languages or libraries with a similar feature, how do 
> you feel that this proposal compares to those?
N/A

> How much effort did you put into your review? A glance, a quick reading, or 
> an in-depth study?
In-depth study and participation in prior threads.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-03 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Jan 3, 2018, at 12:20 PM, Dave DeLong  wrote:
> 
> 
> 
>>> On Jan 3, 2018, at 11:09 AM, Matthew Johnson  wrote:
>>> 
>>> 
 On Jan 3, 2018, at 12:02 PM, Dave DeLong  wrote:
 
 
 
 On Jan 3, 2018, at 10:58 AM, Kevin Nattinger  wrote:
 
>>> [...]
>>> 2️⃣ If the enum is NOT decorated with @frozen, then I, as an 
>>> app author, have to account for the possibility that the module may 
>>> update from underneath my app, and I have to handle an unknown case. 
>>> This is simple: the compiler should require me to add a “default:” case 
>>> to my switch statement. This warning is produced IFF: the enum is 
>>> coming from an external module, and the enum is not decorated with 
>>> @frozen.
>> 
>> This does not help people who need to write a switch statement over an 
>> enum vended by a module that ships with the OS keep their code up to 
>> date as the module adds new cases. I find the example of 
>> `SKPaymentTransactionState` provided by Brent Royal-Gordon here: 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
>>  to be compelling.  There are rare but legitimate reasons to switch over 
>> all known cases of a non-@frozen enum that ship with the OS.  These use 
>> cases deserve proper language support.  I think Jordan’s solution 
>> strikes a good balance.
> 
> I disagree that more is needed. In the case of the transaction state, it 
> should not be marked as @moana, and so the compiler would force you to 
> add a “default” case to your switch statements. The switch statements 
> would still be exhaustive with all known cases (if you choose to handle 
> all known cases), but you’d still need a default case because there might 
> be new transaction states in the future.
 
 And then you don't get the compiler error/warning when you start compiling 
 against the next OS update that changes the enum. That is an absolutely 
 unacceptable loss of compile-time checks.
>>> 
>>> Ah, that’s an excellent point! Thanks for pointing that out.
>>> 
>>> In that case, I revise my proposal:
>>> 
>>> 1️⃣ a @frozen/@tangled/@moana attribute for enums that’s only consulted on 
>>> externally-linked modules
>>> 2️⃣ a “future case:” statement that’s only required on externally-linked, 
>>> non-@moana enums. That way, if the enum adds a new case in the future, 
>>> you’ll still get a switch warning about handling all the cases. And then if 
>>> you want, you could “fallthrough” from this to a “default” case, or 
>>> vice-versa, or have separate implementations.
>> 
>> It sounds to me like the main thing you’re unhappy about is having to deal 
>> with unknown cases when you have a source dependency that you always build 
>> and ship with an app.  I don’t think anyone is happy with that situation.  
> 
> That’s definitely part of it. The other main part is that I’m hugely 
> resistant to adding extraneous syntax when a solution that’s simpler for 
> users exists.

That’s fair.  If we didn’t have a compelling motivating example I would be more 
reluctant about the need to add syntax here, but we do have such an example.

> 
>> Did you take a look at the sketch of a solution provided by John McCall?  
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042333.html
> 
> I’ve read that email several times and don’t understand how it relates.

I should have also linked to his previous email.  Does this one help clarify 
what he has in mind?  
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042329.html

> 
> Dave
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-03 Thread Matthew Johnson via swift-evolution

> On Jan 3, 2018, at 12:02 PM, Dave DeLong  wrote:
> 
> 
> 
>> On Jan 3, 2018, at 10:58 AM, Kevin Nattinger > > wrote:
>> 
> [...]
>   2️⃣ If the enum is NOT decorated with @frozen, then I, as an app 
> author, have to account for the possibility that the module may update 
> from underneath my app, and I have to handle an unknown case. This is 
> simple: the compiler should require me to add a “default:” case to my 
> switch statement. This warning is produced IFF: the enum is coming from 
> an external module, and the enum is not decorated with @frozen.
 
 This does not help people who need to write a switch statement over an 
 enum vended by a module that ships with the OS keep their code up to date 
 as the module adds new cases. I find the example of 
 `SKPaymentTransactionState` provided by Brent Royal-Gordon here: 
 https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
  
 
  to be compelling.  There are rare but legitimate reasons to switch over 
 all known cases of a non-@frozen enum that ship with the OS.  These use 
 cases deserve proper language support.  I think Jordan’s solution strikes 
 a good balance.
>>> 
>>> I disagree that more is needed. In the case of the transaction state, it 
>>> should not be marked as @moana, and so the compiler would force you to add 
>>> a “default” case to your switch statements. The switch statements would 
>>> still be exhaustive with all known cases (if you choose to handle all known 
>>> cases), but you’d still need a default case because there might be new 
>>> transaction states in the future.
>> 
>> And then you don't get the compiler error/warning when you start compiling 
>> against the next OS update that changes the enum. That is an absolutely 
>> unacceptable loss of compile-time checks.
> 
> Ah, that’s an excellent point! Thanks for pointing that out.
> 
> In that case, I revise my proposal:
> 
> 1️⃣ a @frozen/@tangled/@moana attribute for enums that’s only consulted on 
> externally-linked modules
> 2️⃣ a “future case:” statement that’s only required on externally-linked, 
> non-@moana enums. That way, if the enum adds a new case in the future, you’ll 
> still get a switch warning about handling all the cases. And then if you 
> want, you could “fallthrough” from this to a “default” case, or vice-versa, 
> or have separate implementations.

It sounds to me like the main thing you’re unhappy about is having to deal with 
unknown cases when you have a source dependency that you always build and ship 
with an app.  I don’t think anyone is happy with that situation.  Did you take 
a look at the sketch of a solution provided by John McCall?  
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042333.html
 

> 
> Dave
> 
>> 
>>> 
>>> In those cases, your app could decide what to do, if that’s possible at 
>>> all. Maybe there’s other transaction information you could introspect to 
>>> determine if it succeeded or is still pending or whatever, and then your 
>>> app could respond as you see fit.
>>> 
>>> Dave
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
> 

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


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-03 Thread Matthew Johnson via swift-evolution

> On Jan 3, 2018, at 11:49 AM, Dave DeLong  wrote:
> 
> 
> 
>> On Jan 3, 2018, at 10:36 AM, Matthew Johnson > > wrote:
>> 
>> 
>>> On Jan 3, 2018, at 11:07 AM, Dave DeLong via swift-evolution 
>>> > wrote:
>>> 
>>> IMO this is still too large of a hammer for this problem.
>>> 
>>> This whole “unexpected case” thing is only a problem when you’re linking 
>>> libraries that are external to/shipped independently of your app. Right 
>>> now, the *only* case where this might exist is Swift on the server. We 
>>> *might* run in to this in the future once the ABI stabilizes and we have 
>>> the Swift libraries shipping as part of iOS/macOS/Linux. Other than this, 
>>> unexpected enum cases won’t really be a problem developers have to deal 
>>> with.
>>> 
>>> Because this will be such a relatively rare problem, I feel like a syntax 
>>> change like what’s being proposed is a too-massive hammer for such a small 
>>> nail.
>>> 
>>> What feels far more appropriate is:
>>> 
>>> ️ Teaching the compiler/checker/whatever about the linking semantics of 
>>> modules. For modules that are packaged inside the final built product, 
>>> there is no need to deal with any unexpected cases, because we already have 
>>> the exhaustiveness check appropriate for that scenario (regardless of 
>>> whether the module is shipped as a binary or compiled from source). The app 
>>> author decides when to update their dependencies, and updating those 
>>> dependencies will produce new warnings/errors as the compiler notices new 
>>> or deprecated cases. This is the current state of things and is completely 
>>> orthogonal to the entire discussion.
>> 
>> John McCall sketched out a vision of what a solution to this might look like 
>> here: 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042333.html
>>  
>> .
>>  
>> 
>>> 
>>> and
>>> 
>>> ️ Adding an attribute (@frozen, @tangled, @moana, @whatever) that can be 
>>> used to decorate an enum declaration. This attribute would only need to be 
>>> consulted on enums where the compiler can determine that the module will 
>>> *not* be part of the final built product. (Ie, it’s an “external” module, 
>>> in my nomenclature). This, then, is a module that can update independently 
>>> of the final app, and therefore there are two possible cases:
>>> 
>>> 1️⃣ If the enum is decorated with @frozen, then I, as an app author, 
>>> have the assurance that the enum case will not change in future releases of 
>>> the library, and I can safely switch on all known cases and not have to 
>>> provide a default case. 
>>> 
>>> 2️⃣ If the enum is NOT decorated with @frozen, then I, as an app 
>>> author, have to account for the possibility that the module may update from 
>>> underneath my app, and I have to handle an unknown case. This is simple: 
>>> the compiler should require me to add a “default:” case to my switch 
>>> statement. This warning is produced IFF: the enum is coming from an 
>>> external module, and the enum is not decorated with @frozen.
>> 
>> This does not help people who need to write a switch statement over an enum 
>> vended by a module that ships with the OS keep their code up to date as the 
>> module adds new cases. I find the example of `SKPaymentTransactionState` 
>> provided by Brent Royal-Gordon here: 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
>>  
>> 
>>  to be compelling.  There are rare but legitimate reasons to switch over all 
>> known cases of a non-@frozen enum that ship with the OS.  These use cases 
>> deserve proper language support.  I think Jordan’s solution strikes a good 
>> balance.
> 
> I disagree that more is needed. In the case of the transaction state, it 
> should not be marked as @moana, and so the compiler would force you to add a 
> “default” case to your switch statements. The switch statements would still 
> be exhaustive with all known cases (if you choose to handle all known cases), 
> but you’d still need a default case because there might be new transaction 
> states in the future.
> 
> In those cases, your app could decide what to do, if that’s possible at all. 
> Maybe there’s other transaction information you could introspect to determine 
> if it succeeded or is still pending or whatever, and then your app could 
> respond as you see fit.

SKPaymentTransactionState is an excellent motivating example for a better 
solution because it is crucial to update code to handle any new states 
accurately and promptly.  This is much easier to do with compiler assistance 
than without it. 

It is also an excellent motivating example because the API change is driven by 
a 

Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-03 Thread Matthew Johnson via swift-evolution

> On Jan 3, 2018, at 11:47 AM, BJ Homer <bjho...@gmail.com> wrote:
> 
> 
> 
>> On Jan 3, 2018, at 10:36 AM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> This does not help people who need to write a switch statement over an enum 
>> vended by a module that ships with the OS keep their code up to date as the 
>> module adds new cases. I find the example of `SKPaymentTransactionState` 
>> provided by Brent Royal-Gordon here: 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
>>  
>> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html>
>>  to be compelling.  There are rare but legitimate reasons to switch over all 
>> known cases of a non-@frozen enum that ship with the OS.  These use cases 
>> deserve proper language support.  I think Jordan’s solution strikes a good 
>> balance.
> 
> I agree that the SKPaymentTransactionState example is compelling. However, I 
> don’t understand what actual code a developer would put in the “unexpected 
> case:” clause. That enum is related to handling in-app purchases; it’s 
> expected that the app would react in some way to a transaction changing 
> state. What should the app do if the transaction enters an “unexpected” 
> state? Pop up an error to the user that the user can do nothing about? It’s 
> great to get a compiler warning about a case like when the developer builds 
> with the new SDK, but I don’t understand what the already-shipped app is 
> supposed to do in a case like this.
> 
> For the SKPaymentTransactionState case, at least, it seems like the library 
> needs to be responsible to only send known values to the client. Otherwise, 
> the app can have no idea what to do.

There is definitely not a good answer here.  Making the library responsible to 
only send known values is not a solution.  This type represents the state of an 
entity and it should do so as accurately as possible.  Sometimes a new state 
cannot be mapped to one of the previous states.  How would you have StoreKit 
handle the deferred state for old clients?

My position is that the situation is much worse for an app developer when they 
don’t even get the assistance of a compiler warning when updating to the new 
SDK.  App developers are sometimes forced to deal with unfortunate cases like 
this.  Any help the language can provide is appreciated.

> 
> -BJ

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


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-03 Thread Matthew Johnson via swift-evolution

> On Jan 3, 2018, at 11:07 AM, Dave DeLong via swift-evolution 
>  wrote:
> 
> IMO this is still too large of a hammer for this problem.
> 
> This whole “unexpected case” thing is only a problem when you’re linking 
> libraries that are external to/shipped independently of your app. Right now, 
> the *only* case where this might exist is Swift on the server. We *might* run 
> in to this in the future once the ABI stabilizes and we have the Swift 
> libraries shipping as part of iOS/macOS/Linux. Other than this, unexpected 
> enum cases won’t really be a problem developers have to deal with.
> 
> Because this will be such a relatively rare problem, I feel like a syntax 
> change like what’s being proposed is a too-massive hammer for such a small 
> nail.
> 
> What feels far more appropriate is:
> 
> ️ Teaching the compiler/checker/whatever about the linking semantics of 
> modules. For modules that are packaged inside the final built product, there 
> is no need to deal with any unexpected cases, because we already have the 
> exhaustiveness check appropriate for that scenario (regardless of whether the 
> module is shipped as a binary or compiled from source). The app author 
> decides when to update their dependencies, and updating those dependencies 
> will produce new warnings/errors as the compiler notices new or deprecated 
> cases. This is the current state of things and is completely orthogonal to 
> the entire discussion.

John McCall sketched out a vision of what a solution to this might look like 
here: 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171218/042333.html
 
.
 

> 
> and
> 
> ️ Adding an attribute (@frozen, @tangled, @moana, @whatever) that can be 
> used to decorate an enum declaration. This attribute would only need to be 
> consulted on enums where the compiler can determine that the module will 
> *not* be part of the final built product. (Ie, it’s an “external” module, in 
> my nomenclature). This, then, is a module that can update independently of 
> the final app, and therefore there are two possible cases:
> 
>   1️⃣ If the enum is decorated with @frozen, then I, as an app author, 
> have the assurance that the enum case will not change in future releases of 
> the library, and I can safely switch on all known cases and not have to 
> provide a default case. 
> 
>   2️⃣ If the enum is NOT decorated with @frozen, then I, as an app 
> author, have to account for the possibility that the module may update from 
> underneath my app, and I have to handle an unknown case. This is simple: the 
> compiler should require me to add a “default:” case to my switch statement. 
> This warning is produced IFF: the enum is coming from an external module, and 
> the enum is not decorated with @frozen.

This does not help people who need to write a switch statement over an enum 
vended by a module that ships with the OS keep their code up to date as the 
module adds new cases. I find the example of `SKPaymentTransactionState` 
provided by Brent Royal-Gordon here: 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
 

 to be compelling.  There are rare but legitimate reasons to switch over all 
known cases of a non-@frozen enum that ship with the OS.  These use cases 
deserve proper language support.  I think Jordan’s solution strikes a good 
balance.

> 
> 
> ==
> 
> With this proposal, we only have one thing to consider: the spelling of 
> @frozen/@moana/@whatever that we decorate enums in external modules with. 
> Other than that, the existing behavior we currently have is completely 
> capable of covering the possibilities: we just keep using a “default:” case 
> whenever the compiler can’t guarantee that we can be exhaustive in our 
> switching.
> 
> Where the real work would be is teaching the compiler about 
> internally-vs-externally linked modules.
> 
> Dave
> 
>> On Jan 2, 2018, at 7:07 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> [Proposal: 
>> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
>>  
>> ]
>> 
>> Whew! Thanks for your feedback, everyone. On the lighter side of 
>> feedback—naming things—it seems that most people seem to like '@frozen', and 
>> that does in fact have the connotations we want it to have. I like it too.
>> 
>> More seriously, this discussion has convinced me that it's worth including 
>> what the proposal discusses as a 'future' case. The key point that swayed me 
>> is that this can produce a warning when the switch is missing a case rather 
>> than an error, which both provides the necessary 

Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-02 Thread Matthew Johnson via swift-evolution

> On Jan 2, 2018, at 8:45 PM, Xiaodi Wu via swift-evolution 
>  wrote:
> 
> On Tue, Jan 2, 2018 at 8:07 PM, Jordan Rose via swift-evolution 
> > wrote:
> [Proposal: 
> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
>  
> ]
> 
> Whew! Thanks for your feedback, everyone. On the lighter side of 
> feedback—naming things—it seems that most people seem to like '@frozen', and 
> that does in fact have the connotations we want it to have. I like it too.
> 
> More seriously, this discussion has convinced me that it's worth including 
> what the proposal discusses as a 'future' case. The key point that swayed me 
> is that this can produce a warning when the switch is missing a case rather 
> than an error, which both provides the necessary compiler feedback to update 
> your code and allows your dependencies to continue compiling when you update 
> to a newer SDK. I know people on both sides won't be 100% satisfied with 
> this, but does it seem like a reasonable compromise?
> 
> The next question is how to spell it. I'm leaning towards `unexpected case:`, 
> which (a) is backwards-compatible, and (b) also handles "private cases", 
> either the fake kind that you can do in C (as described in the proposal), or 
> some real feature we might add to Swift some day. `unknown case:` isn't bad 
> either.
> 
> I too would like to just do `unknown:` or `unexpected:` but that's 
> technically a source-breaking change:
> 
> switch foo {
> case bar:
>   unknown:
>   while baz() {
> while garply() {
>   if quux() {
> break unknown
>   }
> }
>   }
> }
> 
> Another downside of the `unexpected case:` spelling is that it doesn't work 
> as part of a larger pattern. I don't have a good answer for that one, but 
> perhaps it's acceptable for now.
> 
> I'll write up a revision of the proposal soon and make sure the core team 
> gets my recommendation when they discuss the results of the review.
> 
> ---
> 
> I'll respond to a few of the more intricate discussions tomorrow, including 
> the syntax of putting a new declaration inside the enum rather than outside. 
> Thank you again, everyone, and happy new year!
> 
> I do like this spelling of `@frozen`, and `unknown case` looks perfectly 
> cromulent to me. If this is the path to go down, I'd urge more explicit 
> design as to what happens when `unknown case` and `default` are mixed. I 
> would imagine the most consistent design would be:
> 
> `unknown case` should allow `default` to be omitted if the switch is 
> otherwise exhaustive, obviously.
> `default` should allow `unknown case` to be omitted, just like any other case 
> may then be omitted.
> `unknown case` before `default` should be allowed, just like any other case 
> before `default`; in that case, only known cases not otherwise matched reach 
> the `default`.
> `default` before `unknown case` makes the latter unreachable, just like any 
> other case after `default`.
> 
> The issue here remains that of testability. I wonder if, for such purposes, 
> unknown case should be instantiable when testably imported, with some 
> grammar. In its simplest and yet most exotic form, we could imagine code that 
> testably imports the enum to be allowed to instantiate any made-up case 
> whatsoever (e.g., `@testable import Foo.MyEnum; let x = 
> MyEnum.asdfasdfasdfNonexistent`).

What should happen when an unknown case instantiated via a testability 
mechanism is passed to the library that vended the enum (which is able to truly 
exhaustively switch over the enum)?  I would like to see a solution to the 
testability problem and answering this question seems to be the most difficult 
part of finding a solution.  The best answer is not obvious to me.

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

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


Re: [swift-evolution] [swift-evolution-announce] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-02 Thread Matthew Johnson via swift-evolution

> On Jan 2, 2018, at 8:07 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> [Proposal: 
> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
>  
> ]
> 
> Whew! Thanks for your feedback, everyone. On the lighter side of 
> feedback—naming things—it seems that most people seem to like '@frozen', and 
> that does in fact have the connotations we want it to have. I like it too.
> 
> More seriously, this discussion has convinced me that it's worth including 
> what the proposal discusses as a 'future' case. The key point that swayed me 
> is that this can produce a warning when the switch is missing a case rather 
> than an error, which both provides the necessary compiler feedback to update 
> your code and allows your dependencies to continue compiling when you update 
> to a newer SDK. I know people on both sides won't be 100% satisfied with 
> this, but does it seem like a reasonable compromise?

I think this strikes a reasonable balance.  It allows people to continue 
compiling a dependency that hasn’t been updated if necessary while knowing (if 
they look at the compilation log) that the unknown case may be executed with 
their current SDK.  It is also straightforward to adopt a “treat warnings as 
errors” policy if desired.  It may also be possible to selectively silence or 
upgrade targeted warnings in the future which would also afford additional 
control over how these warnings are treated.

I spent some time digging through the archives tonight and found one of the 
examples I personally found compelling in motivating the need for this: 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170904/039512.html
 
.
  It is Brent Royal-Gordon’s discussion of `SKPaymentTransactionState`:

> `SKPaymentTransactionState`, which tells you the status of an in-app purchase 
> transaction, probably would have seemed like a data enum in iOS 3. After all, 
> what states could a transaction take besides `purchasing`, `purchased`, 
> `failed`, or `restored`? But in iOS 8, StoreKit introduced the `deferred` 
> state to handle a new parental-approval feature. Third-party developers did 
> not expect this and had to scramble to handle the unanticipated change.


This is a great example of an Apple-provided enum which is not likely to be 
declared exhaustive but for which people will have legitimate reasons to switch 
over.  I believe there were other good examples discussing 3rd party libraries 
(related to networking?) shared on the list in the past but I was unable to 
find them in the time I had available this evening.

> 
> The next question is how to spell it. I'm leaning towards `unexpected case:`, 
> which (a) is backwards-compatible, and (b) also handles "private cases", 
> either the fake kind that you can do in C (as described in the proposal), or 
> some real feature we might add to Swift some day. `unknown case:` isn't bad 
> either.

I agree with this direction because it also addresses private cases.  It isn’t 
clear to me why `future` wouldn’t be backwards compatible while `unexpected` or 
`unknown` would but that isn’t a deciding factor for me.

I think `unknown` is the best option.  `unexpected` doesn’t seem right as it 
isn’t exactly unexpected.  When we use this keyword it is precisely because we 
know there may be private cases or new cases added in the future.  We are 
expecting to eventually come across a case we didn’t know about when writing 
the code.

> 
> I too would like to just do `unknown:` or `unexpected:` but that's 
> technically a source-breaking change:
> 
> switch foo {
> case bar:
>   unknown:
>   while baz() {
> while garply() {
>   if quux() {
> break unknown
>   }
> }
>   }
> }

The potential for source breakage here seems pretty remote.  I would be 
happiest if we could just accept it but this will be a relatively rarely used 
feature so I won’t complain if a syntactic compromise needs to be made.

> 
> Another downside of the `unexpected case:` spelling is that it doesn't work 
> as part of a larger pattern. I don't have a good answer for that one, but 
> perhaps it's acceptable for now.
> 
> I'll write up a revision of the proposal soon and make sure the core team 
> gets my recommendation when they discuss the results of the review.

Thanks for keeping an open mind about this and listening to everyone’s feedback 
Jordan!  I really appreciate it.

> 
> ---
> 
> I'll respond to a few of the more intricate discussions tomorrow, including 
> the syntax of putting a new declaration inside the enum rather than outside. 
> Thank you again, everyone, and happy new year!

Happy new year to you as well!

> 
> Jordan
> 
> ___
> swift-evolution mailing list
> 

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-02 Thread Matthew Johnson via swift-evolution

> On Jan 2, 2018, at 2:09 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
> On Tue, Jan 2, 2018 at 1:46 PM, Matthew Johnson <matt...@anandabits.com 
> <mailto:matt...@anandabits.com>> wrote:
> 
> 
> Sent from my iPad
> 
> On Jan 2, 2018, at 12:48 PM, Xiaodi Wu <xiaodi...@gmail.com 
> <mailto:xiaodi...@gmail.com>> wrote:
> 
>> On Tue, Jan 2, 2018 at 9:38 AM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>> Sent from my iPad
>> 
>> On Jan 1, 2018, at 11:47 PM, Chris Lattner <clatt...@nondot.org 
>> <mailto:clatt...@nondot.org>> wrote:
>> 
>>>> On Dec 31, 2017, at 12:14 PM, Matthew Johnson via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> I agree that we need a solution to the problem described.  I also agree 
>>>> that non-exhaustive is most in keeping with the overall design of Swift at 
>>>> module boundaries.  However, I believe this proposal should be modified 
>>>> before being accepted
>>> 
>>> Thanks for writing this up - you’ve explained a common concern in an 
>>> interesting way:
>>> 
>>>> This is likely to be a relatively rare need mostly encountered by 3rd 
>>>> party libraries but it will happen.  When it does happen it would be 
>>>> really unfortunate to be forced to use a `default` clause rather than 
>>>> something like a `future` clause which will produce an error when compiled 
>>>> against an SDK where the enum includes cases that are not covered.  I can 
>>>> imagine cases where this catch-all case would need to do something other 
>>>> than abort the program so I do not like the `switch!` suggestion that has 
>>>> been discussed.  The programmer should still be responsible for 
>>>> determining the behavior of unknown cases.
>>> ..
>>>> While library authors have a legitimate need to reserve the right to 
>>>> introduce new cases for some enums this need can be met without taking 
>>>> away a useful tool for generating static compiler errors when code does 
>>>> not align with intent (in this case, the intent being to cover all known 
>>>> cases).  Switch statements working with these kinds of enums should be 
>>>> required to cover unknown cases but should be able to do so while still 
>>>> being statically checked with regards to known cases.  
>>> 
>>> I think that this could be the crux of some major confusion, the root of 
>>> which is the difference between source packages and binary packages that 
>>> are updated outside your control (e.g. the OS, or a dynamic library that is 
>>> updated independently of your app like a 3rd party plugin).  Consider:
>>> 
>>> 1) When dealing with independently updated binary packages, your code *has* 
>>> to implement some behavior for unexpected cases if the enum is 
>>> non-exhaustive.  It isn’t acceptable to not handle that case, and it isn’t 
>>> acceptable to abort because then your app will start crashing when a new OS 
>>> comes out. You have to build some sort of fallback into your app.
>>> 
>>> 2) When dealing with a source package that contributes to your app (e.g. 
>>> through SwiftPM), *YOU* control when you update that package, and therefore 
>>> it is entirely reasonable to exhaustively handle enums even if that package 
>>> owner didn’t “intend” for them to be exhaustive.  When *you* chose to 
>>> update the package, you get the “unhandled case” error, and you have 
>>> maximal “knowability” about the package’s behavior.
>>> 
>>> 
>>> It seems that your concern stems from the fact that the feature as proposed 
>>> is aligned around module boundaries, and therefore overly punishes source 
>>> packages like #2.  I hope you agree that in case #1, that the feature as 
>>> proposed is the right and only thing we can do: you really do have to 
>>> handle unknown future cases somehow.
>>> 
>>> If I’m getting this right, then maybe there is a variant of the proposal 
>>> that ties the error/warning behavior to whether or not a module is a source 
>>> module vs a binary module.  The problem with that right now is that we have 
>>> no infrastructure in the language to know this…
>> 
>> Hi Chris, thanks for your reply.
>> 
>> The concern you describe isn’t exa

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-02 Thread Matthew Johnson via swift-evolution

> On Jan 2, 2018, at 3:41 PM, Xiaodi Wu  wrote:
> 
> On Tue, Jan 2, 2018 at 3:27 PM, Kevin Nattinger  > wrote:
> [...]
> 
>>> in what other circumstances do we insist that the compiler inform the end 
>>> user about future additions to the API at compile time?
>> 
>> This isn’t a request for the compiler to inform the user about future 
>> additions to an API.  It is a request to validate the compiler’s knowledge 
>> of the current state of an API with the current state of the source code. 
>> 
>> Well, it's of course impossible to inform the user about future additions, 
>> so that's poorly phrased on my part. It's about the compiler informing the 
>> end user about *new* additions, part of the *current* state of the API, that 
>> have cropped up since the user last revised the code when the API was in a 
>> *previous* state (or, indistinguishably, members of which a user is unaware 
>> regardless of the temporal sequence of when such members were added). In 
>> what other circumstances do we insist that the compiler perform this service?
> 
> Enums. That's literally how they work today. You are arguing in favor of 
> actively removing compiler-aided correctness.
> 
> There's also protocol requirements
> 
> No, that's now how enums work today, and it's not how protocol requirements 
> work today. Enums today are all semantically exhaustive; if a case is added 
> in a later version of a library, it's semantically a *different* enum type 
> that happens to share the same name. Not considering all the cases of an 
> exhaustive enum is an _error_, not a _warning_, because there is no basis on 
> which to proceed. This will not change with the proposal. Likewise, adding a 
> protocol requirement without a default implementation is source-breaking. The 
> result is a compiler _error_.
> 
> The question is, what non-source breaking API additions today cause the 
> compiler to inform the end user of such additions?

Posing the question this way takes it as a given that adding a case to a 
resilient enum is non-source breaking with a full stop.  The position of 
everyone asking for something like `future` / `unknown` as an alternative to 
`default` is exactly that this should not be the case.  Instead, adding a case 
should always be binary compatible and should be source compatible by default, 
but authors should have the ability to opt-in to making case additions be 
source-breaking for individual switch statements.  

When you view it this way we are not asking the compiler to inform us of a 
non-source breaking addition.  We are asking the compiler to treat an addition 
as source breaking in a specific context.

> The answer is: none whatsoever. Not new methods or properties on a type, not 
> even new protocol requirements that have a default implementation.
> 
> 
> and, arguably, deprecated methods with a proper message ("use foo instead").
> 
> 



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


Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Jan 2, 2018, at 12:48 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
>> On Tue, Jan 2, 2018 at 9:38 AM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> 
>> Sent from my iPad
>> 
>> On Jan 1, 2018, at 11:47 PM, Chris Lattner <clatt...@nondot.org> wrote:
>> 
>>>> On Dec 31, 2017, at 12:14 PM, Matthew Johnson via swift-evolution 
>>>> <swift-evolution@swift.org> wrote:
>>>> 
>>>> I agree that we need a solution to the problem described.  I also agree 
>>>> that non-exhaustive is most in keeping with the overall design of Swift at 
>>>> module boundaries.  However, I believe this proposal should be modified 
>>>> before being accepted
>>> 
>>> Thanks for writing this up - you’ve explained a common concern in an 
>>> interesting way:
>>> 
>>>> This is likely to be a relatively rare need mostly encountered by 3rd 
>>>> party libraries but it will happen.  When it does happen it would be 
>>>> really unfortunate to be forced to use a `default` clause rather than 
>>>> something like a `future` clause which will produce an error when compiled 
>>>> against an SDK where the enum includes cases that are not covered.  I can 
>>>> imagine cases where this catch-all case would need to do something other 
>>>> than abort the program so I do not like the `switch!` suggestion that has 
>>>> been discussed.  The programmer should still be responsible for 
>>>> determining the behavior of unknown cases.
>>> ..
>>>> While library authors have a legitimate need to reserve the right to 
>>>> introduce new cases for some enums this need can be met without taking 
>>>> away a useful tool for generating static compiler errors when code does 
>>>> not align with intent (in this case, the intent being to cover all known 
>>>> cases).  Switch statements working with these kinds of enums should be 
>>>> required to cover unknown cases but should be able to do so while still 
>>>> being statically checked with regards to known cases.  
>>> 
>>> I think that this could be the crux of some major confusion, the root of 
>>> which is the difference between source packages and binary packages that 
>>> are updated outside your control (e.g. the OS, or a dynamic library that is 
>>> updated independently of your app like a 3rd party plugin).  Consider:
>>> 
>>> 1) When dealing with independently updated binary packages, your code *has* 
>>> to implement some behavior for unexpected cases if the enum is 
>>> non-exhaustive.  It isn’t acceptable to not handle that case, and it isn’t 
>>> acceptable to abort because then your app will start crashing when a new OS 
>>> comes out. You have to build some sort of fallback into your app.
>>> 
>>> 2) When dealing with a source package that contributes to your app (e.g. 
>>> through SwiftPM), *YOU* control when you update that package, and therefore 
>>> it is entirely reasonable to exhaustively handle enums even if that package 
>>> owner didn’t “intend” for them to be exhaustive.  When *you* chose to 
>>> update the package, you get the “unhandled case” error, and you have 
>>> maximal “knowability” about the package’s behavior.
>>> 
>>> 
>>> It seems that your concern stems from the fact that the feature as proposed 
>>> is aligned around module boundaries, and therefore overly punishes source 
>>> packages like #2.  I hope you agree that in case #1, that the feature as 
>>> proposed is the right and only thing we can do: you really do have to 
>>> handle unknown future cases somehow.
>>> 
>>> If I’m getting this right, then maybe there is a variant of the proposal 
>>> that ties the error/warning behavior to whether or not a module is a source 
>>> module vs a binary module.  The problem with that right now is that we have 
>>> no infrastructure in the language to know this…
>> 
>> Hi Chris, thanks for your reply.
>> 
>> The concern you describe isn’t exactly what I was describing but it is 
>> related.  John McCall recently posted a sketch of a solution to the concern 
>> you describe which looked great to me.  I don’t have time to look up the 
>> link this morning but I think it was in this review thread.
>> 
>> The actual concern I am describing is where a 3rd party library (or app) 
>> wants to switch over a 

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2018-01-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

>> On Jan 1, 2018, at 11:47 PM, Chris Lattner <clatt...@nondot.org> wrote:
>> 
>> On Dec 31, 2017, at 12:14 PM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> I agree that we need a solution to the problem described.  I also agree that 
>> non-exhaustive is most in keeping with the overall design of Swift at module 
>> boundaries.  However, I believe this proposal should be modified before 
>> being accepted
> 
> Thanks for writing this up - you’ve explained a common concern in an 
> interesting way:
> 
>> This is likely to be a relatively rare need mostly encountered by 3rd party 
>> libraries but it will happen.  When it does happen it would be really 
>> unfortunate to be forced to use a `default` clause rather than something 
>> like a `future` clause which will produce an error when compiled against an 
>> SDK where the enum includes cases that are not covered.  I can imagine cases 
>> where this catch-all case would need to do something other than abort the 
>> program so I do not like the `switch!` suggestion that has been discussed.  
>> The programmer should still be responsible for determining the behavior of 
>> unknown cases.
> ..
>> While library authors have a legitimate need to reserve the right to 
>> introduce new cases for some enums this need can be met without taking away 
>> a useful tool for generating static compiler errors when code does not align 
>> with intent (in this case, the intent being to cover all known cases).  
>> Switch statements working with these kinds of enums should be required to 
>> cover unknown cases but should be able to do so while still being statically 
>> checked with regards to known cases.  
> 
> I think that this could be the crux of some major confusion, the root of 
> which is the difference between source packages and binary packages that are 
> updated outside your control (e.g. the OS, or a dynamic library that is 
> updated independently of your app like a 3rd party plugin).  Consider:
> 
> 1) When dealing with independently updated binary packages, your code *has* 
> to implement some behavior for unexpected cases if the enum is 
> non-exhaustive.  It isn’t acceptable to not handle that case, and it isn’t 
> acceptable to abort because then your app will start crashing when a new OS 
> comes out. You have to build some sort of fallback into your app.
> 
> 2) When dealing with a source package that contributes to your app (e.g. 
> through SwiftPM), *YOU* control when you update that package, and therefore 
> it is entirely reasonable to exhaustively handle enums even if that package 
> owner didn’t “intend” for them to be exhaustive.  When *you* chose to update 
> the package, you get the “unhandled case” error, and you have maximal 
> “knowability” about the package’s behavior.
> 
> 
> It seems that your concern stems from the fact that the feature as proposed 
> is aligned around module boundaries, and therefore overly punishes source 
> packages like #2.  I hope you agree that in case #1, that the feature as 
> proposed is the right and only thing we can do: you really do have to handle 
> unknown future cases somehow.
> 
> If I’m getting this right, then maybe there is a variant of the proposal that 
> ties the error/warning behavior to whether or not a module is a source module 
> vs a binary module.  The problem with that right now is that we have no 
> infrastructure in the language to know this…

Hi Chris, thanks for your reply.

The concern you describe isn’t exactly what I was describing but it is related. 
 John McCall recently posted a sketch of a solution to the concern you describe 
which looked great to me.  I don’t have time to look up the link this morning 
but I think it was in this review thread.

The actual concern I am describing is where a 3rd party library (or app) wants 
to switch over a non-exhaustive enum provided by a module that is a binary (not 
source) dependency.  The author of the 3rd party library may have a legitimate 
reason to switch over an enum despite the author of the binary module reserving 
the right to add additional cases.  

When this circumstance arises they will do it using the tools provided by the 
language.  Regardless of the final language solution they obviously need to 
cover unknown cases - their library could be shipping on a device which 
receives an update to the binary dependency that contains a new case.  I agree 
with you that a language-defined crash is not appropriate.  The author of the 
switch must take responsibility for the behavior of unknown cases.  

I am arguing that these “pseudo-exhaustive” switch statements will exist in the 
wild.  The crucial point of cont

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2017-12-31 Thread Matthew Johnson via swift-evolution
I have been busy over the holidays and have been considering the arguments in 
this thread so my review is late in coming.
> What is your evaluation of the proposal?
> 
I agree that we need a solution to the problem described.  I also agree that 
non-exhaustive is most in keeping with the overall design of Swift at module 
boundaries.  However, I believe this proposal should be modified before being 
accepted

My primary concern (shard with many others) is that this proposal takes away an 
important tool of exhaustiveness checking in cases where we need to switch over 
an enum vended by a library which was not declared exhaustive.  

This is likely to be a relatively rare need mostly encountered by 3rd party 
libraries but it will happen.  When it does happen it would be really 
unfortunate to be forced to use a `default` clause rather than something like a 
`future` clause which will produce an error when compiled against an SDK where 
the enum includes cases that are not covered.  I can imagine cases where this 
catch-all case would need to do something other than abort the program so I do 
not like the `switch!` suggestion that has been discussed.  The programmer 
should still be responsible for determining the behavior of unknown cases.

I find the argument of untestable code to be completely unconvincing.  As has 
been noted several times in this thread, when all known cases are covered in a 
switch statement the code is equally untestable whether the “other" pattern is 
spelled `default` or `future`.  There has been some discussion of finding a way 
for the compiler to support an extra test-only value somehow.  A tool like this 
could be quite useful regardless of how the “other” pattern is spelled but the 
presence or absence of this tool should not influence the decision to include 
“future” or not.

While library authors have a legitimate need to reserve the right to introduce 
new cases for some enums this need can be met without taking away a useful tool 
for generating static compiler errors when code does not align with intent (in 
this case, the intent being to cover all known cases).  Switch statements 
working with these kinds of enums should be required to cover unknown cases but 
should be able to do so while still being statically checked with regards to 
known cases.  

People are going to write these kinds of switch statements whether the language 
helps them out or not.  Instead of taking a moral standpoint that says “that is 
bad, don’t do it” the language should continue to provide assistance to the 
degree it can.  If the core team remains unconvinced about use cases for these 
kinds of "pseudo-exhaustive” switches I suggest a brief extension to the review 
with a specific request for example use cases.  I believe several good examples 
could be quickly identified in existing open source libraries.

A secondary concern I have is the @exhaustive keyword itself.  I strongly 
believe Swift will be better suited by a more general keyword that is also 
applicable in other contexts.  

I authored earlier discussions about how exhaustiveness could fit into the 
access control system.  This is discussed as an alternative under “closed” and 
“open”.  I think “closed” as a “greater than public” availability with respect 
to switch statements is perfectly sensible.  In this design the access control 
hierarchy would have two branches in different directions that are both 
"greater than public”.  This direction had some proponents but didn’t appear to 
gain traction with the core team.  In case the core team discusses this option 
I do still prefer it.

Another direction that has been discussed in this thread is to use a keyword 
that is shared with fixed layout structs.  Both of these feel like better 
options than a special case, enum-only attribute.  On the other hand, this is a 
relatively minor concern.
> Is the problem being addressed significant enough to warrant a change to 
> Swift?
> 
Yes.
> Does this proposal fit well with the feel and direction of Swift?
> 
For the most part.  However, it does introduce a special case attribute 
specifically for enums.  I would prefer if we try to avoid that and believe it 
is in keeping with the direction of Swift to try and avoid these.
> If you have used other languages or libraries with a similar feature, how do 
> you feel that this proposal compares to those?
> 
I have not worked with a language that supported both exhaustive and 
non-exhaustive enums.
> How much effort did you put into your review? A glance, a quick reading, or 
> an in-depth study?
> 
In-depth study of the proposal and all of the threads on the list.___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [swift-dev] Re-pitch: Deriving collections of enum cases

2017-12-30 Thread Matthew Johnson via swift-evolution
This looks really nice.  Thank you for doing the legwork of researching 
previous discussions and writing up a detailed proposal!

The motivation discusses the common use case of using an enum in a data source 
implementation which requires 0-based Int indices.  However, the proposed 
solution as-written does not specifically address this use case.  Is the intent 
that the compiler-synthesized implementation always uses indices meeting 
0-based Int requirement?  If so it is probably worth stating this explicitly in 
the proposal.

Sent from my iPad

> On Dec 30, 2017, at 5:12 PM, Jacob Bandes-Storch via swift-evolution 
>  wrote:
> 
> Sorry for the delay. I've just updated the proposal text to incorporate 
> various changes, some contributed by others.
> 
> https://github.com/jtbandes/swift-evolution/blob/case-enumerable/proposals/-derived-collection-of-enum-cases.md
> 
> Robert's implementation is a good start, but will need to be updated to match 
> the naming choice in the final proposal, and to use associatedtype.
> 
>> On Fri, Dec 8, 2017 at 9:19 PM, Step Christopher 
>>  wrote:
>> Has this stalled out again? I would like to help with the proposal and even 
>> attempt implementation. 
>> 
>> I also need to catch up on the resilient discussion regarding enum case 
>> ordering. 
>> 
>>> On Nov 14, 2017, at 10:50 PM, Jacob Bandes-Storch via swift-evolution 
>>>  wrote:
>>> 
>>> 
>>> 
>>> Jacob Bandes-Storch
>>> 
>>> On Tue, Nov 14, 2017 at 9:06 PM, Brent Royal-Gordon 
>>>  wrote:
>> On Nov 14, 2017, at 5:21 PM, Xiaodi Wu  wrote:
>> 
>> 1. It must be possible to easily access the count of values, and to 
>> access any particular value using contiguous `Int` indices. This could 
>> be achieved either by directly accessing elements in the list of values 
>> through an Int subscript, or by constructing an Array from the list of 
>> values.
>> 
>> 2. It must be possible to control the order of values in the list of 
>> values, either by using source order or through some other simple, 
>> straightforward mechanism.
>  
> OK, first of all, nowhere in the proposal text are these requirements 
> stated as part of the use case. You're free to put forward new use cases, 
> but here I am trying to design the most elegant way to fulfill a stated 
> need and you're telling me that it's something other than what's written.
 
 Honestly, re-reading the proposal, it never cites a fully-formed use case. 
 Instead, it cites several blog posts, Stack Overflow questions, and small 
 code samples without digging in to the underlying reasons why developers 
 are doing what they're doing. Most of the people discussing it so far seem 
 to have had a tacit understanding that we wanted roughly Array-like 
 access, but we haven't explicitly dug into which properties of an Array 
 are important.
 
 (If anyone involved feels like they had a different understanding of the 
 use case, please speak up.)
 
 I think this is a place where the proposal can be improved, and I'm 
 willing to do some writing to improve it.
>>> 
>>> For the record, I would be happy to add co-authors (or even relinquish 
>>> authorship entirely—I don't really care whose name is on this, it just 
>>> needs to happen!) if you or anyone else has improved wording, motivation, 
>>> justification, etc. to contribute.
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2017-12-21 Thread Matthew Johnson via swift-evolution

> On Dec 21, 2017, at 2:17 PM, John McCall  wrote:
> 
> 
>> On Dec 21, 2017, at 3:10 PM, Matthew Johnson > > wrote:
>> 
>> 
>>> On Dec 21, 2017, at 2:06 PM, John McCall >> > wrote:
>>> 
>>> 
 On Dec 21, 2017, at 2:41 PM, Matthew Johnson > wrote:
 
 
> On Dec 21, 2017, at 1:26 PM, John McCall via swift-evolution 
> > wrote:
> 
>> 
>> On Dec 21, 2017, at 2:03 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> 
>> 
>>> On Dec 20, 2017, at 12:35, Karl Wagner >> > wrote:
>>> 
>>> 
>>> 
 On 20. Dec 2017, at 19:54, Jordan Rose > wrote:
 
 
 
> On Dec 20, 2017, at 05:36, Karl Wagner via swift-evolution 
> > wrote:
> 
> 
> 
>> On 19. Dec 2017, at 23:58, Ted Kremenek via swift-evolution 
>> > 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
>>  
>> +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 

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2017-12-21 Thread Matthew Johnson via swift-evolution

> On Dec 21, 2017, at 2:06 PM, John McCall  wrote:
> 
> 
>> On Dec 21, 2017, at 2:41 PM, Matthew Johnson > > wrote:
>> 
>> 
>>> On Dec 21, 2017, at 1:26 PM, John McCall via swift-evolution 
>>> > wrote:
>>> 
 
 On Dec 21, 2017, at 2:03 PM, Jordan Rose via swift-evolution 
 > wrote:
 
 
 
> On Dec 20, 2017, at 12:35, Karl Wagner  > wrote:
> 
> 
> 
>> On 20. Dec 2017, at 19:54, Jordan Rose > > wrote:
>> 
>> 
>> 
>>> On Dec 20, 2017, at 05:36, Karl Wagner via swift-evolution 
>>> > wrote:
>>> 
>>> 
>>> 
 On 19. Dec 2017, at 23:58, Ted Kremenek via swift-evolution 
 > 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
  
 +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 

Re: [swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

2017-12-21 Thread Matthew Johnson via swift-evolution

> On Dec 21, 2017, at 1:26 PM, John McCall via swift-evolution 
>  wrote:
> 
>> 
>> On Dec 21, 2017, at 2:03 PM, Jordan Rose via swift-evolution 
>> > wrote:
>> 
>> 
>> 
>>> On Dec 20, 2017, at 12:35, Karl Wagner >> > wrote:
>>> 
>>> 
>>> 
 On 20. Dec 2017, at 19:54, Jordan Rose > wrote:
 
 
 
> On Dec 20, 2017, at 05:36, Karl Wagner via swift-evolution 
> > wrote:
> 
> 
> 
>> On 19. Dec 2017, at 23:58, Ted Kremenek via swift-evolution 
>> > 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
>>  
>> +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 

Re: [swift-evolution] Refining SE-0185: Should providing a custom == suppress the default hashValue?

2017-12-15 Thread Matthew Johnson via swift-evolution
+1.  I think there is a reasonable general principle at work here: the 
semantics of the implementation of a refining protocol depend upon the 
semantics of the implementation of a refined protocol.  For this reason the 
compiler should not synthesize an implementation for a refining protocol unless 
it also synthesizes (and can therefore reason about) the implementation of the 
refined protocol.

> On Dec 15, 2017, at 11:58 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> SE-0185 is awesome, and brings the long-awaited ability for the compiler to 
> provide a default implementation of `==` and `hashValue` when you don't 
> provide one yourself. Doug and I were talking the other day and thought of a 
> potential pitfall: what should happen if you provide a manual implementation 
> of `==` without also manually writing your own `hashValue`? It's highly 
> likely that the default implementation of `hashValue` will be inconsistent 
> with `==` and therefore invalid in a situation like this:
> 
> struct Foo: Hashable {
>  // This property is "part of the value"
>  var involvedInEquality: Int
>  // This property isn't; maybe it's a cache or something like that
>  var notInvolvedInEquality: Int
> 
>  static func ==(a: Foo, b: Foo) -> Bool {
>return a.involvedInEquality == b.involvedInEquality
>  }
> }
> 
> As currently implemented, the compiler will still give `Foo` the default 
> hashValue implementation, which will use both of `Foo`'s properties to 
> compute the hash, even though `==` only tests one. This could be potentially 
> dangerous. Should we suppress the default hashValue derivation when an 
> explicit == implementation is provided?
> 
> -Joe
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] Optional Argument Chaining

2017-12-14 Thread Matthew Johnson via swift-evolution


Sent from my iPad

On Dec 13, 2017, at 11:13 PM, Stephen Celis  wrote:

>> On Dec 13, 2017, at 9:53 PM, Erica Sadun  wrote:
>> 
>> Chris L had a beautiful solution for an "Unwrappable" protocol that allowed 
>> all of the optional sugar to be extended to any type that had a biased 
>> `Wrapped` item, allowing it to be used with `Either`, `Wrapped`, etc as well 
>> as form the basis for `Optional` itself.
>> 
>> protocol Unwrappable {
>>  associatedtype Element
>>  func unwrap() -> Element?
>> }
> 
> It would definitely be nice to make "Optional" sugar work for non-"Optional" 
> types! (I think the goal for "async"/"await" is to make it work for any 
> continuation, so it's basically Haskell "do" notation for Swift!)
> 
> I'm not sure the "Unwrappable" protocol can handle many of the examples I 
> mentioned (accumulative errors, parallelism), though I wonder if it could be 
> designed differently to do so. The applicative structure requires just 2 
> functions[1]:
> 
>protocol Applicative: Functor {
>  static func pure(_ value: A) -> Self
>  static func <*> (lhs: Self<(A) -> B>, rhs: Self) -> Self 
>}
> 
> Such a protocol isn't possible in Swift (yet),

Thanks for jumping in and elaborating on a more general approach!  I don’t want 
to sidetrack the thread, but it actually is possible to encode higher-kindred 
types and protocols requiring them in Swift today.  It’s a bit clunky and 
requires some boilerplate but the technique is worth knowing.  
https://gist.github.com/anandabits/f12a77c49fc002cf68a5f1f62a0ac9c4

Some Kotlin folks have created a pretty robust FP library using the same 
technique: http://kategory.io/.

> but it could unlock this kind of sugar for everyone. Here's "Optional" 
> conformance:
> 
>extension Optional: Applicative {
>  static func pure(_ value: Wrapped) -> Wrapped? {
>return value // promoted to Optional.some
>  }
> 
>  static func <*> (lhs: Optional<(Wrapped) -> B>, rhs: Optional) -> B? {
>guard let lhs = lhs, rhs = rhs else { return nil }
>return lhs(rhs)
>  }
>}
> 
> We can't conform to such an "Applicative" protocol today, but we _can_ still 
> write and use these functions in a concrete manner! (Delete the conformance 
> and see!)
> 
> The original post in this thread had this example:
> 
>getPostageEstimate(source: String, destination: String, weight: Double)
> 
> If we were dealing with this function in the world of optional arguments, 
> here's how we could use our abstraction:
> 
>Optional.pure(curry(getPostageEstimate)) <*> john.address <*> 
> alice.address <*> pure(2.0)
> 
> It's not _too_ bad, though it's kinda noisy, we have to maintain a bunch of 
> custom code, we have to curry "getPostageEstimate" before passing it through, 
> we lose our argument labels, and we're living in custom operator world, which 
> can be disconcerting at first.
> 
> If Swift provided sugar over this structure, we'd merely need to do this:
> 
>getPostageEstimate(|source: john.address, destination: alice.address, 
> weight: 2.0|)
> 
> What's even neater is we can use this same format for types that wrap values 
> in other ways! Let's say the addresses are coming from untrusted sources and 
> need to be validated:
> 
>getPostageEstimate(|source: try validateAddr(john), destination: try 
> validateAddr(alice), weight: 2.0|)
> 
> If both addresses are invalid and "throw", we could get both errors and 
> render them at once to our end user.
> 
> Another example: what if we want to get the postage estimate for two 
> addresses that we need to fetch asynchronously:
> 
>getPostageEstimate(|source: await myAddress(), destination: await 
> theirAddress(), weight: 2.0|)
> 
> Such a syntax allows those requests to run in parallel and not block :)
> 
> In these examples, "Optional" promotion becomes applicative promotion ("2.0" 
> is getting wrapped automatically), which might open a can of worms but it's a 
> fun can to think about!
> 
> 
> --
> [1]: Well, technically it also requires "map", since any applicative is a 
> functor, and it also requires that it follows some math laws.
> 
> 
> Stephen
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Optional Argument Chaining

2017-12-11 Thread Matthew Johnson via swift-evolution
It’s worth mentioning that the problem this thread is discussing can be 
generalized to idioms / applicative.  The specific case here is for Optional 
but many other types could benefit from an elegant syntactic solution to this 
problem.  It might be worth exploring a more general solution.  Here’s a link 
to how this is handled in Idris: 
http://docs.idris-lang.org/en/latest/tutorial/interfaces.html#idiom-brackets 
.

Matthew

> On Dec 11, 2017, at 12:01 PM, Jared Khan via swift-evolution 
>  wrote:
> 
> 1. Correct
> 
> 2. It felt natural to me. It’s analogous to the existing optional chaining 
> scenarios and composes nicely. I think it’s about as understandable as 
> existing chaining, a newbie would have to look it up to discover its meaning. 
> What are your thoughts on this particular syntax (ignoring 3. momentarily)? 
> Hopefully others in this thread can share their views too.
> As for how common I’d expect it to be, it’s something I’ve run into myself a 
> few times. Again, I hope members of this list can give their view on if this 
> would be useful to them.
> 
> 3. I’m not entirely sure what the grammar situation is yet but afaik ‘?’ has 
> never been available as a postfix operator. Perhaps I’m missing your point, 
> could you demonstrate where it is allowed?
> 
> Best,
> Jared
> 
>> On 11 Dec 2017, at 17:07, Magnus Ahltorp  wrote:
>> 
>> 
>>> 12 Dec. 2017 01:30 Jared Khan via swift-evolution 
>>>  wrote:
>>> 
>>> I'd like to propose a syntax addition that acts to ease some things that I 
>>> believe should fall under the umbrella of 'optional chaining'. Optional 
>>> chaining allows us to access the properties of an optional value and return 
>>> nil if any link in that chain breaks. I propose we introduce syntax to 
>>> allow similar chaining when passing optional valued parameters to functions 
>>> that expect that parameter to be non-optional.
>> 
>> 1. Am I right in assuming that you propose that the suffix operator "?" 
>> would make the result of the surrounding method/function call optional, so 
>> that a(b(c?)) would make the result of the "b" function call optional, but 
>> not the "a" function call, and that it would be a(b(c?)?) if we would like 
>> to propagate this two levels?
>> 
>> 2. If that is the case, is that understandable/neat enough? How common would 
>> you expect this to be?
>> 
>> 3. For some reason, (in current Swift) the suffix operator "?" seems to be 
>> allowed in intra-expression syntax, and only fails when the inter-expression 
>> syntax is checked for optionality congruence. Is there a reason for this? I 
>> would have expected that the congruence error "cannot use optional chaining 
>> on non-optional value of type" would never be seen for a lone "?", since the 
>> error message "'?' must be followed by a call, member lookup, or subscript" 
>> would always be displayed first if it was checked first. The "." operator 
>> checks intra-expression syntax first, before checking congruence. Is this a 
>> sign that "?" as a suffix operator is already somewhat operational as an 
>> operator for optional types? I have a faint recollection that it was doing 
>> something in earlier versions of Swift.
>> 
>> /Magnus
>> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [RFC] Associated type inference

2017-12-07 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Dec 7, 2017, at 5:27 PM, Douglas Gregor via swift-evolution 
>  wrote:
> 
> 
> 
>> On Dec 2, 2017, at 9:23 PM, Dave Abrahams  wrote:
>> 
>> 
>>> On Nov 30, 2017, at 2:28 PM, Douglas Gregor via swift-evolution 
>>>  wrote:
>> 
>>> What’s a Good Solution Look Like?
>>> Our current system for associated type inference and associated type 
>>> defaults is buggy and complicated.
>> 
>> Well, that’s the problem, then.  Don’t worry, I won’t suggest that you 
>> simply fix the implementation, because even if there weren’t bugs and the 
>> system were predictable I’d still think we could improve the situation for 
>> users by making associated type default declarations more explicit.
>> 
>>> The compiler gets it right often enough that people depend on it, but I 
>>> don’t think anyone can reasonably be expected to puzzle out what’s going to 
>>> happen, and this area is rife with bugs. If we were to design a new 
>>> solution from scratch, what properties should it have?
>>> 
>>> It should allow the author of a protocol to provide reasonable defaults, so 
>>> the user doesn’t have to write them
>>> It shouldn’t require users to write typealiases for “obvious” cases, even 
>>> when they aren’t due to defaults
>>> It shouldn’t infer an inconsistent set of typealiases
>>> It should be something that a competent Swift programmer could reason about 
>>> when it will succeed, when and why it will fail, and what the resulting 
>>> inferred typealiases would be
>>> It should admit a reasonable implementation in the compiler that is 
>>> performant and robust
>> • It should cover all of the existing use cases.
>> • It should not break code at this point.
>> • We should have a migration strategy for existing code that avoids traps 
>> like silent semantic changes.
>> 
>> My bullet is important to me; I don’t think existing use cases are 
>> (inherently) so complex that we can sacrifice almost any of them and still 
>> end up with a sufficiently useful system.  At the very least, existing use 
>> cases provide the only guidance we really have as to what the feature should 
>> do.
> 
> I honestly don’t feel like a have a good handle on all of the use cases for 
> associated type inference, and it’s not something we can simply search for on 
> GitHub. But I think it covers most of them—and Matthew and Greg’s positive 
> feedback helps my confidence here. The biggest potential issue, I think, is 
> that we’ll no longer infer associated types from default implementations, 
> which protocol vendors might be relying on.

Hi Doug.  FWIW, I always explicitly state defaults in protocol declarations so 
inference in default implementations is something that I don’t use.  I think 
it’s very reasonable to require explicit declaration of the default.

There are a few areas where I can imagine a real impact.  The main one that I 
don’t think has been discussed yet is when conformance is declared in an 
extension but inference would need to consider a member declared in the 
original declaration.  This is likely to be pretty common given the requirement 
to declare stored properties in the original declaration and the common pattern 
of declaring conformance in an extension.  If implementation is feasible you 
might want to also consider the original declaration for a conformance that is 
stated in the same module (or even just the same file).

> 
>> 
>> I think we need to acknowledge that my second bullet is unattainable, at 
>> least if we want to improve type checking performance. Not breaking any code 
>> means that given any existing code, the compiler would have to explore the 
>> same solution space it currently does, and come up with the same answers.  
>> Improving performance would require new  declarations to use totally 
>> optional explicit syntax to prevent some explorations, and that’s an 
>> untenable user experience.
> 
> Yes, I agree.
> 
>> Which brings me to my third bullet: unless we are willing to break the code 
>> of protocol users (as opposed to vendors) we need to ensure that vendors can 
>> confidently convert code to use the new system without changing semantics.
> 
> Yeah, (2) below is basically that feature.
> 
>>  
>>> 
>>> A Rough Proposal
>>> I’ve been thinking about this for a bit, and I think there are three ways 
>>> in which we should be able to infer an associated type witness:
>>> 
>>> Associated type defaults, which are specified with the associated type 
>>> itself, e.g.,
>>> 
>>>   associatedtype Indices = DefaultIndices
>>> 
>>> These are easy to reason about for both the programmer and the compiler.
>>> Typealiases in (possibly constrained) protocol extensions, e.g.,
>>> 
>>>   extension RandomAccessCollection where Index : Strideable, Index.Stride 
>>> == IndexDistance {
>>> typealias RandomAccessCollection.Indices = CountableRange
>>>   }
>>> 
>>> I’m intentionally using some odd ‘.’ syntax 

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-03 Thread Matthew Johnson via swift-evolution

> On Dec 3, 2017, at 5:40 PM, Chris Lattner  wrote:
> 
> 
> 
>> On Dec 3, 2017, at 3:39 PM, Matthew Johnson > > wrote:
>> 
 If that's the concern, then it would be pretty straightforward to restrict 
 dynamic protocols for stdlib internal use only and expose only PyVal. The 
 trade-off is that all such bridging code would have to be shipped with 
 Swift itself.
>>> 
>>> Right, this is specifically mentioned as option #2 in the proposal:
>>> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438#reducing-potential-abuse
>>>  
>>> 
>>> 
>>> It sounds like Matthew’s concerns can be addressed by him +1’ing that 
>>> alternative when it comes up for review.
>> 
>> FWIW, another thought along these lines which would go even further in 
>> addressing my concerns would be to isolate PyVal and other dynamic types 
>> provided as part of Swift itself in a separate module which must be imported 
>> and linked against.  That would give teams an easy way to opt-out of these 
>> types being available in their code base in a centralized fashion.  
> 
> Matthew,
> 
> We have already had many directly analogous discussions, e.g. people who want 
> to forbid the force-unwrap operator and IUOs.  The conclusion, which has 
> worked well enough in the community for multiple years now, is to relegate 
> these kinds of coding standard to third party linter tools.

I view interoperability with dynamic languages as being independent of the core 
language so I don’t see that precedent as being necessarily applicable here.  
Interoperability with C is entirely different because it is the lingua franca 
of interoperability in general and predominant operating systems specifically.  
Further, force-unwrap and IUO are core parts of the language and not a library 
feature that could be provided in a separate module.  One could reasonably ask 
what makes dynamic language interoperability more central to the language than 
the facilities provided by Foundation?  We have to draw the line for the 
standard library somewhere and it isn’t as obvious to me as it sounds like it 
is to you that dynamic language interoperability should ship as part of the 
standard library.

That said, I don’t feel so strongly about this to debate it further.  It was 
just another suggestion that I thought might be palatable to you.  Apparently I 
was wrong.  :)

> 
> -Chris
> 

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


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-03 Thread Matthew Johnson via swift-evolution

> On Dec 3, 2017, at 5:38 PM, Chris Lattner  wrote:
> 
> 
> 
>> On Dec 3, 2017, at 3:34 PM, Matthew Johnson > > wrote:
>> 
>>> 
>>> On Dec 3, 2017, at 5:14 PM, Chris Lattner >> > wrote:
>>> 
>>> 
 On Dec 3, 2017, at 2:44 PM, Xiaodi Wu > wrote:
 
> 
> and you don’t realize that PyVal’s are involved.  However, if you are 
> actively writing the code, you have access to code completion and other 
> things that tell you these types, and if it is important for the clarity 
> of the code, you write this instead:
> 
>   let x :PyVal = foo()[“someKey”]
> 
> There is nothing specific to this proposal about this issue.
 
 See above.  In the case of PyVal specifically the concern is somewhat 
 mitigated by the name of the type.  That won’t necessarily always be the 
 case.
 
 If that's the concern, then it would be pretty straightforward to restrict 
 dynamic protocols for stdlib internal use only and expose only PyVal. The 
 trade-off is that all such bridging code would have to be shipped with 
 Swift itself.
>>> 
>>> Right, this is specifically mentioned as option #2 in the proposal:
>>> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438#reducing-potential-abuse
>>>  
>>> 
>>> 
>>> It sounds like Matthew’s concerns can be addressed by him +1’ing that 
>>> alternative when it comes up for review.
>> 
>> This would certainly address the majority of my concerns while still 
>> addressing the motivating use case.  I don’t think it’s an ideal solution 
>> but it’s one I could live with and perhaps it is the best tradeoff.  It 
>> would certainly focus the proposal more directly on the use case you care 
>> most about leaving the distraction of conformances by user-defined Swift 
>> types as a separate conversation.
> 
> 
>> If would had to choose an alternative is this preferable to you over some 
>> kind of usage-site annotation?
> 
> Yes, vastly.  This does not completely defeat the purpose of the proposal in 
> the first place.
> 
> 
> You miss my point.  My point is that AnyObject lookup was carefully 
> considered, has stood the test of time, and is the *right* answer.  Swift 
> 1 would not have been nearly as successful without it.
 
 I don’t think I do.  I was trying to agree with exactly the point that it 
 was the right answer in the early days of Swift and getting it right then 
 was essential to Swift’s success.  
>>> 
>>> Ok, but the “early days of Swift” are directly analogous to the present 
>>> days of other dynamic languages.
>> 
>> On a technical level that is true in many respects, but on a social level 
>> certainly not.  You would obviously know a lot better than I, but I imagine 
>> that Swift’s success at displacing Objective-C in the Apple world was not at 
>> all a foregone conclusion in the earliest days.  It is now a well 
>> established language with a significant user base that isn’t going anywhere.
> 
> Correct.  Similarly, it is also not a forgone conclusion that the Python and 
> Javascript communities will care.  Python and Javascript have at least a 
> couple orders of magnitude more programmers than Swift does. Swift is a toy 
> by comparison.

Understood, and the goal of attracting them is a worthy one!

> 
> -Chris
> 

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


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-03 Thread Matthew Johnson via swift-evolution

> On Dec 3, 2017, at 5:14 PM, Chris Lattner  wrote:
> 
> 
>> On Dec 3, 2017, at 2:44 PM, Xiaodi Wu > > wrote:
>> 
>>> 
>>> and you don’t realize that PyVal’s are involved.  However, if you are 
>>> actively writing the code, you have access to code completion and other 
>>> things that tell you these types, and if it is important for the clarity of 
>>> the code, you write this instead:
>>> 
>>> let x :PyVal = foo()[“someKey”]
>>> 
>>> There is nothing specific to this proposal about this issue.
>> 
>> See above.  In the case of PyVal specifically the concern is somewhat 
>> mitigated by the name of the type.  That won’t necessarily always be the 
>> case.
>> 
>> If that's the concern, then it would be pretty straightforward to restrict 
>> dynamic protocols for stdlib internal use only and expose only PyVal. The 
>> trade-off is that all such bridging code would have to be shipped with Swift 
>> itself.
> 
> Right, this is specifically mentioned as option #2 in the proposal:
> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438#reducing-potential-abuse
>  
> 
> 
> It sounds like Matthew’s concerns can be addressed by him +1’ing that 
> alternative when it comes up for review.

FWIW, another thought along these lines which would go even further in 
addressing my concerns would be to isolate PyVal and other dynamic types 
provided as part of Swift itself in a separate module which must be imported 
and linked against.  That would give teams an easy way to opt-out of these 
types being available in their code base in a centralized fashion.  

> 
>>> You miss my point.  My point is that AnyObject lookup was carefully 
>>> considered, has stood the test of time, and is the *right* answer.  Swift 1 
>>> would not have been nearly as successful without it.
>> 
>> I don’t think I do.  I was trying to agree with exactly the point that it 
>> was the right answer in the early days of Swift and getting it right then 
>> was essential to Swift’s success.  
> 
> Ok, but the “early days of Swift” are directly analogous to the present days 
> of other dynamic languages.  
> 
>> 
>> Aside from the historical necessity of AnyObject, it is also a very specific 
>> and widely know type that doesn’t have any statically available members at 
>> all and only looks up @objc members.  These properties help to reduce the 
>> risk that somebody misunderstands what is going on.
>> 
>> I imagine we could restrict all such dynamic types from having any 
>> statically available members without losing much.
> 
> This isn’t practical.  We need some traditionally defined members so that 
> PyVal can conform to standard protocols, like ExpressibleByIntegerLiteral and 
> many others.
> 
> -Chris
> 

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


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-03 Thread Matthew Johnson via swift-evolution

> On Dec 3, 2017, at 5:14 PM, Chris Lattner  wrote:
> 
> 
>> On Dec 3, 2017, at 2:44 PM, Xiaodi Wu > > wrote:
>> 
>>> 
>>> and you don’t realize that PyVal’s are involved.  However, if you are 
>>> actively writing the code, you have access to code completion and other 
>>> things that tell you these types, and if it is important for the clarity of 
>>> the code, you write this instead:
>>> 
>>> let x :PyVal = foo()[“someKey”]
>>> 
>>> There is nothing specific to this proposal about this issue.
>> 
>> See above.  In the case of PyVal specifically the concern is somewhat 
>> mitigated by the name of the type.  That won’t necessarily always be the 
>> case.
>> 
>> If that's the concern, then it would be pretty straightforward to restrict 
>> dynamic protocols for stdlib internal use only and expose only PyVal. The 
>> trade-off is that all such bridging code would have to be shipped with Swift 
>> itself.
> 
> Right, this is specifically mentioned as option #2 in the proposal:
> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438#reducing-potential-abuse
>  
> 
> 
> It sounds like Matthew’s concerns can be addressed by him +1’ing that 
> alternative when it comes up for review.

This would certainly address the majority of my concerns while still addressing 
the motivating use case.  I don’t think it’s an ideal solution but it’s one I 
could live with and perhaps it is the best tradeoff.  It would certainly focus 
the proposal more directly on the use case you care most about leaving the 
distraction of conformances by user-defined Swift types as a separate 
conversation.  If would had to choose an alternative is this preferable to you 
over some kind of usage-site annotation?

> 
>>> You miss my point.  My point is that AnyObject lookup was carefully 
>>> considered, has stood the test of time, and is the *right* answer.  Swift 1 
>>> would not have been nearly as successful without it.
>> 
>> I don’t think I do.  I was trying to agree with exactly the point that it 
>> was the right answer in the early days of Swift and getting it right then 
>> was essential to Swift’s success.  
> 
> Ok, but the “early days of Swift” are directly analogous to the present days 
> of other dynamic languages.

On a technical level that is true in many respects, but on a social level 
certainly not.  You would obviously know a lot better than I, but I imagine 
that Swift’s success at displacing Objective-C in the Apple world was not at 
all a foregone conclusion in the earliest days.  It is now a well established 
language with a significant user base that isn’t going anywhere.

>  
> 
>> 
>> Aside from the historical necessity of AnyObject, it is also a very specific 
>> and widely know type that doesn’t have any statically available members at 
>> all and only looks up @objc members.  These properties help to reduce the 
>> risk that somebody misunderstands what is going on.
>> 
>> I imagine we could restrict all such dynamic types from having any 
>> statically available members without losing much.
> 
> This isn’t practical.  We need some traditionally defined members so that 
> PyVal can conform to standard protocols, like ExpressibleByIntegerLiteral and 
> many others.
> 
> -Chris
> 

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


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-03 Thread Matthew Johnson via swift-evolution

> On Dec 3, 2017, at 11:36 AM, Chris Lattner  wrote:
> 
> On Dec 2, 2017, at 7:11 PM, Matthew Johnson  > wrote:
>>> 
>>> This does not improve clarity of code, it merely serves to obfuscate logic. 
>>>  It is immediately apparent from the APIs being used, the API style, and 
>>> the static types (in Xcode or through static declarations) that this is all 
>>> Python stuff.  
>> 
>> It may be immediately apparent when the types involved are obviously 
>> dynamic, such as in this example where Python.import is explicitly used.  
>> However, my concern is less about the intended use case of dynamic language 
>> interop than I am that this feature will be generally available to all types 
>> in Swift.  
>> 
>> This is big change from AnyObject dispatch.  It opens up the dynamism to 
>> types and contexts that are not necessarily obviously using dynamic lookup, 
>> callable, etc.  Maybe this won’t turn out to be a problem in practice but I 
>> still think it’s a legitimate concern.
> 
> Sure, it is a legit concern, but it is also nothing new.  This is the 
> standard concern with type inference.

The concern for me is orthogonal to type inference.  The name of a type 
supporting dynamic lookup will not necessarily provide any indication that the 
type supports dynamic lookup.

> 
> While there are weird cases, in practice, values do not get magicked out of 
> no-where.  They most commonly are either root values like:
> 
>   let np = Python.import(“foo”)
>   let pyInt = PyVal(42)
> 
> or they come for parameters:
> 
>   func f(x : PyVal) {
> 
> The place that is potentially surprising is when the type gets buried because 
> you’re working with some API that returns a [String, PyVal] dictionary or 
> something:
> 
> 
>   let x = foo()[“someKey”]
> 
> and you don’t realize that PyVal’s are involved.  However, if you are 
> actively writing the code, you have access to code completion and other 
> things that tell you these types, and if it is important for the clarity of 
> the code, you write this instead:
> 
>   let x :PyVal = foo()[“someKey”]
> 
> There is nothing specific to this proposal about this issue.

See above.  In the case of PyVal specifically the concern is somewhat mitigated 
by the name of the type.  That won’t necessarily always be the case.

> 
> 
>> I’m uncertain what the right answer is.  I’m still not really comfortable 
>> with opening up dynamic lookup to any user-defined type without some way to 
>> indicate to readers that dynamic lookup is happening in a piece of code.  
>> Maybe there is a less localized annotation that would indicate dynamic 
>> lookup is in effect for a larger chunk of code.  
> 
> You seem to be extremely concerned that people will adopt DynamicMemberLookup 
> for types where it doesn’t make sense and abuse the feature.  I am having a 
> real problem understanding what your concern is, so I’d really love for you 
> to explain some theoretical examples of the bad thing that happens: why 
> someone (non-maliciously) adopts the protocol, what code gets written, and 
> what harm actually comes from it.
> 
> Let me use a made up tale from a parallel universe to illustrate why I don’t 
> understand your concern.  Imagine if Swift didn’t already interoperate with 
> C, and did not already have IUOs.  Someone who cared about C language 
> interoperability would quickly realize that the ergonomics of importing 
> everything as strong optionals is a non-starter, jeopardizing the usability 
> of C interop, and would propose IUOs as a feature.
> 
> We’d then have a long and drawn out conversation about the various options on 
> how to model this, the pros and cons of each, and would settle on IUO as the 
> least bad design (as an aside, in our universe, when we went through the 
> design process that led to IUOs, this is exactly what happened, we even 
> considered syntaxing them as interobangs :-).
> 
> At that point, there would be a general uproar because IUOs have high 
> potential for abuse: Swift is “all about” strong types and safety, which IUOs 
> undermine.  Strong optionals are considered a pain to use by some people and 
> widely misunderstood (I think they are the biggest challenge in learning 
> Swift in practice), and so it is a reasonable feature that people could 
> pervasively adopt IUOs, leading to a much worse world all around.
> 
> 
> This made up parallel universe is exactly analogous to what is happening now. 
>  DynamicMemberLookup is no more dangerous and harmful than IUOs are.  They 
> will be one more tool in the toolbox.  While it is possible that someone will 
> abuse it, this will not be widespread.  People who are particularly worried 
> will build a single new rule into their linters (which already flag uses of 
> x!), and the world will keep revolving.

There is an important difference between IUOs and dynamic lookup in my mind.  
In the case of 

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-03 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Dec 3, 2017, at 10:40 AM, David Hart <da...@hartbit.com> wrote:
> 
> 
> 
>> On 3 Dec 2017, at 04:11, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>>> On Dec 2, 2017, at 7:40 PM, Chris Lattner <clatt...@nondot.org> wrote:
>>> 
>>> On Dec 2, 2017, at 2:13 PM, Matthew Johnson <matt...@anandabits.com> wrote:
>>>>> For all those reasons, we really do need something like AnyObject 
>>>>> dispatch if we care about working with dynamically typed languages.  The 
>>>>> design I’m suggesting carefully cordons this off into its own struct 
>>>>> type, so it doesn’t infect the rest of the type system, and is 
>>>>> non-invasive in the compiler.
>>>> 
>>>> I am quite familiar with dynamic languages and agree that this is 
>>>> necessary if we are going to fully open up access to these languages from 
>>>> Swift.
>>> 
>>> Ok, then it appears you agree that something like anyobject dispatch is 
>>> necessary for effective dynamic language interop.
>>> 
>>>>>> I strongly urge you to reconsider the decision of that dynamic members 
>>>>>> must be made available with no indication at usage sites.  An indication 
>>>>>> of dynamic lookup at usage sites aligns very well (IMO) with the rest of 
>>>>>> Swift (AnyObject lookup aside) by calling attention to code that 
>>>>>> requires extra care to get right.
>>>>> 
>>>>> I don’t understand this.  The proposal is fully type safe, and this 
>>>>> approach is completely precedented by AnyObject.  Swift’s type system 
>>>>> supports many ways to express fallibility, and keeping those decisions 
>>>>> orthogonal to this proposal is the right thing to do, because it allows 
>>>>> the author of the type to decide what model makes sense for them.
>>>> 
>>>> Allowing the author of the type to choose whether the mechanism is hidden 
>>>> or visible is exactly what I don’t want to allow.  I think you have the 
>>>> right design regarding types and semantics - the author chooses.  But I 
>>>> don’t want these calls to look like ordinary member lookup when I’m 
>>>> reading code.  
>>>> 
>>>> They inherently have a much greater chance of failure than ordinary member 
>>>> lookup.  Further, authors are likely to choose immediate traps or nil IUO 
>>>> as failure modes as forcing users to deal with Optional on every call is 
>>>> likely to be untenable.  I believe this behavior should be represented by 
>>>> some kind of syntax at the usage site.  I don’t believe it is an undue 
>>>> burden.  It would make the dynamic lookup semantic clear to all readers 
>>>> and would help to discourage abuse.
>>> 
>>> I believe that adding explicit syntax would be counterproductive to your 
>>> goals, and would not make dynamic lookup syntax more clear.  I assume that 
>>> you would also want the same thing for DynamicCallable too, and operator 
>>> overloads, subscripts, and every other operation you perform on these 
>>> values, since they all have the exact same behavior.
>>> 
>>> If we required some syntax even as minimal as “foo.^bar” and "baz^(42)”, 
>>> that change would turn this (which uses runtime failing or IUO return 
>>> values like AnyObject):
>>> 
>>> let np = Python.import("numpy")
>>> let x = np.array([6, 7, 8])
>>> let y =  np.arange(24).reshape(2, 3, 4)
>>> 
>>> let a = np.ones(3, dtype: np.int32)
>>> let b = np.linspace(0, pi, 3)
>>> let c = a+b
>>> let d = np.exp(c)
>>> print(d)
>>> 
>>> into:
>>> 
>>> let np = Python.import("numpy")
>>> let b = np^.array^([6, 7, 8])
>>> let y =  np^.arange^(24)^.reshape^(2, 3, 4)
>>> 
>>> let a = np^.ones^(3, dtype: np^.int32)
>>> let b = np^.linspace^(0, pi, 3)
>>> let c = a+^b
>>> let d = np^.exp^(c)
>>> 
>>> This does not improve clarity of code, it merely serves to obfuscate logic. 
>>>  It is immediately apparent from the APIs being used, the API style, and 
>>> the static types (in Xcode or through static declarations) that this is all 
>>>

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Dec 2, 2017, at 7:40 PM, Chris Lattner  wrote:
> 
> On Dec 2, 2017, at 2:13 PM, Matthew Johnson  wrote:
>>> For all those reasons, we really do need something like AnyObject dispatch 
>>> if we care about working with dynamically typed languages.  The design I’m 
>>> suggesting carefully cordons this off into its own struct type, so it 
>>> doesn’t infect the rest of the type system, and is non-invasive in the 
>>> compiler.
>> 
>> I am quite familiar with dynamic languages and agree that this is necessary 
>> if we are going to fully open up access to these languages from Swift.
> 
> Ok, then it appears you agree that something like anyobject dispatch is 
> necessary for effective dynamic language interop.
> 
 I strongly urge you to reconsider the decision of that dynamic members 
 must be made available with no indication at usage sites.  An indication 
 of dynamic lookup at usage sites aligns very well (IMO) with the rest of 
 Swift (AnyObject lookup aside) by calling attention to code that requires 
 extra care to get right.
>>> 
>>> I don’t understand this.  The proposal is fully type safe, and this 
>>> approach is completely precedented by AnyObject.  Swift’s type system 
>>> supports many ways to express fallibility, and keeping those decisions 
>>> orthogonal to this proposal is the right thing to do, because it allows the 
>>> author of the type to decide what model makes sense for them.
>> 
>> Allowing the author of the type to choose whether the mechanism is hidden or 
>> visible is exactly what I don’t want to allow.  I think you have the right 
>> design regarding types and semantics - the author chooses.  But I don’t want 
>> these calls to look like ordinary member lookup when I’m reading code.  
>> 
>> They inherently have a much greater chance of failure than ordinary member 
>> lookup.  Further, authors are likely to choose immediate traps or nil IUO as 
>> failure modes as forcing users to deal with Optional on every call is likely 
>> to be untenable.  I believe this behavior should be represented by some kind 
>> of syntax at the usage site.  I don’t believe it is an undue burden.  It 
>> would make the dynamic lookup semantic clear to all readers and would help 
>> to discourage abuse.
> 
> I believe that adding explicit syntax would be counterproductive to your 
> goals, and would not make dynamic lookup syntax more clear.  I assume that 
> you would also want the same thing for DynamicCallable too, and operator 
> overloads, subscripts, and every other operation you perform on these values, 
> since they all have the exact same behavior.
> 
> If we required some syntax even as minimal as “foo.^bar” and "baz^(42)”, that 
> change would turn this (which uses runtime failing or IUO return values like 
> AnyObject):
> 
>   let np = Python.import("numpy")
>   let x = np.array([6, 7, 8])
>   let y =  np.arange(24).reshape(2, 3, 4)
>   
>   let a = np.ones(3, dtype: np.int32)
>   let b = np.linspace(0, pi, 3)
>   let c = a+b
>   let d = np.exp(c)
>   print(d)
> 
> into:
> 
>   let np = Python.import("numpy")
>   let b = np^.array^([6, 7, 8])
>   let y =  np^.arange^(24)^.reshape^(2, 3, 4)
>   
>   let a = np^.ones^(3, dtype: np^.int32)
>   let b = np^.linspace^(0, pi, 3)
>   let c = a+^b
>   let d = np^.exp^(c)
> 
> This does not improve clarity of code, it merely serves to obfuscate logic.  
> It is immediately apparent from the APIs being used, the API style, and the 
> static types (in Xcode or through static declarations) that this is all 
> Python stuff.  

It may be immediately apparent when the types involved are obviously dynamic, 
such as in this example where Python.import is explicitly used.  However, my 
concern is less about the intended use case of dynamic language interop than I 
am that this feature will be generally available to all types in Swift.  

This is big change from AnyObject dispatch.  It opens up the dynamism to types 
and contexts that are not necessarily obviously using dynamic lookup, callable, 
etc.  Maybe this won’t turn out to be a problem in practice but I still think 
it’s a legitimate concern.

> When you start mixing in use of native Swift types like dictionaries 
> (something we want to encourage because they are typed!) you end up with an 
> inconsistent mismash where people would just try adding syntax or applying 
> fixits continuously until the code builds.
> 
> Beyond that, it is counterproductive to your goals, because it means that 
> people are far less likely to use to use optional returns.  Doing so (which 
> produces a safer result) would cause a double tax in syntax, and would be a 
> confusing jumble.  I can’t bring myself to do the whole example above, one 
> line - just converting member lookup syntax but not callable syntax - would 
> end up:
> 
>   let y =  

Re: [swift-evolution] [RFC] Associated type inference

2017-12-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Dec 2, 2017, at 4:40 PM, Douglas Gregor  wrote:
> 
> 
> 
> Sent from my iPhone
> 
>> On Dec 2, 2017, at 1:37 PM, Matthew Johnson  wrote:
>> 
>> 
>>> On Nov 30, 2017, at 6:28 PM, Douglas Gregor via swift-evolution 
>>>  wrote:
>>> 
>>> Hello Swift community,
>>> 
>>> Associated type inference, which is the process by which the Swift compiler 
>>> attempts to infer typealiases to satisfy associated-type requirements based 
>>> on other requirements, has caused both implementation problems and user 
>>> confusion for a long time. Some of you might remember a previous (failed) 
>>> attempt to remove this feature from the Swift language, in SE-0108 “Remove 
>>> associated type inference”. 
>>> 
>>> I’m not sure we can remove this feature outright (i.e., the concerns that 
>>> sank that proposal are still absolutely valid), because it is so very 
>>> convenient and a lot of user code likely depends on it in some form or 
>>> other. So, here I’d like to describe the uses of the feature, its current 
>>> (very problematic) implementation approach, and a half-baked proposal to 
>>> narrow the scope of associated type inference to something that I think is 
>>> more tractable. I need help with the design of this feature, because I feel 
>>> like it’s going to be a delicate balance between implementability and 
>>> expressiveness.
>>> 
>>> A Motivating Example
>>> As a motivating example, let’s consider a “minimal” random access 
>>> collection:
>>> 
>>> struct MyCollection {
>>> var contents: [T]
>>> }
>>> 
>>> extension MyCollection: RandomAccessCollection {
>>> var startIndex: Int { return contents.startIndex }
>>> var endIndex: Int { return contents.endIndex }
>>> subscript(index: Int) -> T { return contents[index] }
>>> }
>>> 
>>> This is actually pretty awesome: by providing just two properties and a 
>>> subscript, we get the full breadth of the random access collection API! 
>>> This is relying heavily on associated type inference (for associated type 
>>> requirements) and default implementations specified on protocol extensions. 
>>> Without associated type inference, we would have had to write:
>>> 
>>> 
>>> extension MyCollection: RandomAccessCollection {
>>> typealias Element = T
>>> typealias Index = Int
>>> typealias Indices = CountableRange
>>> typealias Iterator = IndexingIterator
>>> typealias SubSequence = RandomAccessSlice
>>> 
>>> var startIndex: Int { return contents.startIndex }
>>> var endIndex: Int { return contents.endIndex }
>>> subscript(index: Int) -> T { return contents[index] }
>>> }
>>> 
>>> where the bolded typealiases are currently inferred. It was worse back when 
>>> we reviewed SE-0108, because IIRC there were a few underscored associated 
>>> types (e.g., _Element) that have since been removed. Still, that’s a bit of 
>>> additional work to define a “minimal” collection, and requires quite a bit 
>>> more understanding: how do I know to choose IndexingIterator, and 
>>> CountableRange, and RandomAccessSlice?
>>> 
>>> The issue would get worse with, e.g., SE-0174 “Change filter to return an 
>>> associated type”, which adds an associated type Filtered that almost nobody 
>>> will ever customize, and isn’t really fundamental to the way collections 
>>> work. Adding Filtered to the standard library would be a source-breaking 
>>> change, because users would have to write a typealias giving it its default.
>>> 
>>> Associated Type Defaults
>>> One of the ways in which we avoid having to specify typealiases is to use 
>>> associated type defaults. For example, the standard library contains 
>>> associated type defaults for Indices, Iterator, and SubSequence. Let’s 
>>> focus on Indices:
>>> 
>>> protocol Collection : Sequence {
>>>   associatedtype Indices = DefaultIndices
>>>   // ...
>>> }
>>> 
>>> protocol BidirectionalCollection : Collection {
>>>   associatedtype Indices = DefaultBidirectionalIndices
>>>   // ...
>>> }
>>> 
>>> protocol RandomAccessCollection : BidirectionalCollection {
>>>   associatedtype Indices = DefaultRandomAccessIndices
>>>   // ...
>>> }
>>> 
>>> The basic idea here is that different protocols in the hierarchy provide 
>>> different defaults, and you presumably want the default from the most 
>>> specific protocol. If I define a type and make it conform to 
>>> BidirectionalCollection, I’d expect to get 
>>> DefaultBidirectionalIndices for Indices. If a define a type and make 
>>> it conform to RandomAccessIterator, I’d expect to get 
>>> DefaultRandomAccessIndices.
>>> 
>>> (Aside: DefaultRandomAccessIndices and DefaultBidirectionalIndices got 
>>> collapsed into DefaultIndices now that we have conditional conformances for 
>>> the standard library, but the issues I’m describing remain).
>>> 
>>> Associated type defaults seem like a reasonable feature that fits well 
>>> 

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-02 Thread Matthew Johnson via swift-evolution

> On Dec 2, 2017, at 2:44 PM, Chris Lattner  wrote:
> 
> On Dec 1, 2017, at 5:50 PM, Matthew Johnson  > wrote:
 This design introduces a significant hole in the type system which is 
 contrary to the spirit of Swift.
>>> 
>>> There is no “hole” in the type system.  The proposal is fully type safe. 
>>> 
>>> Further, the addition is absolutely in the spirit of Swift, because it is 
>>> directly analogous to an existing feature: AnyObject lookup.  The 
>>> difference between it and AnyObject lookup is that AnyObject lookup is:
>>> 
>>> a) specific to Objective-C interop
>>> b) type unsafe
>>> c) massively invasive on the rest of the compiler.
>>> 
>>> We’ve made many attempts to narrow the scope of AnyObject lookup, but it is 
>>> difficult to do so given backwards compatibility constraints and the 
>>> limited nature of Objective-C metadata.
>> 
>> I may have spoken incorrectly but I do still believe it is contrary to what 
>> I (and apparently many others) feel is the spirit of Swift.  
>> 
>> As I understand it, AnyObject lookup was a necessity during the historical 
>> development of Swift.  The attempts to narrow its scope have merit 
>> regardless of how far they can go.  They indicate that perhaps it is a 
>> feature we would remove if that were possible.  I would love to see that 
>> happen someday (although I know it is unlikely), or at least see it be made 
>> explicit at the call site.  I suspect if this feature did not exist and it 
>> was proposed today it would be met with at least as much resistance as your 
>> proposals have.
> 
> This isn’t the way I see it.  You’re right that we want to reduce AnyObject 
> dispatch wherever possible: types are good after all.  Swift on Linux doesn’t 
> even have AnyObject dispatch, so you can tell that it is a means to an end, 
> not a feature that we think is great for Swift on its own merits.

It’s a means to an end and the need for that end is growing smaller over time.

> 
> What is that end?  It is interoperability with truly dynamic values, which do 
> occur in Objective-C, where pervasive casting would harm code clarity and 
> usability.  The desire to fix AnyObject you are seeing are related to two 
> different issues: 1) The design of AnyObject dispatch itself is problematic 
> in some ways, and 2) many values in ObjC APIs were typed as id simply because 
> there was no way to describe a more specific type given Objective-C’s 
> original type system (which has been improved).  However, given the presence 
> of actually polymorphic values being used by some APIs, I don’t imagine it 
> going away entirely.

Which is a reason to consider making this mechanism more visible in the syntax.

> 
> 
> In the case of other dynamic languages, the situation is even more severe.  
> Some dynamic languages have progressive type systems available, but not all 
> do.  Those which do have to deal with the fact that the base languages were 
> not designed for typing systems, which is far more severe a problem than 
> Objective-C’s situation.  
> 
> If you haven’t already, I encourage you to read the mypy docs 
> (http://mypy.readthedocs.io/en/stable/index.html 
> ) to understand how the type 
> system they’re trying to build on top of Python works.  They have to contend 
> with things like:
> 
> - the single array subscript operator taking both scalars and ranges, and 
> returning different type results depending on their input (Python has no 
> overloading)
> - pervasive use of duck typing, e.g. int is duck type compatible with float 
> and complex (duck typing is for many non-primitive types as well)
> - pervasive use of variance
> - APIs creep to “just work” when passed all sorts of weird values, meaning 
> that their API contract is extremely loose.
> - Python supports *dynamically computed base classes* and lots of other crazy 
> things.
> - and more..
> 
> Mypy also only supports a subset of Python - it doesn’t support properties 
> with setters as one example, and its generic and class system is only 
> partially implemented.  The only way to use it in practice is to use their 
> ability to silence warnings, it is not an acceptable basis for a sound type 
> system that we could depend on in Swift.
> 
> 
> For all those reasons, we really do need something like AnyObject dispatch if 
> we care about working with dynamically typed languages.  The design I’m 
> suggesting carefully cordons this off into its own struct type, so it doesn’t 
> infect the rest of the type system, and is non-invasive in the compiler.

I am quite familiar with dynamic languages and agree that this is necessary if 
we are going to fully open up access to these languages from Swift.

> 
> 
 It doesn’t just make dynamic language interop easy, it also changes the 
 semantics of any type which conforms to DynamicMemberLookupProtocol.  That 
 

Re: [swift-evolution] [RFC] Associated type inference

2017-12-02 Thread Matthew Johnson via swift-evolution

> On Nov 30, 2017, at 6:28 PM, Douglas Gregor via swift-evolution 
>  wrote:
> 
> Hello Swift community,
> 
> Associated type inference, which is the process by which the Swift compiler 
> attempts to infer typealiases to satisfy associated-type requirements based 
> on other requirements, has caused both implementation problems and user 
> confusion for a long time. Some of you might remember a previous (failed) 
> attempt to remove this feature from the Swift language, in SE-0108 “Remove 
> associated type inference”. 
> 
>  
> 
> I’m not sure we can remove this feature outright (i.e., the concerns that 
> sank that proposal are still absolutely valid), because it is so very 
> convenient and a lot of user code likely depends on it in some form or other. 
> So, here I’d like to describe the uses of the feature, its current (very 
> problematic) implementation approach, and a half-baked proposal to narrow the 
> scope of associated type inference to something that I think is more 
> tractable. I need help with the design of this feature, because I feel like 
> it’s going to be a delicate balance between implementability and 
> expressiveness.
> 
> A Motivating Example
> As a motivating example, let’s consider a “minimal” random access collection:
> 
> struct MyCollection {
> var contents: [T]
> }
> 
> extension MyCollection: RandomAccessCollection {
> var startIndex: Int { return contents.startIndex }
> var endIndex: Int { return contents.endIndex }
> subscript(index: Int) -> T { return contents[index] }
> }
> 
> This is actually pretty awesome: by providing just two properties and a 
> subscript, we get the full breadth of the random access collection API! This 
> is relying heavily on associated type inference (for associated type 
> requirements) and default implementations specified on protocol extensions. 
> Without associated type inference, we would have had to write:
> 
> 
> extension MyCollection: RandomAccessCollection {
> typealias Element = T
> typealias Index = Int
> typealias Indices = CountableRange
> typealias Iterator = IndexingIterator
> typealias SubSequence = RandomAccessSlice
> 
> var startIndex: Int { return contents.startIndex }
> var endIndex: Int { return contents.endIndex }
> subscript(index: Int) -> T { return contents[index] }
> }
> 
> where the bolded typealiases are currently inferred. It was worse back when 
> we reviewed SE-0108, because IIRC there were a few underscored associated 
> types (e.g., _Element) that have since been removed. Still, that’s a bit of 
> additional work to define a “minimal” collection, and requires quite a bit 
> more understanding: how do I know to choose IndexingIterator, and 
> CountableRange, and RandomAccessSlice?
> 
> The issue would get worse with, e.g., SE-0174 “Change filter to return an 
> associated type” 
> ,
>  which adds an associated type Filtered that almost nobody will ever 
> customize, and isn’t really fundamental to the way collections work. Adding 
> Filtered to the standard library would be a source-breaking change, because 
> users would have to write a typealias giving it its default.
> 
> Associated Type Defaults
> One of the ways in which we avoid having to specify typealiases is to use 
> associated type defaults. For example, the standard library contains 
> associated type defaults for Indices, Iterator, and SubSequence. Let’s focus 
> on Indices:
> 
> protocol Collection : Sequence {
>   associatedtype Indices = DefaultIndices
>   // ...
> }
> 
> protocol BidirectionalCollection : Collection {
>   associatedtype Indices = DefaultBidirectionalIndices
>   // ...
> }
> 
> protocol RandomAccessCollection : BidirectionalCollection {
>   associatedtype Indices = DefaultRandomAccessIndices
>   // ...
> }
> 
> The basic idea here is that different protocols in the hierarchy provide 
> different defaults, and you presumably want the default from the most 
> specific protocol. If I define a type and make it conform to 
> BidirectionalCollection, I’d expect to get DefaultBidirectionalIndices 
> for Indices. If a define a type and make it conform to RandomAccessIterator, 
> I’d expect to get DefaultRandomAccessIndices.
> 
> (Aside: DefaultRandomAccessIndices and DefaultBidirectionalIndices got 
> collapsed into DefaultIndices now that we have conditional conformances for 
> the standard library , but the 
> issues I’m describing remain).
> 
> Associated type defaults seem like a reasonable feature that fits well enough 
> into the design. However, it’s not the only thing in place with our 
> MyCollection example, for which Indices was inferred to CountableRange. How’s 
> that happen?
> 

Re: [swift-evolution] [Pitch] Generalized supertype constraints

2017-12-02 Thread Matthew Johnson via swift-evolution
This thread received very light, but positive feedback.  I would really like to 
see this feature added and am willing to draft and official proposal but am not 
able to implement it.  If anyone is interested in collaborating just let me 
know.


> On Nov 24, 2017, at 5:03 PM, Matthew Johnson via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> One of the most frequent frustrations I encounter when writing generic code 
> in Swift is the requirement that supertype constraints be concrete.  When I 
> mentioned this on Twitter 
> (https://twitter.com/anandabits/status/929958479598534656 
> <https://twitter.com/anandabits/status/929958479598534656>) Doug Gregor 
> mentioned that this feature is smaller and mostly straightforward to design 
> and implement (https://twitter.com/dgregor79/status/929975472779288576 
> <https://twitter.com/dgregor79/status/929975472779288576>).
> 
> I currently have a PR open to add the high-level description of this feature 
> found below to the generics manifesto 
> (https://github.com/apple/swift/pull/13012 
> <https://github.com/apple/swift/pull/13012>):
> 
> Currently, supertype constraints may only be specified using a concrete class 
> or protocol type.  This prevents us from abstracting over the supertype.
> 
> ```swift
> protocol P {
>   associatedtype Base
>   associatedtype Derived: Base
> }
> ```
> 
> In the above example `Base` may be any type.  `Derived` may be the same as 
> `Base` or may be _any_ subtype of `Base`.  All subtype relationships 
> supported by Swift should be supported in this context including, but not 
> limited to, classes and subclasses, existentials and conforming concrete 
> types or refining existentials, `T?` and  `T`, `((Base) -> Void)` and 
> `((Derived) -> Void)`, etc.
> 
> Generalized supertype constraints would be accepted in all syntactic 
> locations where generic constraints are accepted.
> 
> I would like to see generalized supertype constraints make it into Swift 5 if 
> possible.  I am not an implementer so I will not be able to bring a proposal 
> forward alone but am interested in collaborating with anyone interested in 
> working on implementation.
> 
> I am also interested in hearing general feedback on this feature from the 
> community at large.  Have you also found this limitation frustrating?  In 
> what contexts?  Does anyone have reservations about introducing this 
> capability?  If so, what are they?
> 
> Matthew
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-12-01 Thread Matthew Johnson via swift-evolution

> On Dec 1, 2017, at 12:23 AM, Chris Lattner  wrote:
> 
>> On Nov 30, 2017, at 6:15 AM, Matthew Johnson  wrote:
>>> 
>>> I think better interoperability with Python (and other OO languages in 
>>> widespread use) is a good goal, and I agree that the implementation of the 
>>> feature described is straight-forward and not terribly invasive in the 
>>> compiler.
>>> 
>>> However, I do not think this proposal is going in the right direction for 
>>> Swift. I have objections on several different grounds.
>> 
>> +1 to everything Doug says here.  He articulates the concerns I tried to 
>> voice in an earlier thread more clearly and more thoroughly.  
> 
> Doug’s email was pretty confusing, so I’ll try to clear up some of the 
> misconceptions here.  I also updated the proposal with a new section at the 
> end, please check it out.

Thank you for your latest reply and the latest reply to Doug.  I can only speak 
for myself, but it helped me to better understand the motivation you have for 
the proposal.  I really do appreciate your view and the motivation behind it.

> 
>> This design introduces a significant hole in the type system which is 
>> contrary to the spirit of Swift.
> 
> There is no “hole” in the type system.  The proposal is fully type safe. 
> 
> Further, the addition is absolutely in the spirit of Swift, because it is 
> directly analogous to an existing feature: AnyObject lookup.  The difference 
> between it and AnyObject lookup is that AnyObject lookup is:
> 
> a) specific to Objective-C interop
> b) type unsafe
> c) massively invasive on the rest of the compiler.
> 
> We’ve made many attempts to narrow the scope of AnyObject lookup, but it is 
> difficult to do so given backwards compatibility constraints and the limited 
> nature of Objective-C metadata.

I may have spoken incorrectly but I do still believe it is contrary to what I 
(and apparently many others) feel is the spirit of Swift.  

As I understand it, AnyObject lookup was a necessity during the historical 
development of Swift.  The attempts to narrow its scope have merit regardless 
of how far they can go.  They indicate that perhaps it is a feature we would 
remove if that were possible.  I would love to see that happen someday 
(although I know it is unlikely), or at least see it be made explicit at the 
call site.  I suspect if this feature did not exist and it was proposed today 
it would be met with at least as much resistance as your proposals have.

> 
>> It doesn’t just make dynamic language interop easy, it also changes the 
>> semantics of any type which conforms to DynamicMemberLookupProtocol.  That 
>> is not something that is locally visible when looking at a piece of code.  
>> Worse, it does so in a way that trivial mistakes such as a typo can turn 
>> into runtime errors.  Worst of all, as Doug points out it is possible to use 
>> retroactive conformance to change the semantics of vast quantities of widely 
>> used types in one fell swoop.
> 
> This is a feature, like many others, which can be misused.  This has not been 
> the metric we have used to judge what should go into Swift.  I can elaborate 
> if my response to Doug wasn’t clear.

The primary problem I have is that misuse is too easy and too subtle.  It is at 
least as easy to misuse as other features in Swift which have been carefully 
designed to be obvious at usage sites.  

I was happy to see that you are willing to consider Xiaodi’s suggestion to 
require conformance to be stated as part of the original type declaration.  
That would be a significant improvement to the proposal IMO.  I strongly urge 
you to reconsider the decision of that dynamic members must be made available 
with no indication at usage sites.  An indication of dynamic lookup at usage 
sites aligns very well (IMO) with the rest of Swift (AnyObject lookup aside) by 
calling attention to code that requires extra care to get right.

> 
>> One additional concern that I don’t believe has been mentioned is that of 
>> evolution.  When a library is imported from a dynamic language and the 
>> library makes breaking changes Swift code written using this feature will 
>> break without notice until a runtime error occurs.  Is that acceptable?  
>> That may be what users of dynamic languages are accustomed to but can we do 
>> better in Swift?  If we can make the process of upgrading dependencies less 
>> a less harrowing experience perhaps that could be a major selling point in 
>> moving them to Swift.  But we won’t accomplish that with this design.
> 
> How would you this to work with *any* interoperability approach?  Dynamic 
> languages are in fact dynamic, and need the ability to do dynamic lookups 
> somehow.  Those dynamic lookups will all have the problem you observe.

I’ll mostly let Doug continue the discussion of the approach he is suggesting.  
It looks to me like that is an approach that might help in this area.  For 
example, if a 

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-11-30 Thread Matthew Johnson via swift-evolution

> On Nov 30, 2017, at 3:48 PM, Paul Cantrell via swift-evolution 
>  wrote:
> 
> 
> 
>> On Nov 30, 2017, at 3:40 PM, Douglas Gregor via swift-evolution 
>> > wrote:
>> 
>> 
>> 
>>> On Nov 30, 2017, at 1:01 PM, Zach Wolfe >> > wrote:
>>> 
>>> Doug and others have brought up some great points, and I think Doug’s idea 
>>> of a common infrastructure for importing declarations from other languages 
>>> is _extremely_ attractive for the long-term future of Swift. 
>>> 
>>> However, unlike this proposal, that will (I imagine as a non-compiler 
>>> engineer) be a colossal undertaking, and as such it’s not going to make it 
>>> into Swift 5, or possibly even 6 or 7. I understand, then, Chris’s (and 
>>> other’s) desire to start interfacing with Python code now, not later. For 
>>> me, far and away the biggest problem with this proposal (and the only 
>>> outright deal-breaker) is that dynamic member lookups do not differentiate 
>>> themselves in any way from statically-checked member lookups syntactically. 
>>> I don’t object as strongly as others to the idea of adding this kind of 
>>> dynamism to the language, but if it’s going to be there, it should not be 
>>> possible to slightly misspell a static member name and end up with an 
>>> unexpectedly dynamic member that may or may not fail at compile-time.
>> 
>> As noted at the end of my message, I think one can write a Swift library to 
>> make working with the Python runtime much easier, and write a wrapper 
>> generator that produces Swift APIs from Python code that use said Swift 
>> library.
> 
> That might be true for Python; I’m quite certain it’s not the case for Ruby 
> or JS as they exist in the wild. However…
> 
> At the risk of stating a universally unpopular opinion, beyond interop with 
> dynamic languages such as Python, there’s also value in dynamic member lookup 
> for •purely Swift-centric• reasons.
> 
> I say this with mixed feelings. I share Douglas’s concerns about breaking 
> Swift’s safety bubble. I like it that the language generally makes it clear 
> •at the point of use• which language features have runtime pitfalls that the 
> compiler cannot check. The points where this is not true of the language 
> (e.g. array subscripts) always feel a bit gritty between the teeth.
> 
> There can, however, be great value in constructing type membership at 
> runtime. The ergonomic access to JSON that’s been discussed in this proposal 
> is nothing to sneeze at. Dynamic languages make for lovely DSLs in a way that 
> fully statically type checked languages never do. Things like Rails’s 
> programmatically generated named routes (e.g. “user_post_path(id)” because 
> routing configuration created a user resource with nested posts) are possible 
> to approximate with statically typed approaches — but only clumsily, never 
> with the same expressiveness and concision.
> 
> I don’t mean to sneeze at the downside of dynamic typing either. They too are 
> nothing to sneeze at. I’ve spent many years on both sides of the dynamic 
> divide, and all I see is difficult tradeoffs.
> 
> Swift so far has said that dynamism isn’t worth the tradeoffs; it’s 
> aggressively avoided even robust runtime reflection, much less dynamic 
> dispatch. That may indeed be the right call for the language — but I’m not 
> easily convinced there isn’t room to open the door wider.
> 
> I think of Chris’s post back in the early days of this list about the 
> “programmer model” the language creates, and wonder if there’s a way we can’t 
> make a model that leaves the door open to this kind of dynamic dispatch where 
> it makes sense for the people and situation at hand, while still staying true 
> to the language’s spirit of “compile-time safety by default, exceptions to 
> that by intent at point of use.”
> 
> Opening the door to dynamism might take some of the flavor of the way the 
> language currently handles unsafe memory access: it’s possible and even 
> reasonably ergonomic, but you always know when you’ve crossed the Rubicon 
> into Dangerland.

I would really like to see Swift gain more dynamic capabilities eventually.  I 
wrote a lot of Ruby years ago and really enjoyed some aspects of it. 

On the other hand, I do want to see us be very deliberate about adding them and 
do it in the right way and only when we are confident that we have identified 
the right feature(s) and designs for them.  If that means waiting a while I 
would rather wait than have regrets later.  If we can identify a design that 
feels appropriate for Swift and decide now is the time to introduce it I will 
be happy with that, but the timeline shouldn’t be prioritized higher than 
getting the design right.

The absolute minimum criteria I have for something I would consider worth 
taking a close look at is making dynamic member lookup clear at the call 

Re: [swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

2017-11-30 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Nov 30, 2017, at 2:24 AM, Douglas Gregor via swift-evolution 
>  wrote:
> 
> 
> 
>> On Nov 26, 2017, at 10:04 PM, Chris Lattner via swift-evolution 
>>  wrote:
>> 
>> I’d like to formally propose the inclusion of user-defined dynamic member 
>> lookup types.
>> 
>> Here is my latest draft of the proposal:
>> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438
>> https://github.com/apple/swift-evolution/pull/768
>> 
>> An implementation of this design is available here:
>> https://github.com/apple/swift/pull/13076
>> 
>> The implementation is straight-forward and (IMO) non-invasive in the 
>> compiler.
> 
> 
> I think better interoperability with Python (and other OO languages in 
> widespread use) is a good goal, and I agree that the implementation of the 
> feature described is straight-forward and not terribly invasive in the 
> compiler.
> 
> However, I do not think this proposal is going in the right direction for 
> Swift. I have objections on several different grounds.

+1 to everything Doug says here.  He articulates the concerns I tried to voice 
in an earlier thread more clearly and more thoroughly.  

This design introduces a significant hole in the type system which is contrary 
to the spirit of Swift.  It doesn’t just make dynamic language interop easy, it 
also changes the semantics of any type which conforms to 
DynamicMemberLookupProtocol.  That is not something that is locally visible 
when looking at a piece of code.  Worse, it does so in a way that trivial 
mistakes such as a typo can turn into runtime errors.  Worst of all, as Doug 
points out it is possible to use retroactive conformance to change the 
semantics of vast quantities of widely used types in one fell swoop.

One additional concern that I don’t believe has been mentioned is that of 
evolution.  When a library is imported from a dynamic language and the library 
makes breaking changes Swift code written using this feature will break without 
notice until a runtime error occurs.  Is that acceptable?  That may be what 
users of dynamic languages are accustomed to but can we do better in Swift?  If 
we can make the process of upgrading dependencies less a less harrowing 
experience perhaps that could be a major selling point in moving them to Swift. 
 But we won’t accomplish that with this design.

Interop with dynamic languages is a worthy goal, but we should do it in a way 
that has no potential impact on code that does not need the feature.  A 
semantic variant of “don’t pay for what you don’t use” should apply here.  If 
we add this feature everyone will pay for it every time they read unfamiliar 
Swift code.  They will have to contend with the potential for conformances to 
this protocol, even on standard library types.  That feels like a pretty high 
cost to me, especially for programmers who aren’t using the dynamic language 
interop features themselves.

Further, a consistent theme has been the desire to avoid things like compiler 
flags that could fragment the community.  I fear this feature has the potential 
to do that, especially if it is really successful at attracting people from the 
dynamic language community.  I think we should consider carefully the following 
questions:

* Do we want to encourage these programmers to continue writing code in an 
extremely dynamic style when they come to Swift or do we want to encourage them 
to embrace the advantages of relying on the type system?  
* If we want them to embrace the type system but that would keep them away from 
Swift how do we feel about that?  

Matthew

> 
> Philosophy
> Swift is, unabashedly, a strong statically-typed language. We don’t allow 
> implicit down casting, we require “as?” so you have to cope with the 
> possibility of failure (or use “as!” and think hard about the “!”). Even the 
> gaping hole that is AnyObject dispatch still requires the existence of an 
> @objc declaration and produces an optional lookup result, so the user must 
> contend with the potential for dynamic failure. Whenever we discuss adding 
> more dynamic features to Swift, there’s a strong focus on maintaining that 
> strong static type system.
> 
> IMO, this proposal is a significant departure from the fundamental character 
> of Swift, because it allows access to possibly-nonexistent members (as well 
> as calls with incorrect arguments, in the related proposal) without any 
> indication that the operation might fail. It’s easy to fall through these 
> cracks for any type that supports DynamicMemberLookupProtocol—a 
> single-character typo when using a DynamicMemberLookupProtocol-capable type 
> means you’ve fallen out of the safety that Swift provides. I think that’s a 
> poor experience for the Python interoperability case, but more on that in the 
> Tooling section below.
> 
> While we shouldn’t necessarily avoid a feature simply because it can be used 
> distastefully, 

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 4:11 PM, Slava Pestov  wrote:
> 
> 
> 
>> On Nov 28, 2017, at 1:35 PM, Matthew Johnson > > wrote:
>> 
 * the compiler doesn’t have to reason about an overload set which might 
 improve build times, etc
>>> 
>>> They’re effectively equivalent, because we still have to decide which 
>>> subset of the default arguments apply at a given call site by checking all 
>>> combinations of constraints.
>> 
>> Interesting.  Are there no advantages to the compiler that would be possible 
>> if an overload set was replaced with constrained default arguments?
>> 
> 
> Probably not. In general I’m wary of designing language features specifically 
> to speed up the type checker, since they make not have the intended effect or 
> even the opposite effect. We know the type checker implementation is not the 
> best possible implementation of a type checker — there is a lot we can 
> improve without changing the language.

That isn’t the motivation here.  I thought it might be an incidental benefit.  
If it isn’t the motivating use case still stands.  Of course it may or may not 
be sufficient to justify the feature.  :)

> 
> Slava

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


Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 3:28 PM, Slava Pestov  wrote:
> 
> 
> 
>> On Nov 28, 2017, at 1:25 PM, Matthew Johnson > > wrote:
>> 
>> 
>>> On Nov 28, 2017, at 3:18 PM, Slava Pestov >> > wrote:
>>> 
>>> 
>>> 
 On Nov 28, 2017, at 8:44 AM, Matthew Johnson > wrote:
 
 func makeResource(
 with configuration: Configuration = () where Configuration == Void, 
 actionHandler: @escaping (Action) -> Void = { _ in } where Action == 
 Never
 )
>>> 
>>> Similar question to the one I posed earlier — what happens if I’m using 
>>> makeResource() from a generic context? Is the conditional default argument 
>>> simply not available?
>> 
>> Right.  If the constraints are not met at the call site the default is not 
>> available.  I think you understood, but looking at the example above I 
>> omitted the resource type parameter.  It should read:
>> 
>> func makeResource(
>> with configuration: R.Configuration = () where R.Configuration == Void, 
>> actionHandler: @escaping (R.Action) -> Void = { _ in } where R.Action == 
>> Never
>> )
>> 
>>> 
>>> In this case, how is it different from defining some static overloads of 
>>> makeResource(), some of which have default arguments and some of which are 
>>> generic?
>> 
>> From the point of view of the call site it is not different.  The 
>> differences are that:
>> 
>> * the user is presented with a single API rather than several overloads
> 
> Is this less confusing than encountering a new ‘where’ clause on default 
> arguments, which is probably rare enough that many users will spend 
> months/years using Swift without seeing it?

I think so.  The where clause is used for constraints consistently in the 
language so the meaning of seeing one attached to a default argument should be 
intuitive for anyone familiar with the generics system.  In the motivating use 
case I have there would still be an overload set available but it would be much 
smaller with this feature and therefore the available signatures would be much 
more clear.

> 
>> * the compiler doesn’t have to reason about an overload set which might 
>> improve build times, etc
> 
> They’re effectively equivalent, because we still have to decide which subset 
> of the default arguments apply at a given call site by checking all 
> combinations of constraints.

Interesting.  Are there no advantages to the compiler that would be possible if 
an overload set was replaced with constrained default arguments?

> 
> Slava
> 
>> 
>>> 
>>> Slava
>> 
> 

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


Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 3:18 PM, Slava Pestov  wrote:
> 
> 
> 
>> On Nov 28, 2017, at 8:44 AM, Matthew Johnson > > wrote:
>> 
>> func makeResource(
>> with configuration: Configuration = () where Configuration == Void, 
>> actionHandler: @escaping (Action) -> Void = { _ in } where Action == 
>> Never
>> )
> 
> Similar question to the one I posed earlier — what happens if I’m using 
> makeResource() from a generic context? Is the conditional default argument 
> simply not available?

Right.  If the constraints are not met at the call site the default is not 
available.  I think you understood, but looking at the example above I omitted 
the resource type parameter.  It should read:

func makeResource(
with configuration: R.Configuration = () where R.Configuration == Void, 
actionHandler: @escaping (R.Action) -> Void = { _ in } where R.Action == 
Never
)

> 
> In this case, how is it different from defining some static overloads of 
> makeResource(), some of which have default arguments and some of which are 
> generic?

>From the point of view of the call site it is not different.  The differences 
>are that:

* the user is presented with a single API rather than several overloads
* the library author isn’t required to maintain an overload set
* the compiler doesn’t have to reason about an overload set which might improve 
build times, etc

> 
> Slava

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


Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 11:40 AM, Tony Allevato  wrote:
> 
> 
> 
> On Tue, Nov 28, 2017 at 9:16 AM Matthew Johnson  > wrote:
>> On Nov 28, 2017, at 11:01 AM, Tony Allevato > > wrote:
>> 
>> 
>> 
>> On Tue, Nov 28, 2017 at 8:45 AM Matthew Johnson > > wrote:
>>> On Nov 28, 2017, at 10:06 AM, Tony Allevato >> > wrote:
>>> 
>>> 
>>> 
>>> On Mon, Nov 27, 2017 at 10:32 PM Slava Pestov >> > wrote:
>>> Hi Tony,
>>> 
>>> So if my understanding is correct, the basic proposal is the following:
>>> 
>>> func id(t: T ?= T.defaultValue) { return t }
>>> 
>>> extension Int { static var defaultValue = 0 }
>>> 
>>> extension String { static var defaultValue = “” }
>>> 
>>> id() as Int // returns 0
>>> id() as String // returns “”
>>> id() as SomeRandomType // fails to type check — no default argument
>>> 
>>> I don’t understand what would happen if the caller is itself generic 
>>> though, for example:
>>> 
>>> callsID(_ t: T) {
>>>   _ = id() as T
>>> }
>>> 
>>> It appears that body of callsID() itself cannot type check without 
>>> knowledge of the concrete T that will be used with this function.
>>> 
>>> Thanks for bringing up this example, Slava.
>>> 
>>> Unless I'm misunderstanding, the issue you're describing is inherent to the 
>>> *problem* described in the original post, not to any specific hypothetical 
>>> syntax for adding the default arguments, correct? In other words, if this 
>>> was written using extensions as can be done today:
>>> 
>>> ```
>>> struct Foo {
>>>   func id(t: T) -> T { return t }
>>> }
>>> 
>>> extension Foo where T == Void {
>>>   func id() -> T { return () }
>>> }
>>> 
>>> extension Foo where T == Int {
>>>   func id() -> T { return 0 }
>>> }
>>> 
>>> callsID(_ t: T) {
>>>   _ = Foo().id() as T// mark
>>> }
>>> ```
>>> 
>>> The compiler would still reject the marked line because there's no 
>>> guarantee that T is one of the types that has the necessary overload.
>>> 
>>> But now that you've mentioned it, it does have me thinking that this 
>>> problem might be better left to extensions. In one sense, default arguments 
>>> are a kind of "overload synthesis”,
>> 
>> They appear to callers as if they were overloads but I think it’s important 
>> that they actually do so *without* introducing an overload.  Reducing the 
>> size of an overload set is good for users, library authors and the compiler. 
>>  The benefits that come to all parties when the size of an overload set is 
>> reduced is the primary reason I started this thread.
>> 
>>> but on the other hand, there's an expectation that the default value 
>>> expression is of a single type (or set of related types) known at compile 
>>> time. Even if it's generic, it still must be expressed in terms of whatever 
>>> constraints are present on that generic type—you can't use a disjunction of 
>>> types, but instead have to have a common protocol that would provide some 
>>> operation.
>> 
>> This should not change for any given default value expression.  This thread 
>> doesn’t discuss changing that.  I discusses the ability to constrain the 
>> presence of a default value expression.
>> 
>> But that's exactly the distinction that I'm driving at—the more I think 
>> about it, the more I have difficulty expressing it cleanly and I think 
>> that's because these aren't the same as default arguments—they really are 
>> distinct overloads because you're talking about the presence or absence of 
>> an argument based on specific constraints instead of something that applies 
>> to the function uniformly for all possible types that satisfy the 
>> constraint. So what I'm suggesting is that maybe conflating this concept 
>> with default arguments is the wrong approach after all.
>> 
>>  
>>  While it would be useful to allow multiple default value expressions for 
>> different constraints the most common case will be a single constrained 
>> default value expression for any given argument.  We could just allow a 
>> trailing where clause on the default value expression itself like this:
>> 
>> func makeResource(
>> with configuration: Configuration = () where Configuration == Void, 
>> actionHandler: @escaping (Action) -> Void = { _ in } where Action == 
>> Never
>> )
>> 
>> That addresses the most common cases for this feature with a fairly obvious 
>> and direct syntax.
>> 
>> Allowing only one constraint seems arbitrary and I imagine that the 
>> immediately following question would be "what if I want more than one?" I 
>> wouldn't want to address only part of the problem. My ICU example further up 
>> in the thread shows a scenario where I would want defaults for two distinct 
>> types (if I also wanted to publicize the general 

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 11:01 AM, Tony Allevato  wrote:
> 
> 
> 
> On Tue, Nov 28, 2017 at 8:45 AM Matthew Johnson  > wrote:
>> On Nov 28, 2017, at 10:06 AM, Tony Allevato > > wrote:
>> 
>> 
>> 
>> On Mon, Nov 27, 2017 at 10:32 PM Slava Pestov > > wrote:
>> Hi Tony,
>> 
>> So if my understanding is correct, the basic proposal is the following:
>> 
>> func id(t: T ?= T.defaultValue) { return t }
>> 
>> extension Int { static var defaultValue = 0 }
>> 
>> extension String { static var defaultValue = “” }
>> 
>> id() as Int // returns 0
>> id() as String // returns “”
>> id() as SomeRandomType // fails to type check — no default argument
>> 
>> I don’t understand what would happen if the caller is itself generic though, 
>> for example:
>> 
>> callsID(_ t: T) {
>>   _ = id() as T
>> }
>> 
>> It appears that body of callsID() itself cannot type check without knowledge 
>> of the concrete T that will be used with this function.
>> 
>> Thanks for bringing up this example, Slava.
>> 
>> Unless I'm misunderstanding, the issue you're describing is inherent to the 
>> *problem* described in the original post, not to any specific hypothetical 
>> syntax for adding the default arguments, correct? In other words, if this 
>> was written using extensions as can be done today:
>> 
>> ```
>> struct Foo {
>>   func id(t: T) -> T { return t }
>> }
>> 
>> extension Foo where T == Void {
>>   func id() -> T { return () }
>> }
>> 
>> extension Foo where T == Int {
>>   func id() -> T { return 0 }
>> }
>> 
>> callsID(_ t: T) {
>>   _ = Foo().id() as T// mark
>> }
>> ```
>> 
>> The compiler would still reject the marked line because there's no guarantee 
>> that T is one of the types that has the necessary overload.
>> 
>> But now that you've mentioned it, it does have me thinking that this problem 
>> might be better left to extensions. In one sense, default arguments are a 
>> kind of "overload synthesis”,
> 
> They appear to callers as if they were overloads but I think it’s important 
> that they actually do so *without* introducing an overload.  Reducing the 
> size of an overload set is good for users, library authors and the compiler.  
> The benefits that come to all parties when the size of an overload set is 
> reduced is the primary reason I started this thread.
> 
>> but on the other hand, there's an expectation that the default value 
>> expression is of a single type (or set of related types) known at compile 
>> time. Even if it's generic, it still must be expressed in terms of whatever 
>> constraints are present on that generic type—you can't use a disjunction of 
>> types, but instead have to have a common protocol that would provide some 
>> operation.
> 
> This should not change for any given default value expression.  This thread 
> doesn’t discuss changing that.  I discusses the ability to constrain the 
> presence of a default value expression.
> 
> But that's exactly the distinction that I'm driving at—the more I think about 
> it, the more I have difficulty expressing it cleanly and I think that's 
> because these aren't the same as default arguments—they really are distinct 
> overloads because you're talking about the presence or absence of an argument 
> based on specific constraints instead of something that applies to the 
> function uniformly for all possible types that satisfy the constraint. So 
> what I'm suggesting is that maybe conflating this concept with default 
> arguments is the wrong approach after all.
> 
>  
>  While it would be useful to allow multiple default value expressions for 
> different constraints the most common case will be a single constrained 
> default value expression for any given argument.  We could just allow a 
> trailing where clause on the default value expression itself like this:
> 
> func makeResource(
> with configuration: Configuration = () where Configuration == Void, 
> actionHandler: @escaping (Action) -> Void = { _ in } where Action == Never
> )
> 
> That addresses the most common cases for this feature with a fairly obvious 
> and direct syntax.
> 
> Allowing only one constraint seems arbitrary and I imagine that the 
> immediately following question would be "what if I want more than one?" I 
> wouldn't want to address only part of the problem. My ICU example further up 
> in the thread shows a scenario where I would want defaults for two distinct 
> types (if I also wanted to publicize the general initializer to everyone).

Did you really mean “only one constraint” here?  Or did you mean “only one 
default value expression”?  These are very different.  I would not want to 
restrict the number of constraints.  What I am suggesting is that limiting this 
to a single (possibly constrained) default value expression presents a 
relatively obvious syntactic 

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 10:06 AM, Tony Allevato  wrote:
> 
> 
> 
> On Mon, Nov 27, 2017 at 10:32 PM Slava Pestov  > wrote:
> Hi Tony,
> 
> So if my understanding is correct, the basic proposal is the following:
> 
> func id(t: T ?= T.defaultValue) { return t }
> 
> extension Int { static var defaultValue = 0 }
> 
> extension String { static var defaultValue = “” }
> 
> id() as Int // returns 0
> id() as String // returns “”
> id() as SomeRandomType // fails to type check — no default argument
> 
> I don’t understand what would happen if the caller is itself generic though, 
> for example:
> 
> callsID(_ t: T) {
>   _ = id() as T
> }
> 
> It appears that body of callsID() itself cannot type check without knowledge 
> of the concrete T that will be used with this function.
> 
> Thanks for bringing up this example, Slava.
> 
> Unless I'm misunderstanding, the issue you're describing is inherent to the 
> *problem* described in the original post, not to any specific hypothetical 
> syntax for adding the default arguments, correct? In other words, if this was 
> written using extensions as can be done today:
> 
> ```
> struct Foo {
>   func id(t: T) -> T { return t }
> }
> 
> extension Foo where T == Void {
>   func id() -> T { return () }
> }
> 
> extension Foo where T == Int {
>   func id() -> T { return 0 }
> }
> 
> callsID(_ t: T) {
>   _ = Foo().id() as T// mark
> }
> ```
> 
> The compiler would still reject the marked line because there's no guarantee 
> that T is one of the types that has the necessary overload.
> 
> But now that you've mentioned it, it does have me thinking that this problem 
> might be better left to extensions. In one sense, default arguments are a 
> kind of "overload synthesis”,

They appear to callers as if they were overloads but I think it’s important 
that they actually do so *without* introducing an overload.  Reducing the size 
of an overload set is good for users, library authors and the compiler.  The 
benefits that come to all parties when the size of an overload set is reduced 
is the primary reason I started this thread.

> but on the other hand, there's an expectation that the default value 
> expression is of a single type (or set of related types) known at compile 
> time. Even if it's generic, it still must be expressed in terms of whatever 
> constraints are present on that generic type—you can't use a disjunction of 
> types, but instead have to have a common protocol that would provide some 
> operation.

This should not change for any given default value expression.  This thread 
doesn’t discuss changing that.  I discusses the ability to constrain the 
presence of a default value expression.  While it would be useful to allow 
multiple default value expressions for different constraints the most common 
case will be a single constrained default value expression for any given 
argument.  We could just allow a trailing where clause on the default value 
expression itself like this:

func makeResource(
with configuration: Configuration = () where Configuration == Void, 
actionHandler: @escaping (Action) -> Void = { _ in } where Action == Never
)

That addresses the most common cases for this feature with a fairly obvious and 
direct syntax.  It also avoids the potential ambiguity that could arise from 
allowing multiple defaults with different (potentially overlapping) constraints.


>  
> 
> Slava
> 
>> On Nov 27, 2017, at 4:10 PM, Tony Allevato via swift-evolution 
>> > wrote:
>> 
>> I totally agree that that's a good rule in general—I'm not 100% comfortable 
>> making an exception to it for this, but I wanted to start a discussion about 
>> a different approach than had been considered so far.
>> 
>> The idea of forcing the user to acknowledge the explicitness of SFINAE with 
>> a strawman syntax `=?` instead of `=` was a thought experiment to bridge the 
>> wild-west-C++ world of templates and Swift's stricter generics, but I can 
>> definitely understand if even that kind of approach is something that the 
>> core team (who are far more familiar with the C++ side of that coin than I 
>> am) doesn't wish to support. As was pointed out, it's not something Swift 
>> supports anywhere else today.
>> 
>> If we look at it from that point of view, where such a semantic treatment of 
>> generics would not be supported, I think it becomes a lot harder to 
>> rationalize treating this as "default arguments". What you really do have 
>> (and what writing it as constrained extensions makes clear) is additional 
>> overloads, because they only apply to certain subsets of types. If that's 
>> the case, maybe it's the wrong approach to try to turn overloads into 
>> "partial default values".
> 

___
swift-evolution mailing list
swift-evolution@swift.org

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-28 Thread Matthew Johnson via swift-evolution

> On Nov 28, 2017, at 12:34 AM, Slava Pestov <spes...@apple.com> wrote:
> 
> 
> 
>> On Nov 27, 2017, at 3:38 PM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> You are effectively proposing that in this very narrow case we perform 
>> overload resolution on a symbol in a generic type context *after* the 
>> generic type has been replaced with a concrete type. 
> 
> Keep in mind that in general, this would require runtime support — we don’t 
> always know the concrete substitution for a generic parameter at compile 
> time, especially in the presence of separate compilation (but even without, 
> for instance when optimizations are not enabled or unable to recover concrete 
> type information).

Thanks for mentioning that.  IMO, it rules out this approach as it means we 
wouldn’t always know statically whether a default argument is available.  C++ 
gets away with it because templates are always substituted during compilation 
and that isn’t true for Swift generics.

> 
> Slava

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


Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-27 Thread Matthew Johnson via swift-evolution
lt argument in that case”. Something like SFINAE in 
>>>>> C++, but more explicit.
>>>>> 
>>>>> I’m imagining something like this:
>>>>> 
>>>>> func defaultConfiguration() -> Void {
>>>>>   return ()
>>>>> }
>>>>> 
>>>>> func defaultActionHandler() -> (Never) -> Void {
>>>>>   return { _ in }
>>>>> }
>>>>> 
>>>>> struct ResourceDescription {
>>>>>   func makeResource(
>>>>> with configuration: R.Configuration =? defaultConfiguration(),
>>>>> actionHandler: @escaping (R.Action) -> Void =? defaultActionHandler()
>>>>>   ) -> R {
>>>>> // create a resource using the provided configuration
>>>>> // connect the action handler
>>>>> // return the resource
>>>>>   }
>>>>> }
>>>>> The main difference here is the strawman =? syntax, which would indicate 
>>>>> that “the default argument exists if there is a way the RHS can be 
>>>>> satisfied for some instances of the generic arguments; otherwise, there 
>>>>> is no default”, instead of today’s behavior where it would be an error. 
>>>>> There could be multiple overloads of defaultConfiguration and 
>>>>> defaultActionHandler (even ones that are themselves generic) and it would 
>>>>> do the right thing when there are matches and when there aren’t.
>>>>> 
>>>>> I like this approach because it mostly takes advantage of existing 
>>>>> language features and is fairly lightweight in terms of how it’s 
>>>>> expressed in code compared to regular default arguments—we’d just need to 
>>>>> design the new operator and type-checker logic around it.
>>>>> 
>>>> 
>>>> This is an interesting approach.  One advantage to something in this 
>>>> direction is that it could support defining different defaults for the 
>>>> same argument under different constraints by overloading the default 
>>>> argument factories on their return type.
>>>> 
>>>> One concern I have is that it doesn’t allows us to clearly define under 
>>>> which constraints a default argument is available.  I suspect this might 
>>>> be problematic especially for public interfaces where source compatibility 
>>>> is a concern.  
>>>> 
>>>> It's certainly an interesting idea but it would suggest that the 
>>>> constraints under which a default argument is available can change at 
>>>> runtime. I'm concerned, like you, that this is difficult to reason about. 
>>>> It is still unclear to me how widespread the underlying issue is that 
>>>> requires conditional default arguments, but the conversation thus far has 
>>>> been about compile-time constraints and Tony's design seems to envision 
>>>> much more than that.
>>>> 
>>>> This runtime/reasoning problem already exists today with default 
>>>> arguments, because you can write something like this:
>>>> 
>>>> struct Foo {
>>>>   static var defaultExponent = 2.0
>>>> 
>>>>   func raise(_ x: Double, to exponent: Double = defaultExponent) {
>>>> print(pow(x, exponent))
>>>>   }
>>>> }
>>>> 
>>>> Foo().raise(4)  // "16.0"
>>>> Foo.defaultExponent = 3.0
>>>> Foo().raise(4)  // "64.0"
>>>> Swift lets you write a default value expression that references static 
>>>> (but not instance) vars of the enclosing type, as well as anything else 
>>>> that’s visible from that expression’s scope. Should people do this? 
>>>> Probably not, for the reasons that you described.
>>>> 
>>>> But the point is that my example is no more harmful or difficult to reason 
>>>> about than default arguments in the language today. My proposed solution 
>>>> in no way changes the runtime behavior of default argument expressions. 
>>>> I’m not envisioning anything more than what default arguments can already 
>>>> do except for adding a way to choose different default factories (or 
>>>> choose none without error) based on the static types of the generic 
>>>> arguments that are bound at a particular call site.
>>>> 
>>>> 
>>>> 
>>>> I think I prefer Xiaodi’s

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-27 Thread Matthew Johnson via swift-evolution
say 
>>>> that “if no overload matches, then it’s not an error—just don’t have a 
>>>> default argument in that case”. Something like SFINAE in C++, but more 
>>>> explicit.
>>>> 
>>>> I’m imagining something like this:
>>>> 
>>>> func defaultConfiguration() -> Void {
>>>>   return ()
>>>> }
>>>> 
>>>> func defaultActionHandler() -> (Never) -> Void {
>>>>   return { _ in }
>>>> }
>>>> 
>>>> struct ResourceDescription {
>>>>   func makeResource(
>>>> with configuration: R.Configuration =? defaultConfiguration(),
>>>> actionHandler: @escaping (R.Action) -> Void =? defaultActionHandler()
>>>>   ) -> R {
>>>> // create a resource using the provided configuration
>>>> // connect the action handler
>>>> // return the resource
>>>>   }
>>>> }
>>>> The main difference here is the strawman =? syntax, which would indicate 
>>>> that “the default argument exists if there is a way the RHS can be 
>>>> satisfied for some instances of the generic arguments; otherwise, there is 
>>>> no default”, instead of today’s behavior where it would be an error. There 
>>>> could be multiple overloads of defaultConfiguration and 
>>>> defaultActionHandler (even ones that are themselves generic) and it would 
>>>> do the right thing when there are matches and when there aren’t.
>>>> 
>>>> I like this approach because it mostly takes advantage of existing 
>>>> language features and is fairly lightweight in terms of how it’s expressed 
>>>> in code compared to regular default arguments—we’d just need to design the 
>>>> new operator and type-checker logic around it.
>>>> 
>>> 
>>> This is an interesting approach.  One advantage to something in this 
>>> direction is that it could support defining different defaults for the same 
>>> argument under different constraints by overloading the default argument 
>>> factories on their return type.
>>> 
>>> One concern I have is that it doesn’t allows us to clearly define under 
>>> which constraints a default argument is available.  I suspect this might be 
>>> problematic especially for public interfaces where source compatibility is 
>>> a concern.  
>>> 
>>> It's certainly an interesting idea but it would suggest that the 
>>> constraints under which a default argument is available can change at 
>>> runtime. I'm concerned, like you, that this is difficult to reason about. 
>>> It is still unclear to me how widespread the underlying issue is that 
>>> requires conditional default arguments, but the conversation thus far has 
>>> been about compile-time constraints and Tony's design seems to envision 
>>> much more than that.
>>> 
>>> This runtime/reasoning problem already exists today with default arguments, 
>>> because you can write something like this:
>>> 
>>> struct Foo {
>>>   static var defaultExponent = 2.0
>>> 
>>>   func raise(_ x: Double, to exponent: Double = defaultExponent) {
>>> print(pow(x, exponent))
>>>   }
>>> }
>>> 
>>> Foo().raise(4)  // "16.0"
>>> Foo.defaultExponent = 3.0
>>> Foo().raise(4)  // "64.0"
>>> Swift lets you write a default value expression that references static (but 
>>> not instance) vars of the enclosing type, as well as anything else that’s 
>>> visible from that expression’s scope. Should people do this? Probably not, 
>>> for the reasons that you described.
>>> 
>>> But the point is that my example is no more harmful or difficult to reason 
>>> about than default arguments in the language today. My proposed solution in 
>>> no way changes the runtime behavior of default argument expressions. I’m 
>>> not envisioning anything more than what default arguments can already do 
>>> except for adding a way to choose different default factories (or choose 
>>> none without error) based on the static types of the generic arguments that 
>>> are bound at a particular call site.
>>> 
>>> 
>>> 
>>> I think I prefer Xiaodi’s suggestion for that reason.  His approach could 
>>> also support multiple defaults for the same parameter as long as the 
>>> constraints are not allowed to overlap (overlapping constraints would 
>>

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-27 Thread Matthew Johnson via swift-evolution
 concern.  
>> 
>> It's certainly an interesting idea but it would suggest that the constraints 
>> under which a default argument is available can change at runtime. I'm 
>> concerned, like you, that this is difficult to reason about. It is still 
>> unclear to me how widespread the underlying issue is that requires 
>> conditional default arguments, but the conversation thus far has been about 
>> compile-time constraints and Tony's design seems to envision much more than 
>> that.
>> 
>> This runtime/reasoning problem already exists today with default arguments, 
>> because you can write something like this:
>> 
>> struct Foo {
>>   static var defaultExponent = 2.0
>> 
>>   func raise(_ x: Double, to exponent: Double = defaultExponent) {
>> print(pow(x, exponent))
>>   }
>> }
>> 
>> Foo().raise(4)  // "16.0"
>> Foo.defaultExponent = 3.0
>> Foo().raise(4)  // "64.0"
>> Swift lets you write a default value expression that references static (but 
>> not instance) vars of the enclosing type, as well as anything else that’s 
>> visible from that expression’s scope. Should people do this? Probably not, 
>> for the reasons that you described.
>> 
>> But the point is that my example is no more harmful or difficult to reason 
>> about than default arguments in the language today. My proposed solution in 
>> no way changes the runtime behavior of default argument expressions. I’m not 
>> envisioning anything more than what default arguments can already do except 
>> for adding a way to choose different default factories (or choose none 
>> without error) based on the static types of the generic arguments that are 
>> bound at a particular call site.
>> 
>> 
>> 
>> I think I prefer Xiaodi’s suggestion for that reason.  His approach could 
>> also support multiple defaults for the same parameter as long as the 
>> constraints are not allowed to overlap (overlapping constraints would result 
>> in ambiguity similar to ambiguous overload resolution) or an explicit 
>> argument is required if they do.
>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> On Fri, Nov 24, 2017 at 8:36 PM, T.J. Usiyan via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> I am all for this. are many types where there is an obvious 'zero' or 
>>> 'default' value and the ability to express "use that when possible" without 
>>> an overload is welcome.
>>> 
>>> 
>>> The best thing that I can think of right now, in terms of syntax, is 
>>> actually using @overload
>>> 
>>> ```
>>> struct ResourceDescription {
>>> 
>>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>>> @escaping (R.Action) -> Void) -> R 
>>>  @overload(R.Configuration == Void) func makeResource(actionHandler: 
>>> @escaping (R.Action) -> Void) -> R
>>> @overload(R.Action == Never)  func makeResource(with configuration: 
>>> R.Configuration) -> R
>>> {
>>> // create a resource using the provided configuration
>>> // connect the action handler
>>> // return the resource
>>>   }
>>> }
>>> ```
>>> 
>>> 
>>> This isn't great though…
>>> 
>>> On Fri, Nov 24, 2017 at 6:11 PM, Matthew Johnson via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> As mentioned in my prior message, I currently have a PR open to update the 
>>> generics manifesto (https://github.com/apple/swift/pull/13012 
>>> <https://github.com/apple/swift/pull/13012>).  I removed one topic from 
>>> that update at Doug Gregor’s request that it be discussed on the list 
>>> first.  
>>> 
>>> The idea is to add the ability to make default arguments conditional (i.e. 
>>> depend on generic constraints).  It is currently possible to emulate 
>>> conditional default arguments using an overload set.  This is verbose, 
>>> especially when several arguments are involved.  Here is an example use 
>>> case using the overload method to emulate this feature:
>>> 
>>> ```swift
>>> protocol Resource {
>>>   associatedtype Configuration
>>>   associatedtype Action
>>> }
>>> struct ResourceDescription {
>>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>>> @escaping (

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-27 Thread Matthew Johnson via swift-evolution

> On Nov 27, 2017, at 3:27 PM, Tony Allevato <tony.allev...@gmail.com> wrote:
> 
> On Mon, Nov 27, 2017 at 12:49 PM Matthew Johnson <matt...@anandabits.com 
> <mailto:matt...@anandabits.com>> wrote:
>> On Nov 27, 2017, at 1:24 PM, Tony Allevato <tony.allev...@gmail.com 
>> <mailto:tony.allev...@gmail.com>> wrote:
>> 
>> 
>> 
>> On Mon, Nov 27, 2017 at 11:12 AM Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> On Nov 27, 2017, at 12:50 PM, Douglas Gregor <dgre...@apple.com 
>>> <mailto:dgre...@apple.com>> wrote:
>>> 
>>> 
>>> 
>>>> On Nov 24, 2017, at 3:11 PM, Matthew Johnson via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> As mentioned in my prior message, I currently have a PR open to update the 
>>>> generics manifesto (https://github.com/apple/swift/pull/13012 
>>>> <https://github.com/apple/swift/pull/13012>).  I removed one topic from 
>>>> that update at Doug Gregor’s request that it be discussed on the list 
>>>> first.  
>>>> 
>>>> The idea is to add the ability to make default arguments conditional (i.e. 
>>>> depend on generic constraints).  It is currently possible to emulate 
>>>> conditional default arguments using an overload set.  This is verbose, 
>>>> especially when several arguments are involved.  Here is an example use 
>>>> case using the overload method to emulate this feature:
>>>> 
>>>> ```swift
>>>> protocol Resource {
>>>>   associatedtype Configuration
>>>>   associatedtype Action
>>>> }
>>>> struct ResourceDescription {
>>>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>>>> @escaping (R.Action) -> Void) -> R {
>>>> // create a resource using the provided configuration
>>>> // connect the action handler
>>>> // return the resource
>>>>   }
>>>> }
>>>> 
>>>> extension ResourceDescription where R.Configuration == Void {
>>>>   func makeResource(actionHandler: @escaping (R.Action) -> Void) -> R {
>>>> return makeResource(with: (), actionHandler: actionHandler)
>>>>   }
>>>> }
>>>> 
>>>> extension ResourceDescription where R.Action == Never {
>>>>   func makeResource(with configuration: R.Configuration) -> R {
>>>> return makeResource(with: configuration, actionHandler: { _ in })
>>>>   }
>>>> }
>>>> 
>>>> extension ResourceDescription where R.Configuration == Void, R.Action == 
>>>> Never {
>>>>   func makeResource() -> R {
>>>> return makeResource(with: (), actionHandler: { _ in })
>>>>   }
>>>> }
>>>> 
>>>> ```
>>>> 
>>>> Adding language support for defining these more directly would eliminate a 
>>>> lot of boilerplate and reduce the need for overloads.
>>> 
>>> If one could refer to `self` in a default argument (which is not a big 
>>> problem), you could turn the default into a requirement itself… although it 
>>> doesn’t *quite* work with your example as written because it would always 
>>> need to be implemented somehow:
>>> 
>>>> protocol Resource {
>>>>   associatedtype Configuration
>>>>   associatedtype Action
>>> func defaultConfiguration() -> Configuration
>>> func defaultHandler() -> ((R.Action) -> Void)
>>>> }
>> 
>> This won’t work on its own for this use case because there is only a valid 
>> default in relatively narrow (but common) cases.  For most values of 
>> Configuration and Action an argument must be provided by the caller.  
>> Xiaodi’s proposed syntax is the best fit (so far) for the use case I had in 
>> mind.  
>> 
>> Out of curiosity, what part of my proposed syntax misses the mark for your 
>> use case?
> 
> I think it’s important that we be clear about when a default is and is not 
> available.  Your syntax makes the availability of a default non-local.
> 
> That's certainly true. It can be mitigated somewhat by placing the 
> definitions as close to the declaration as possible, but it's still up to the 
> user to do the right thing here:
> 
> ```
> struct Resourc

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-27 Thread Matthew Johnson via swift-evolution

> On Nov 27, 2017, at 1:24 PM, Tony Allevato <tony.allev...@gmail.com> wrote:
> 
> 
> 
> On Mon, Nov 27, 2017 at 11:12 AM Matthew Johnson via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> On Nov 27, 2017, at 12:50 PM, Douglas Gregor <dgre...@apple.com 
>> <mailto:dgre...@apple.com>> wrote:
>> 
>> 
>> 
>>> On Nov 24, 2017, at 3:11 PM, Matthew Johnson via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> As mentioned in my prior message, I currently have a PR open to update the 
>>> generics manifesto (https://github.com/apple/swift/pull/13012 
>>> <https://github.com/apple/swift/pull/13012>).  I removed one topic from 
>>> that update at Doug Gregor’s request that it be discussed on the list 
>>> first.  
>>> 
>>> The idea is to add the ability to make default arguments conditional (i.e. 
>>> depend on generic constraints).  It is currently possible to emulate 
>>> conditional default arguments using an overload set.  This is verbose, 
>>> especially when several arguments are involved.  Here is an example use 
>>> case using the overload method to emulate this feature:
>>> 
>>> ```swift
>>> protocol Resource {
>>>   associatedtype Configuration
>>>   associatedtype Action
>>> }
>>> struct ResourceDescription {
>>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>>> @escaping (R.Action) -> Void) -> R {
>>> // create a resource using the provided configuration
>>> // connect the action handler
>>> // return the resource
>>>   }
>>> }
>>> 
>>> extension ResourceDescription where R.Configuration == Void {
>>>   func makeResource(actionHandler: @escaping (R.Action) -> Void) -> R {
>>> return makeResource(with: (), actionHandler: actionHandler)
>>>   }
>>> }
>>> 
>>> extension ResourceDescription where R.Action == Never {
>>>   func makeResource(with configuration: R.Configuration) -> R {
>>> return makeResource(with: configuration, actionHandler: { _ in })
>>>   }
>>> }
>>> 
>>> extension ResourceDescription where R.Configuration == Void, R.Action == 
>>> Never {
>>>   func makeResource() -> R {
>>> return makeResource(with: (), actionHandler: { _ in })
>>>   }
>>> }
>>> 
>>> ```
>>> 
>>> Adding language support for defining these more directly would eliminate a 
>>> lot of boilerplate and reduce the need for overloads.
>> 
>> If one could refer to `self` in a default argument (which is not a big 
>> problem), you could turn the default into a requirement itself… although it 
>> doesn’t *quite* work with your example as written because it would always 
>> need to be implemented somehow:
>> 
>>> protocol Resource {
>>>   associatedtype Configuration
>>>   associatedtype Action
>> func defaultConfiguration() -> Configuration
>> func defaultHandler() -> ((R.Action) -> Void)
>>> }
> 
> This won’t work on its own for this use case because there is only a valid 
> default in relatively narrow (but common) cases.  For most values of 
> Configuration and Action an argument must be provided by the caller.  
> Xiaodi’s proposed syntax is the best fit (so far) for the use case I had in 
> mind.  
> 
> Out of curiosity, what part of my proposed syntax misses the mark for your 
> use case?

I think it’s important that we be clear about when a default is and is not 
available.  Your syntax makes the availability of a default non-local.

> 
> The parts that I think are somewhat unfortunate are losing a small bit of 
> reference locality and the introduction of a new operator to distinguish 
> between "default argument not present if no match found" vs. “com pile time 
> error", definitely. However, one unfortunate trend I've noticed when new 
> features are proposed is that there's a tendency to end up with "let's invent 
> @yet_another_attribute" and that just doesn't seem scalable or clean if we 
> can strive to better integrate it into the syntax of the language.

Xiaodi acknowledged that his suggestion is a bit clunky but I’m not sure we can 
do better while preserving clarity and making the defaults part of the function 
declaration.  If we added this feature it would be relatively advanced and 
usually used by library developers. 

Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-27 Thread Matthew Johnson via swift-evolution

> On Nov 27, 2017, at 12:50 PM, Douglas Gregor <dgre...@apple.com> wrote:
> 
> 
> 
>> On Nov 24, 2017, at 3:11 PM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> As mentioned in my prior message, I currently have a PR open to update the 
>> generics manifesto (https://github.com/apple/swift/pull/13012 
>> <https://github.com/apple/swift/pull/13012>).  I removed one topic from that 
>> update at Doug Gregor’s request that it be discussed on the list first.  
>> 
>> The idea is to add the ability to make default arguments conditional (i.e. 
>> depend on generic constraints).  It is currently possible to emulate 
>> conditional default arguments using an overload set.  This is verbose, 
>> especially when several arguments are involved.  Here is an example use case 
>> using the overload method to emulate this feature:
>> 
>> ```swift
>> protocol Resource {
>>   associatedtype Configuration
>>   associatedtype Action
>> }
>> struct ResourceDescription {
>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>> @escaping (R.Action) -> Void) -> R {
>> // create a resource using the provided configuration
>> // connect the action handler
>> // return the resource
>>   }
>> }
>> 
>> extension ResourceDescription where R.Configuration == Void {
>>   func makeResource(actionHandler: @escaping (R.Action) -> Void) -> R {
>> return makeResource(with: (), actionHandler: actionHandler)
>>   }
>> }
>> 
>> extension ResourceDescription where R.Action == Never {
>>   func makeResource(with configuration: R.Configuration) -> R {
>> return makeResource(with: configuration, actionHandler: { _ in })
>>   }
>> }
>> 
>> extension ResourceDescription where R.Configuration == Void, R.Action == 
>> Never {
>>   func makeResource() -> R {
>> return makeResource(with: (), actionHandler: { _ in })
>>   }
>> }
>> 
>> ```
>> 
>> Adding language support for defining these more directly would eliminate a 
>> lot of boilerplate and reduce the need for overloads.
> 
> If one could refer to `self` in a default argument (which is not a big 
> problem), you could turn the default into a requirement itself… although it 
> doesn’t *quite* work with your example as written because it would always 
> need to be implemented somehow:
> 
>> protocol Resource {
>>   associatedtype Configuration
>>   associatedtype Action
> func defaultConfiguration() -> Configuration
> func defaultHandler() -> ((R.Action) -> Void)
>> }

This won’t work on its own for this use case because there is only a valid 
default in relatively narrow (but common) cases.  For most values of 
Configuration and Action an argument must be provided by the caller.  Xiaodi’s 
proposed syntax is the best fit (so far) for the use case I had in mind.  

That said, the ability to refer to self in default arguments is complementary 
as it would expand the cases where conditional default arguments could be 
provided.  For example, in the example above it would allow a resource to 
provide a nontrivial default configuration.

> 
>>  Doug mentioned that it may also help simplify associated type inference 
>> (https://github.com/apple/swift/pull/13012#discussion_r152124535 
>> <https://github.com/apple/swift/pull/13012#discussion_r152124535>).
> 
> Oh, I thought this was something related to choosing a defaults for 
> associated types, which might have helped with my current 
> associated-type-inference quandary. The topic you actually wanted to discuss 
> is disjoint (sorry).

I was wondering how it was related and wondered if it was somehow due to 
reduction in the size of the overload set.  If you have any ideas on changes 
that might help guide the inference algorithm somehow please start a new 
thread.  Even if you’re only able to describe the challenges it might be worth 
a thread if it’s possible others might have useful ideas.  Improving the 
reliability and predictability of inference is a very important topic!

> 
>   - Doug
> 
> 

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


Re: [swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-25 Thread Matthew Johnson via swift-evolution

> On Nov 25, 2017, at 1:28 PM, Tony Allevato via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> On Fri, Nov 24, 2017 at 7:18 PM Xiaodi Wu via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> 
> 
> 
> It's kludgy, but we could have something like:
> 
> ```
> @defaultArgument(configuration = (), where R.Configuration == Void)
> @defaultArgument(actionHandler = { _ in }, where R.Action == Never)
> func makeResource(with configuration: R.Configuration, actionHandler: 
> @escaping (R.Action) -> Void) -> R { ... }
> ```
> 
> I don't like that we'd be setting a default argument on something lexically 
> before even encountering it in the declaration, but it's serviceable.
> 
> 
> What if we could take advantage of the fact that you can have non-constant 
> expressions in default arguments? Overload resolution could already do most 
> of the job—what we need on top of that is a way for the author to say that 
> “if no overload matches, then it’s not an error—just don’t have a default 
> argument in that case”. Something like SFINAE in C++, but more explicit.
> 
> I’m imagining something like this:
> 
> func defaultConfiguration() -> Void {
>   return ()
> }
> 
> func defaultActionHandler() -> (Never) -> Void {
>   return { _ in }
> }
> 
> struct ResourceDescription {
>   func makeResource(
> with configuration: R.Configuration =? defaultConfiguration(),
> actionHandler: @escaping (R.Action) -> Void =? defaultActionHandler()
>   ) -> R {
> // create a resource using the provided configuration
> // connect the action handler
> // return the resource
>   }
> }
> The main difference here is the strawman =? syntax, which would indicate that 
> “the default argument exists if there is a way the RHS can be satisfied for 
> some instances of the generic arguments; otherwise, there is no default”, 
> instead of today’s behavior where it would be an error. There could be 
> multiple overloads of defaultConfiguration and defaultActionHandler (even 
> ones that are themselves generic) and it would do the right thing when there 
> are matches and when there aren’t.
> 
> I like this approach because it mostly takes advantage of existing language 
> features and is fairly lightweight in terms of how it’s expressed in code 
> compared to regular default arguments—we’d just need to design the new 
> operator and type-checker logic around it.
> 
This is an interesting approach.  One advantage to something in this direction 
is that it could support defining different defaults for the same argument 
under different constraints by overloading the default argument factories on 
their return type.

One concern I have is that it doesn’t allows us to clearly define under which 
constraints a default argument is available.  I suspect this might be 
problematic especially for public interfaces where source compatibility is a 
concern.  

I think I prefer Xiaodi’s suggestion for that reason.  His approach could also 
support multiple defaults for the same parameter as long as the constraints are 
not allowed to overlap (overlapping constraints would result in ambiguity 
similar to ambiguous overload resolution) or an explicit argument is required 
if they do.

> 
> 
> 
> 
> 
> On Fri, Nov 24, 2017 at 8:36 PM, T.J. Usiyan via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> I am all for this. are many types where there is an obvious 'zero' or 
> 'default' value and the ability to express "use that when possible" without 
> an overload is welcome.
> 
> 
> The best thing that I can think of right now, in terms of syntax, is actually 
> using @overload
> 
> ```
> struct ResourceDescription {
> 
>   func makeResource(with configuration: R.Configuration, actionHandler: 
> @escaping (R.Action) -> Void) -> R 
>  @overload(R.Configuration == Void) func makeResource(actionHandler: 
> @escaping (R.Action) -> Void) -> R
> @overload(R.Action == Never)  func makeResource(with configuration: 
> R.Configuration) -> R
> {
> // create a resource using the provided configuration
> // connect the action handler
> // return the resource
>   }
> }
> ```
> 
> 
> This isn't great though…
> 
> On Fri, Nov 24, 2017 at 6:11 PM, Matthew Johnson via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> As mentioned in my prior message, I currently have a PR open to update the 
> generics manifesto (https://github.com/apple/swift/pull/13012 
> <https://github.com/apple/swift/pull/13012>).  I removed one topic from th

[swift-evolution] [Pre-pitch] Conditional default arguments

2017-11-24 Thread Matthew Johnson via swift-evolution
As mentioned in my prior message, I currently have a PR open to update the 
generics manifesto (https://github.com/apple/swift/pull/13012 
).  I removed one topic from that 
update at Doug Gregor’s request that it be discussed on the list first.  

The idea is to add the ability to make default arguments conditional (i.e. 
depend on generic constraints).  It is currently possible to emulate 
conditional default arguments using an overload set.  This is verbose, 
especially when several arguments are involved.  Here is an example use case 
using the overload method to emulate this feature:

```swift
protocol Resource {
  associatedtype Configuration
  associatedtype Action
}
struct ResourceDescription {
  func makeResource(with configuration: R.Configuration, actionHandler: 
@escaping (R.Action) -> Void) -> R {
// create a resource using the provided configuration
// connect the action handler
// return the resource
  }
}

extension ResourceDescription where R.Configuration == Void {
  func makeResource(actionHandler: @escaping (R.Action) -> Void) -> R {
return makeResource(with: (), actionHandler: actionHandler)
  }
}

extension ResourceDescription where R.Action == Never {
  func makeResource(with configuration: R.Configuration) -> R {
return makeResource(with: configuration, actionHandler: { _ in })
  }
}

extension ResourceDescription where R.Configuration == Void, R.Action == Never {
  func makeResource() -> R {
return makeResource(with: (), actionHandler: { _ in })
  }
}

```

Adding language support for defining these more directly would eliminate a lot 
of boilerplate and reduce the need for overloads.  Doug mentioned that it may 
also help simplify associated type inference 
(https://github.com/apple/swift/pull/13012#discussion_r152124535 
).

The reason that I call this a pre-pitch and one reason Doug requested it be 
discussed on list is that I haven’t thought of a good way to express this 
syntactically.  I am interested in hearing general feedback on the idea.  I am 
also looking for syntax suggestions.

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


[swift-evolution] [Pitch] Generalized supertype constraints

2017-11-24 Thread Matthew Johnson via swift-evolution
One of the most frequent frustrations I encounter when writing generic code in 
Swift is the requirement that supertype constraints be concrete.  When I 
mentioned this on Twitter 
(https://twitter.com/anandabits/status/929958479598534656 
) Doug Gregor 
mentioned that this feature is smaller and mostly straightforward to design and 
implement (https://twitter.com/dgregor79/status/929975472779288576 
).

I currently have a PR open to add the high-level description of this feature 
found below to the generics manifesto 
(https://github.com/apple/swift/pull/13012):

Currently, supertype constraints may only be specified using a concrete class 
or protocol type.  This prevents us from abstracting over the supertype.

```swift
protocol P {
  associatedtype Base
  associatedtype Derived: Base
}
```

In the above example `Base` may be any type.  `Derived` may be the same as 
`Base` or may be _any_ subtype of `Base`.  All subtype relationships supported 
by Swift should be supported in this context including, but not limited to, 
classes and subclasses, existentials and conforming concrete types or refining 
existentials, `T?` and  `T`, `((Base) -> Void)` and `((Derived) -> Void)`, etc.

Generalized supertype constraints would be accepted in all syntactic locations 
where generic constraints are accepted.

I would like to see generalized supertype constraints make it into Swift 5 if 
possible.  I am not an implementer so I will not be able to bring a proposal 
forward alone but am interested in collaborating with anyone interested in 
working on implementation.

I am also interested in hearing general feedback on this feature from the 
community at large.  Have you also found this limitation frustrating?  In what 
contexts?  Does anyone have reservations about introducing this capability?  If 
so, what are they?

Matthew

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


Re: [swift-evolution] [Pitch] Make Optional, Array, and Dictionary conditionally Equatable

2017-11-22 Thread Matthew Johnson via swift-evolution
Seems like a no-brainer to me.  If there has been any argument against making 
this change I am really curious to know what it is.  I’m super excited that 
this might make it into 4.1.  Woohoo!!!

> On Nov 22, 2017, at 12:51 AM, Douglas Gregor via swift-evolution 
>  wrote:
> 
> Hi all,
> 
> We’re having a bit of a debate  
> over the question of whether SE-0143 “Conditional Conformances” 
> 
>  actually proposes any standard library changes at all, or whether they 
> should all be brought up separately. So, I’ll pitch the pieces that I’d love 
> to put into 4.1 to see if they’re as obvious as I think they should be :)
> 
> Proposal: make Optional, Array, ArraySlice, ContiguousArray, and Dictionary 
> conform to Equatable when their type parameters are Equatable (and Set always 
> conform to Equatable). Specifically, add to the standard library:
> 
>   extension Optional: Equatable where Wrapped: Equatable { /*== already 
> exists */ }
>   extension Array: Equatable where Element: Equatable { /*== already 
> exists */ }
>   extension ArraySlice: Equatable where Element: Equatable { /*== already 
> exists */ }
>   extension ContiguousArray: Equatable where Element: Equatable { /*== 
> already exists */ }
>   extension Dictionary: Equatable where Value: Equatable { /*== already 
> exists */ }
>   extension Set: Equatable { /*== already exists */ }
> 
> Motivation: we need these for ==/!= to properly compose. It’s a 
> highly-requested feature and an obvious “first use” of conditional 
> conformances for the standard library that is unlikely to break any code.
> 
> Implementation: https://github.com/apple/swift/pull/13046 
> 
> 
> Thoughts?
> 
> 
>   - Doug
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [Pitch] Improving capturing semantics of local functions

2017-11-14 Thread Matthew Johnson via swift-evolution


Sent from my iPhone

> On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution 
>  wrote:
> 
> Having read all the arguments for what to add to local functions it still 
> strikes me as a poor use of engineering resources to fix them (though I do 
> agree they have problems). A better use of resources would be:
> 
>   1. Deprecate local functions.
>   2. Allow closures when assigned to a function type to be:
>   2a. Recursive.
>   2b. Annotatable with:
> 2bi.  @inline
> 2bii. @escaping
>   2c. Generic.
> 
> That would be a similar engineering effort and give a better short term 
> result of better closures which would be much more widely applicable as well 
> as addressing the issues with local functions.

I believe generic closures would require adding higher rank types to Swift.  
That would be pretty cool but I suspect the engineering effort is at least an 
order of magnitude greater than the changes discussed in this thread.

> 
> It also gives a better long term result of not having to maintain local 
> functions.
>   
> 
>   -- Howard.
> 
>> On 15 November 2017 at 09:08, Alex Lynch via swift-evolution 
>>  wrote:
>> The inference algebra just suggested was enjoyable to read, but is still a 
>> new syntax. Which is interesting and deserving of its own proposal. The 
>> purpose of this proposal is simply to introduce the existing capture syntax 
>> to local functions. Thanks to everyone's feedback pointing out that the 
>> `self` reference analysis is a deeper question than initially realized. 
>> 
>> Alex
>> 
>>> On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution 
>>>  wrote:
 On 14 November 2017 at 21:02, David Hart  wrote:
>>> 
 
 
 I’d be very hesitant to introduce this syntax:
 
 it’s new syntax, so it comes with a complexity tax (it isn’t naturally 
 obvious what it means for a func to be weak)
 it’s only sugar for the capture of self
>>> 
>>> it might cover well over 90% of use cases (by my "pessimistic" estimate)... 
>>> if someone has a quick way to scan and analyse, say, github swift sources 
>>> we may even know that current percentage number of real life usage.
 it doesn’t transpose well to local closures
>>> 
>>> the last one - maybe not. follow me:
>>> 
>>> let closure = { [weak self, bar] in ... }
>>> 
>>> which today can be written as: 
>>> 
>>> let closure = { [weak self, bar] () -> Int in ... } // full form
>>> 
>>> or as:
>>> 
>>> let closure: () -> Int = { [weak self, bar] in ... } // full form
>>> 
>>> which allows this change:
>>> 
>>> let closure:  [weak self, bar] () -> Int = { ... } // full alt form
>>> 
>>> or in alternative form:
>>> 
>>> let closure:  weak () -> Int = { [bar] in ... } // short hand form
>>> 
>>> same can be with functions:
>>> 
>>> func fn() -> Int { [weak self, bar] in ... } // full form
>>> 
>>> weak func fn() -> Int { [bar] in ... } // short hand form
>>> 
>>> the two capture attributes will in practice be "close" to each other:
>>> 
>>> weak func fn() {
>>> [bar] in
>>> 
>>> }
>>> 
>>> and in majority of cases there will be only weak self:
>>> 
>>> weak func fn() {
>>> 
>>> }
>>> 
>>> Mike
>>> 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> 
>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

2017-11-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Nov 11, 2017, at 5:27 PM, Chris Lattner <clatt...@nondot.org> wrote:
> 
> Ok, which differences?
> 
> -Chris
> 
>> On Nov 11, 2017, at 2:19 PM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>>> On Nov 11, 2017, at 11:40 AM, Chris Lattner <sa...@nondot.org> wrote:
>>> 
>>> On Nov 10, 2017, at 6:10 PM, Matthew Johnson via swift-evolution 
>>> <swift-evolution@swift.org> wrote:
>>>>>> On Nov 10, 2017, at 11:25 AM, Matthew Johnson via swift-evolution 
>>>>>> <swift-evolution@swift.org> wrote:
>>>>>> 
>>>>>>>> 
>>>>>>>> People have reasonably asked for the ability to make their own 
>>>>>>>> function-like types in the past, such that "myvalue(...)" behaves like 
>>>>>>>> sugar for "myvalue.call(...)" or something like that. In most cases, 
>>>>>>>> they still want to have type system control over what arguments and 
>>>>>>>> results their call operation produces. They don't really get that with 
>>>>>>>> this proposal; they lose all control over the arity and argument 
>>>>>>>> types. 
>>>>>>> 
>>>>>>> As I mentioned, this is directly addressed in the writeup. Here’s the 
>>>>>>> link:
>>>>>>> https://gist.github.com/lattner/a6257f425f55fe39fd6ac7a2354d693d#staticly-checking-for-exact-signatures
>>>>>> 
>>>>>> That discusses why you didn’t include it in the present proposal but I 
>>>>>> think it’s reasonable to oppose adding a dynamic callable feature prior 
>>>>>> to a more Swifty static callable.
>>>>> 
>>>>> Why?  One does not preclude the other.
>>>> 
>>>> For exactly the reason Joe articulates.  Some people will use what the 
>>>> language offers to get the syntax they desire even if it sacrifices type 
>>>> safety.  If we’re going to have first-class callable types in Swift (I 
>>>> think it’s a great idea) type safety for native code should be prioritized 
>>>> over syntactic convenience for dynamic language interop.  We can have 
>>>> both, but the former should come first IMO.
>>> 
>>> Hi Matthew,
>>> 
>>> In point of fact, Swift already has the feature you are referring to.  It 
>>> just spells it with square brackets instead of parentheses.  A simple 
>>> change to the punctuation character has much less point than the proposal 
>>> that I’m pitching.
>> 
>> This is true if you squint, but I imagine a design for callable types would 
>> include some 
>>  differences other than just punctuation.

I think there was a pretty good discussion of this distinction in the  SE-0021 
timeframe.  Specifically, subscripts model storage while callable would model 
functions.  This means that subscripts can be used in a key path while callable 
would not (at last for now).  

On the other hand, I would want to see callables implicitly convert to a value 
of a compatible function type (possibly through a subtype relationship). 
Without this capability the syntactic illusion is only half complete.  The 
callable feels like a function when used directly but not when it is assigned 
to a function type or passed elsewhere - it must be explicitly be wrapped in a 
closure and the arguments forwarded.  First-class callable types are a 
syntactic sugar feature and as such if they exist they should be usable 
syntactically in all of the same ways functions are.

Read-only subscripts are ok as a workaround in absence of first-class callable 
types (although I think in many ways just using `call` is better).  
Nevertheless, they are a workaround and can never be more than that because of 
the fundamental difference in what they model.

Matthew

>> 
>>> 
>>> -Chris
>>> 
>>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

2017-11-11 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Nov 11, 2017, at 11:40 AM, Chris Lattner <sa...@nondot.org> wrote:
> 
> On Nov 10, 2017, at 6:10 PM, Matthew Johnson via swift-evolution 
> <swift-evolution@swift.org> wrote:
>>>> On Nov 10, 2017, at 11:25 AM, Matthew Johnson via swift-evolution 
>>>> <swift-evolution@swift.org> wrote:
>>>> 
>>>>>> 
>>>>>> People have reasonably asked for the ability to make their own 
>>>>>> function-like types in the past, such that "myvalue(...)" behaves like 
>>>>>> sugar for "myvalue.call(...)" or something like that. In most cases, 
>>>>>> they still want to have type system control over what arguments and 
>>>>>> results their call operation produces. They don't really get that with 
>>>>>> this proposal; they lose all control over the arity and argument types. 
>>>>> 
>>>>> As I mentioned, this is directly addressed in the writeup. Here’s the 
>>>>> link:
>>>>> https://gist.github.com/lattner/a6257f425f55fe39fd6ac7a2354d693d#staticly-checking-for-exact-signatures
>>>> 
>>>> That discusses why you didn’t include it in the present proposal but I 
>>>> think it’s reasonable to oppose adding a dynamic callable feature prior to 
>>>> a more Swifty static callable.
>>> 
>>> Why?  One does not preclude the other.
>> 
>> For exactly the reason Joe articulates.  Some people will use what the 
>> language offers to get the syntax they desire even if it sacrifices type 
>> safety.  If we’re going to have first-class callable types in Swift (I think 
>> it’s a great idea) type safety for native code should be prioritized over 
>> syntactic convenience for dynamic language interop.  We can have both, but 
>> the former should come first IMO.
> 
> Hi Matthew,
> 
> In point of fact, Swift already has the feature you are referring to.  It 
> just spells it with square brackets instead of parentheses.  A simple change 
> to the punctuation character has much less point than the proposal that I’m 
> pitching.

This is true if you squint, but I imagine a design for callable types would 
include some 
 differences other than just punctuation.

> 
> -Chris
> 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

2017-11-10 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Nov 10, 2017, at 7:41 PM, Chris Lattner <sa...@nondot.org> wrote:
> 
> 
>> On Nov 10, 2017, at 11:25 AM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>>>> 
>>>> People have reasonably asked for the ability to make their own 
>>>> function-like types in the past, such that "myvalue(...)" behaves like 
>>>> sugar for "myvalue.call(...)" or something like that. In most cases, they 
>>>> still want to have type system control over what arguments and results 
>>>> their call operation produces. They don't really get that with this 
>>>> proposal; they lose all control over the arity and argument types. 
>>> 
>>> As I mentioned, this is directly addressed in the writeup. Here’s the link:
>>> https://gist.github.com/lattner/a6257f425f55fe39fd6ac7a2354d693d#staticly-checking-for-exact-signatures
>> 
>> That discusses why you didn’t include it in the present proposal but I think 
>> it’s reasonable to oppose adding a dynamic callable feature prior to a more 
>> Swifty static callable.
> 
> Why?  One does not preclude the other.

For exactly the reason Joe articulates.  Some people will use what the language 
offers to get the syntax they desire even if it sacrifices type safety.  If 
we’re going to have first-class callable types in Swift (I think it’s a great 
idea) type safety for native code should be prioritized over syntactic 
convenience for dynamic language interop.  We can have both, but the former 
should come first IMO.

Setting this aside, I’m very curious to hear whether type providers influence 
your thinking after you’ve had a chance to look into them.  I have always 
thought they were very cool.

> 
> -Chris
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

2017-11-10 Thread Matthew Johnson via swift-evolution

> On Nov 10, 2017, at 1:19 PM, Chris Lattner via swift-evolution 
>  wrote:
> 
>> On Nov 10, 2017, at 10:51 AM, Joe Groff via swift-evolution 
>> > wrote:
>>> 
 Since we also lack the more obvious static "Callable" protocol idea to 
 give even well-typed call syntax to user-defined types, this also seems 
 like it'd be easily abused for that purpose too.
>>> 
>>> Similarly, I’d love for you to elaborate on how the potential for abuse of 
>>> this feature is different than anything else in Swift (e.g. operator 
>>> overloading).  Potential for abuse hasn’t been a particularly guiding force 
>>> in the design on Swift, and for good reasons.
>>> 
>>> I also don’t understand what you mean by a static Callable protocol.  I 
>>> specifically address what I think you might mean in the “alternatives” part 
>>> of the proposal, did you read that?
>> 
>> People have reasonably asked for the ability to make their own function-like 
>> types in the past, such that "myvalue(...)" behaves like sugar for 
>> "myvalue.call(...)" or something like that. In most cases, they still want 
>> to have type system control over what arguments and results their call 
>> operation produces. They don't really get that with this proposal; they lose 
>> all control over the arity and argument types.
> 
> As I mentioned, this is directly addressed in the writeup. Here’s the link:
> https://gist.github.com/lattner/a6257f425f55fe39fd6ac7a2354d693d#staticly-checking-for-exact-signatures
>  
> 
That discusses why you didn’t include it in the present proposal but I think 
it’s reasonable to oppose adding a dynamic callable feature prior to a more 
Swifty static callable.

> 
> -Chris
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

2017-11-10 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Nov 10, 2017, at 12:51 PM, Joe Groff via swift-evolution 
>  wrote:
> 
> 
> 
>> On Nov 10, 2017, at 10:41 AM, Chris Lattner  wrote:
>> 
>> On Nov 10, 2017, at 10:03 AM, Joe Groff  wrote:
>>> 
>>> I don't like the idea of some calls having wildly different semantics from 
>>> others; it's difficult enough to tell what exactly a call might be doing 
>>> already.
>> 
>> This isn’t particularly useful feedback.  Can you elaborate more on what 
>> your concern is, and how calls are unlike anything else in Swift that would 
>> have this potential problem?
>> 
>>> Since we also lack the more obvious static "Callable" protocol idea to give 
>>> even well-typed call syntax to user-defined types, this also seems like 
>>> it'd be easily abused for that purpose too.
>> 
>> Similarly, I’d love for you to elaborate on how the potential for abuse of 
>> this feature is different than anything else in Swift (e.g. operator 
>> overloading).  Potential for abuse hasn’t been a particularly guiding force 
>> in the design on Swift, and for good reasons.
>> 
>> I also don’t understand what you mean by a static Callable protocol.  I 
>> specifically address what I think you might mean in the “alternatives” part 
>> of the proposal, did you read that?
> 
> People have reasonably asked for the ability to make their own function-like 
> types in the past, such that "myvalue(...)" behaves like sugar for 
> "myvalue.call(...)" or something like that. In most cases, they still want to 
> have type system control over what arguments and results their call operation 
> produces. They don't really get that with this proposal; they lose all 
> control over the arity and argument types. That may be what you want for 
> calling into a dynamically-typed black hole, but it's not what you want in 
> general. I fear that people would be willing to compromise their designs in 
> order to get the sugar they want by contorting to fit this design.

+1.  This exact concern is the first thing that came to mind while reading this 
proposal.  

The general problem of interop with dynamic languages is an important one but a 
solution shouldn’t come at the cost of introducing syntactic sugar that is 
sub-optimal for native Swift code.

> 
>> 
>>> I think a much better general solution to the problem of "make dynamic 
>>> systems interact with type systems" is something like F#'s type providers 
>>> which lets you write your own importers that look at dynamic information 
>>> from a database, dynamic language VM, or some other system and generate 
>>> type information usable by the compiler.
>> 
>> Thanks! I wasn’t aware of type providers, I’ll investigate them.
>> 
>>> Integration at the importer level could let you produce more well-typed 
>>> Swift declarations by looking at the runtime information you get by 
>>> importing a Python module.
>> 
>> This is also addressed directly in the proposal.  I don’t want to add Python 
>> specific support to Swift.  The motivations are explained in the proposal.
> 
> I'm not suggesting a Python-specific feature, I'm suggesting that type 
> providers could be a general framework for the kinds of problems you 
> encounter trying to make dynamic systems work with Swift, including Python.
> 
> -Joe
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [swift-evolution-announce] [Review] SE-188 Make stdlib index types Hashable

2017-11-09 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Nov 9, 2017, at 6:29 AM, Xiaodi Wu via swift-evolution 
>  wrote:
> 
> 
>> On Thu, Nov 9, 2017 at 05:28 Brent Royal-Gordon via swift-evolution 
>>  wrote:
>> >   
>> > https://github.com/apple/swift-evolution/blob/master/proposals/0188-stdlib-index-types-hashable.md
>> >
>> > • What is your evaluation of the proposal?
>> 
>> This all seems very sensible, but here's my big question:
>> 
>> AnyIndex, which type erases any index type at run-time, would not be 
>> hashable since it might wrap a non-hashable type.
>> 
>> Why not? Specifically, why shouldn't we require `Hashable` conformance on 
>> indices? Adding it would require changes to conforming types, sure, but 
>> indices are already required to be `Equatable`, and `Hashable` conformance 
>> just got really easy to add, and custom `Collection`s are a relatively rare 
>> and advanced feature.
> 
> For a source-breaking change, that’s the wrong question to ask. It’s not “why 
> not,” but “why so”? It’s so easy to add the conformance, and any type can opt 
> into it so easily, what is the gain by forcing it and can it be justified as 
> a source-breaking change?

In this case we’re talking about the requirements on indices when ABI stability 
happens.  That’s a pretty important point of design to get right.  I think 
Brent *is* asking the right question in this case.  I haven’t given it enough 
thought to form a clear opinion as to the answer yet.

> 
>> 
>> Is it worth a source break to add it? Personally, I think so—but even if you 
>> disagree, I think we should document why we decided not to add it.
>> 
>> > • Is the problem being addressed significant enough to warrant a change to 
>> > Swift?
>> 
>> Yes.
>> 
>> > • Does this proposal fit well with the feel and direction of Swift?
>> 
>> Yes.
>> 
>> > • If you have used other languages or libraries with a similar feature, 
>> > how do you feel that this proposal compares to those?
>> 
>> N/A.
>> 
>> > • How much effort did you put into your review? A glance, a quick reading, 
>> > or an in-depth study?
>> 
>> Quick reading, nothing more.
>> 
>> --
>> Brent Royal-Gordon
>> Architechies
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Pitch: Remove default initialization of optional bindings

2017-11-06 Thread Matthew Johnson via swift-evolution

> On Nov 6, 2017, at 4:33 PM, Slava Pestov via swift-evolution 
>  wrote:
> 
> Hi all,
> 
> Right now, the following two declarations are equivalent:
> 
> struct S {
>  var x: Int?
> }
> 
> struct S {
>  var x: Int? = nil
> }
> 
> That is, mutable bindings of sugared optional type (but not Optional!) 
> always have a default value of ‘nil’. This feature increases the surface area 
> of the language for no good reason, and I would like to deprecate it in 
> -swift-version 5 with a short proposal. Does anyone feel strongly about 
> giving it up? I suspect most Swift users don’t even know it exists.

I don’t have too strong an opinion on this, leaning towards being supportive.  
That said, I think you underestimate the source breakage it will cause.  I have 
seen a lot  of code this change will break (albeit in a trivial way that’s easy 
to migrate).

> 
> Slava
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] Adding Result to the Standard Library

2017-11-02 Thread Matthew Johnson via swift-evolution
I have been writing code in a style that uses explicit effect handling lately.  
In this style of code, a request describing an async task is returned from a 
function and later interpreted by a library.  When the task completes the 
library passes the result to completion handler that is part of the task 
description (which produces subsequent effects to interpret).  

It isn’t possible to express the completion handlers attached to task 
descriptions as an async call.  The function needs to return the task 
description immediately.  For this reason, I believe it will be necessary to 
continue using a Result type in code written in this style even after async / 
await is introduced.

> On Nov 2, 2017, at 1:53 PM, Dan Stenmark via swift-evolution 
>  wrote:
> 
> With the upcoming async-await constructs supporting do-try-catch natively, 
> what would the use-case for an explicit Result type be?
> 
> Dan
> 
>> On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution 
>> > wrote:
>> 
>> Swift-Evolution:
>>  I’ve written a first draft of a proposal to add Result to the 
>> standard library by directly porting the Result type used in Alamofire to 
>> the standard library. I’d be happy to implement it (type and tests for 
>> free!) if someone could point me to the right place to do so. I’m not 
>> including it directly in this email, since it includes the full 
>> implementation and is therefore quite long. (Discourse, please!) 
>> 
>> https://github.com/jshier/swift-evolution/blob/master/proposals/0187-add-result-to-the-standard-library.md
>>  
>> 
>> 
>> 
>> Thanks, 
>> 
>> Jon Shier
>> 
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] Pitch: Member lookup on String should not find members of NSString

2017-10-25 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Oct 24, 2017, at 5:55 PM, Slava Pestov via swift-evolution 
>  wrote:
> 
> I think to maintain source compatibility, the old behavior would be preserved 
> until/if we remove -swift-version 4 mode. By deprecating it though, we won’t 
> have to devote as much time to maintaining it going forward.

I think the point is that some of the APIs should continue to be offered, but 
directly rather than via NSString.  We need an analysis of what APIs are 
affected that includes recommendations on which to deprecate and which to 
replace.  We can’t make an informed decision without that.

> 
> Slava
> 
>> On Oct 24, 2017, at 3:54 PM, Philippe Hausler  wrote:
>> 
>> I think any serious proposal with the removal of APIs would need to consider 
>> source compatibility and to do so you should likely audit the API surface 
>> area that is being offered (and replace it via the NSStringAPI.swift 
>> extension)
>> 
>>> On Oct 24, 2017, at 3:12 PM, Slava Pestov via swift-evolution 
>>>  wrote:
>>> 
>>> Perhaps you could write up a proposal to outline the missing functionality 
>>> :-)
>>> 
>>> Slava
>>> 
 On Oct 24, 2017, at 3:09 PM, Jonathan Hull  wrote:
 
 I would feel better about it if String gained a lot of the utility of 
 NSString (so that we don’t have to go to NSString all the time for methods)
 
 Thanks,
 Jon
 
> On Oct 24, 2017, at 3:00 PM, Slava Pestov via swift-evolution 
>  wrote:
> 
> Hi,
> 
> Members of NSString, except those defined in Foundation, are available on 
> values of type String. For example,
> 
> extension NSString {
> @objc func foo() {}
> }
> 
> let s: String = “hello”
> 
> s.foo()
> 
> We don’t do this for any other bridged types, for instance NSArray 
> methods are not imported as Array methods. It’s literally a special case 
> in the type checker for member lookup on String.
> 
> This behavior doesn’t really much sense conceptually and it was put in as 
> a stop-gap in Swift 1 to beef up the String API. I would like to phase it 
> out as follows:
> 
> - Unconditional warning in Swift 4.1, with a fixit to insert an ‘as 
> NSString’ cast
> - Error in Swift 5 with -swift-version 5
> 
> What does everyone think about this?
> 
> Slava
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
 
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [draft] Introduce Sequence.filteredMap(_:)

2017-10-24 Thread Matthew Johnson via swift-evolution

> On Oct 24, 2017, at 1:57 AM, David Hart via swift-evolution 
>  wrote:
> 
> I also cast my vote for filterMap. It’s concise, understandable and is kind 
> of a term of art also.

+1.  This seems like the best option to me.

> 
>> On 24 Oct 2017, at 02:56, BJ Homer via swift-evolution 
>> > wrote:
>> 
>> I agree with Xiaodi; I like ‘filterMap’ more than ‘filteredMap’. But both 
>> are superior to ‘flatMap’ in this context.
>> 
>> -BJ
>> 
>> On Oct 23, 2017, at 5:22 PM, Max Moiseev > > wrote:
>> 
>>> It occurred to me that filteringMap(_:) should be even more descriptive, 
>>> still conform to the guidelines, although similarly unprecedented and 
>>> un-googlable.
>>> 
>>> Max
>>> 
 On Oct 23, 2017, at 3:52 PM, Xiaodi Wu > wrote:
 
 +1 in general. As to the name: since 'map' is used as a term of art, 
 'filterMap' seems superior to 'filteredMap', which half follows naming 
 guidelines and half is a term of art; neither is immediately 
 comprehensible but 'filterMap' can be googled and has precedents in other 
 languages.
 On Mon, Oct 23, 2017 at 17:24 BJ Homer via swift-evolution 
 > wrote:
 I strongly agree! In fact, I just started writing up a similar proposal 
 the other day, but hadn’t had time to finish it yet.
 
 The current name for this particular filtering variant is not particularly 
 descriptive. It’s certainly not obvious to newcomers that ‘flatMap’ will 
 filter out results. And it’s not true to the existing usage of ‘flatMap' 
 from other languages; you have to really squint at it to see how any 
 “flattening” is happening at all.
 
 So yes, a big +1 from me. Thanks!
 
 -BJ Homer
 
> On Oct 23, 2017, at 4:15 PM, Max Moiseev via swift-evolution 
> > wrote:
> 
> Hi swift-evolution!
> 
> I would like to propose the following change to the standard library:
> 
> deprecate `Sequence.flatMap(_: (Element) -> U?) -> [U]` and make this 
> functionality available under a new name `Sequence.filteredMap(_:)`.
> 
> The draft is available at 
> https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95 
>  and is 
> included below for your convenience.
> 
> Max
> 
> Introduce Sequence.filteredMap(_:)
> 
> Proposal: SE- 
> Authors: Max Moiseev 
> Review Manager: TBD
> Status: Awaiting implementation
>  
> Introduction
> 
> We propose to deprecate the controversial version of a Sequence.flatMap 
> method and provide the same functionality under a different, and 
> potentially more descriptive, name.
> 
>  
> Motivation
> 
> The Swift standard library currently defines 3 distinct overloads for 
> flatMap:
> 
> Sequence.flatMap(_: (Element) -> S) -> [S.Element]
> where S : Sequence
> Optional.flatMap(_: (Wrapped) -> U?) -> U?
> Sequence.flatMap(_: (Element) -> U?) -> [U]
> The last one, despite being useful in certain situations, can be (and 
> often is) misused. Consider the following snippet:
> 
> struct Person {
>   var age: Int
>   var name: String
> }
> 
> func getAges(people: [Person]) -> [Int] {
>   return people.flatMap { $0.age }
> }
> What happens inside getNames is: thanks to the implicit promotion to 
> Optional, the result of the closure gets wrapped into a .some, then 
> immediately unwrapped by the implementation of flatMap, and appended to 
> the result array. All this unnecessary wrapping and unwrapping can be 
> easily avoided by just using map instead.
> 
> func getAges(people: [Person]) -> [Int] {
>   return people.map { $0.age }
> }
> It gets even worse when we consider future code modifications, like the 
> one where Swift 4 introduced a Stringconformance to the Collection 
> protocol. The following code used to compile (due to the flatMap overload 
> in question).
> 
> func getNames(people: [Person]) -> [String] {
>   return people.flatMap { $0.name }
> }
> But it no longer does, because now there is a better overload that does 
> not involve implicit promotion. In this particular case, the compiler 
> error would be obvious, as it would point at the same line where flatMap 
> is used. Imagine however 

Re: [swift-evolution] Fix "private extension" (was "Public Access Modifier Respected in Type Definition")

2017-10-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Oct 2, 2017, at 7:33 PM, Jordan Rose via swift-evolution 
>  wrote:
> 
> 
> 
>> On Oct 2, 2017, at 03:25, Vladimir.S via swift-evolution 
>>  wrote:
>> 
>> On 01.10.2017 1:18, Chris Lattner wrote:
 On Sep 29, 2017, at 10:42 AM, Xiaodi Wu via swift-evolution 
  wrote:
 
 Vladimir, I agree with you on that change, but it’s a separate topic from 
 this one.
 
 Tony is absolutely correct that this topic has already been discussed. It 
 is a deliberate design decision that public types do not automatically 
 expose members without explicit access modifiers; this has been brought up 
 on this list, and it is clearly not in scope for discussion as no new 
 insight can arise this late in the game. The inconsistency with public 
 extensions was brought up, the proposed solution was to remove modifiers 
 for extensions, but this proposal was rejected. So, the final design is 
 what we have.
>>> Agreed.  The core team would only consider a refinement or change to access 
>>> control if there were something actively broken that mattered for ABI 
>>> stability.
>> 
>> So we have to live with *protected* extension inconsistency for very long 
>> time just because core team don't want to even discuss _this particular_ 
>> inconsistency(when access level in *private extension* must be private, not 
>> fileprivate)?
>> 
>> Yes, we decided that access level for extension will mean a default and top 
>> most access level for nested methods, OK. But even in this rule, which 
>> already differ from access modifiers for types, we have another one special 
>> case for 'private extension'.
>> 
>> Don't you think this is not normal situation and actually there IMO can't be 
>> any reason to keep this bug-producing inconsistency in Swift? (especially 
>> given Swift 5 seems like is a last moment to fix this)
> 
> I hate to say it but I'm inclined to agree with Vladimir on this. "private 
> extension" has a useful meaning now distinct from "fileprivate extension", 
> and it was an oversight that SE-0169 didn't include a fix here. On this very 
> narrow, very specific access control issue I think it would still be worth 
> discussing; like Xiaodi said it's not related to James' original 
> thread-starter.

I agree with this in principle but would not want to see it become a slippery 
slope back into extremely long access control discussions.

> 
> (I maintain that the current model does not include a special case; it simply 
> means the 'private' is resolved at the level of the extension rather than the 
> level of its members. But that isn't what people expect and it's not as 
> useful.)
> 
> 
> I agree that changing the behavior of all access modifiers on extensions is 
> out of scope. (I also agree that it is a bad idea. Sorry, James, but wanting 
> 'pubic' here indicates that your mental model of extensions does not match 
> what Swift is actually doing, and that could get you into trouble.)
> 
> Jordan
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Enums and Source Compatibility

2017-09-18 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Sep 17, 2017, at 5:02 PM, Jonathan Hull  wrote:
> 
> 
>> On Sep 17, 2017, at 7:55 AM, Matthew Johnson  wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>>> On Sep 17, 2017, at 3:37 AM, Jonathan Hull via swift-evolution 
>>>  wrote:
>>> 
>>> I run into use cases like this all the time…
>>> 
>>> I think I would prefer to see those concrete cases in a subtype though:
>>> 
>>> enum DrinkSize {
>>> case small
>>> case medium
>>> case large
>>> }
>>> 
>>> enum SummerDrinkSize : DrinkSize {
>>> //Inherits DrinkSize’s cases
>>> case extraLarge
>>> }
>>> 
>>> Because it is a subtype, you could place a SummerDrinkSize anywhere you can 
>>> put a DrinkSize.  As a result, all switches on it would need a default case 
>>> to handle cases they hadn’t planned for. If you mark an enum with “final” 
>>> then it can’t be extended and switches can be exhaustive.
>> 
>> You have the subtype relationship backwards here.  DrinkSize is a subtype of 
>> SummerDrinkSize.  All values of DrinkSize are also valid values of 
>> SummerDrinkSize but not vice versa.  For this reason, inheritance syntax 
>> doesn't make sense.  The syntax that makes more sense is some kind of case 
>> embedding syntax:
>> 
>> enum SummerDrinkSize {
>>  cases DrinkSize
>>  case extraLarge
>> }
> 
> I disagree.  I get that the shape of a DrinkSize would always fit in a 
> SummerDrinkSize hole (ignoring the overriding/extension of methods), but the 
> fact that we are requiring ‘default’ in switches changes the calculus.  
> Basically, it changed when we decided to change whether exhaustive was the 
> default.  The point is to make people consider that they may have cases which 
> they may not expect.  That is much easier with a concrete idea of subtype, 
> which people are already used to.

Requiring developers to consider cases that may be added to an enum in the 
future is orthogonal to any potential subtype relationship between two value 
types.

> 
> 
>>> 
>>> In addition to inheriting the cases, a subtype would also inherit, and be 
>>> able to override, methods defined on the super-type.  You could use super 
>>> to call the super-type’s implementation. 
>> 
>> I think implementation sharing is a bad idea for value types.  Value 
>> subtyping should be conceptualized as a restricted mechanism for 
>> value-preserving implicit conversion.
> 
> Why?

First, this is how value subtyping already works in the case of Optional where 
`T` is a subtype of `T?`.

More generally, this approach is roughly analogous to implicit promotion in 
C-family languages.  We want `Int8` to be a subtype of `Int16`, `Int32`, `Int`, 
etc.

This approach allows a value type to have multiple value-preserving supertypes 
without the performance impact of dynamic dispatch or the complexity of 
multiple inheritance.

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


Re: [swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

2017-09-09 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Sep 9, 2017, at 11:42 AM, gs. <griotsp...@gmail.com> wrote:
> 
> How does fragility play into this? Does this only work for fragile (closed) 
> and internal/private/fileprivate enums?

That's a great question.  I think it would have to have that limitation.  Using 
Jordan's terminology, by definition a nonexhaustive cannot provide a complete 
list of all values.

> 
> TJ 
> 
>> On Sep 9, 2017, at 15:23, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>>> On Sep 9, 2017, at 7:33 AM, Brent Royal-Gordon <br...@architechies.com> 
>>> wrote:
>>> 
>>>> On Sep 8, 2017, at 5:14 PM, Xiaodi Wu via swift-evolution 
>>>> <swift-evolution@swift.org> wrote:
>>>> 
>>>> Here, people just want an array of all cases. Give them an array of all 
>>>> cases. When it's not possible (i.e., in the case of cases with associated 
>>>> values), don't do it.
>>> 
>>> 
>>> I agree it should be Int-indexed; that seems to be what people want from 
>>> this.
>>> 
>>> I seem to recall that there is information about the available enum cases 
>>> in the module metadata. If so, and if we're willing to lock that in as part 
>>> of the ABI design, I think we should write—or at least allow for—a custom 
>>> Int-indexed collection, because this may allow us to recurse into 
>>> associated value types. If we aren't going to have suitable metadata, 
>>> though, I agree we should just use an Array. There are pathological cases 
>>> where instantiating a large Array might be burdensome, but sometimes you 
>>> just have to ignore the pathological cases.
>>> 
>>> (The "infinite recursion" problem with associated values is actually 
>>> relatively easy to solve, by the way: Don't allow, or at least don't 
>>> generate, `ValuesEnumerable` conformance on enums with `indirect` cases.)
>> 
>> This is the direction I think makes the most sense in terms of how we should 
>> approach synthesis.  The open question in my mind is what the exact 
>> requirement of the protocol should be.  Should it exactly match what we 
>> synthesize (`[Self]` or an associated `Collection where Iterator.Element == 
>> Self, Index == Int`) or whether the protocol should have a more relaxed 
>> requirement of `Sequence where Iterator.Element == Self` like Tony proposed.
>> 
>>> 
>>> -- 
>>> Brent Royal-Gordon
>>> Architechies
>>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

2017-09-09 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Sep 9, 2017, at 7:33 AM, Brent Royal-Gordon  wrote:
> 
>> On Sep 8, 2017, at 5:14 PM, Xiaodi Wu via swift-evolution 
>>  wrote:
>> 
>> Here, people just want an array of all cases. Give them an array of all 
>> cases. When it's not possible (i.e., in the case of cases with associated 
>> values), don't do it.
> 
> 
> I agree it should be Int-indexed; that seems to be what people want from this.
> 
> I seem to recall that there is information about the available enum cases in 
> the module metadata. If so, and if we're willing to lock that in as part of 
> the ABI design, I think we should write—or at least allow for—a custom 
> Int-indexed collection, because this may allow us to recurse into associated 
> value types. If we aren't going to have suitable metadata, though, I agree we 
> should just use an Array. There are pathological cases where instantiating a 
> large Array might be burdensome, but sometimes you just have to ignore the 
> pathological cases.
> 
> (The "infinite recursion" problem with associated values is actually 
> relatively easy to solve, by the way: Don't allow, or at least don't 
> generate, `ValuesEnumerable` conformance on enums with `indirect` cases.)

This is the direction I think makes the most sense in terms of how we should 
approach synthesis.  The open question in my mind is what the exact requirement 
of the protocol should be.  Should it exactly match what we synthesize 
(`[Self]` or an associated `Collection where Iterator.Element == Self, Index == 
Int`) or whether the protocol should have a more relaxed requirement of 
`Sequence where Iterator.Element == Self` like Tony proposed.

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 4:26 PM, Robert Widmann <devteam.cod...@gmail.com> wrote:
> 
>> 
>> On Sep 8, 2017, at 2:59 PM, Matthew Johnson <matt...@anandabits.com 
>> <mailto:matt...@anandabits.com>> wrote:
>> 
>>> 
>>> On Sep 8, 2017, at 2:17 PM, Robert Widmann <devteam.cod...@gmail.com 
>>> <mailto:devteam.cod...@gmail.com>> wrote:
>>> 
>>>> 
>>>> On Sep 4, 2017, at 11:35 AM, Matthew Johnson via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> 
>>>>> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan <griotsp...@gmail.com 
>>>>> <mailto:griotsp...@gmail.com>> wrote:
>>>>> 
>>>>> I wasn't arguing for a strictly parallel syntax. I was arguing against 
>>>>> being able to omit labels. I don't view those as strictly tied together. 
>>>>> How are they?
>>>> 
>>>> Like Xiaodi I don’t think it would be productive to rehash the prior 
>>>> discussion so I’m going to try to be brief.  
>>>> 
>>>> In the discussion one idea that arose was to support two labels for 
>>>> associated values in a manner similar to parameters.  One would be used 
>>>> during construction and the other during matching.  
>>>> 
>>>> The idea behind this was that when creating a value a case is analagous to 
>>>> a factory method and it would be nice to be able provide labels using the 
>>>> same naming guidelines we use for external argument labels.  For example, 
>>>> if an associated value was an index `at` might be used for clarity at the 
>>>> call site.  Labels like this don’t necessarily make as much sense when 
>>>> destructuring the value.  The idea of the “internal” label of a case was 
>>>> that it would be used when matching and could be elided if the bound name 
>>>> was identical.  In the example, `index` might be used.
>>> 
>>> It’s an interesting idea, but I don’t know of too many cases where I 
>>> wouldn’t want the name for destructuring to serve as an API name somehow.  
>>> A function may use labels to aid understanding, flow,  readability, etc. 
>>> but an enum case is not necessarily a function-like value, nor does this 
>>> proposal want them to be (modulo some internal modeling).
>> 
>> An enum case is *exactly* analogous to a static factory method or property 
>> when it is used to construct values.  It obviously plays a different role in 
>> pattern context.
>> 
>>> 
>>>> 
>>>> When matching, `let` is interspersed between the label and the name 
>>>> binding.
>>> 
>>> Good thing this works then
>>> 
>>> enum Foo {
>>>   case foo(x: Int, y: String, z: Float)
>>> }
>>> 
>>> func bar(_ x : Foo) {
>>>   switch x {
>>>   case let .foo(x: x, y: y, z: z): break
>>>   }
>>> }
>> 
>> I consider this syntax to be an anti-pattern.  It can be unclear where a new 
>> name is bound and where the value of a pre-existing name is matched.
>> 
>>> 
>>> Even better, John mentioned in the rationale that if the labels ever grow 
>>> to be clumsy we can come up with some kind of “ellipses-like” pattern to 
>>> indicate we intend to match all the labelled values as they are so named, 
>>> etc.  
>> 
>> It sounds like this would introduce name bindings without the name being 
>> explicitly declared.  That works fine where there is a standard pattern such 
>> as `oldValue` in a property observer.  I’m not sure I would like it in this 
>> context though.
>> 
>>> Or, and this is the far easier thing that can and should be done today, 
>>> just use a struct.
>> 
>> I generally agree with this advice.
>> 
>>> 
>>>>  Any label is already at a distance from the name it labels.  Instead of 
>>>> providing a label the important thing is that the semantic of the bound 
>>>> variable be clear at the match site.  Much of the time the label actually 
>>>> reduces clarity at a match site by adding verbosity and very often 
>>>> repetition.  If the bound name clearly communicates the purpose of the 
>>>> associated value a label cannot add any additional clarity, it can only 
>>>> reduce clarity.
>>> 
>>> I disagree.  This would make sense in a world where we didn’t allow 
&g

Re: [swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 12:05 PM, Tony Allevato  wrote:
> 
> 
> 
> On Fri, Sep 8, 2017 at 9:44 AM Matthew Johnson  > wrote:
>> On Sep 8, 2017, at 11:32 AM, Tony Allevato > > wrote:
>> 
>> 
>> 
>> On Fri, Sep 8, 2017 at 8:35 AM Matthew Johnson > > wrote:
>>> On Sep 8, 2017, at 9:53 AM, Tony Allevato via swift-evolution 
>>> > wrote:
>>> 
>>> Thanks for bringing this up, Logan! It's something I've been thinking about 
>>> a lot lately after a conversation with some colleagues outside of this 
>>> community. Some of my thoughts:
>>> 
>>> AFAIK, there are two major use cases here: (1) you need the whole 
>>> collection of cases, like in your example, and (2) you just need the number 
>>> of cases. The latter seems to occur somewhat commonly when people want to 
>>> use an enum to define the sections of, say, a UITableView. They just return 
>>> the count from numberOfSections(in:) and then switch over the cases in 
>>> their cell-providing methods.
>>> 
>>> Because of #2, it would be nice to avoid instantiating the collection 
>>> eagerly. (Also because of examples like Jonathan's, where the enum is 
>>> large.) If all the user is ever really doing is iterating over them, 
>>> there's no need to keep the entire collection in memory. This leads us to 
>>> look at Sequence; we could use something like AnySequence to keep the 
>>> current case as our state and a transition function to advance to the next 
>>> one. If a user needs to instantiate the full array from that sequence they 
>>> can do so, but they have to do it explicitly.
>>> 
>>> The catch is that Sequence only provides `underestimatedCount`, rather than 
>>> `count`. Calling the former would be an awkward API (why is it 
>>> underestimated? we know how many cases there are). I suppose we could 
>>> create a concrete wrapper for Sequence (PrecountedSequence?) that provides 
>>> a `count` property to make that cleaner, and then have 
>>> `underestimatedCount` return the same thing if users passed this thing into 
>>> a generic operation constrained over Sequence. (The standard library 
>>> already has support wrappers like EnumeratedSequence, so maybe this is 
>>> appropriate.)
>>> 
>>> Another question that would need to be answered is, how should the cases be 
>>> ordered? Declaration order seems obvious and straightforward, but if you 
>>> have a raw-value enum (say, integers), you could have the declaration order 
>>> and the numeric order differ. Maybe that's not a problem. Tying the 
>>> iteration order to declaration order also means that the behavior of a 
>>> program could change simply by reördering the cases. Maybe that's not a big 
>>> problem either, but it's something to call out.
>>> 
>>> If I were designing this, I'd start with the following approach. First, add 
>>> a new protocol to the standard library:
>>> 
>>> ```
>>> public protocol ValueEnumerable {
>>>   associatedtype AllValuesSequence: Sequence where 
>>> AllValuesSequence.Iterator.Element == Self
>>> 
>>>   static var allValues: AllValuesSequence { get }
>>> }
>>> ```
>>> 
>>> Then, for enums that declare conformance to that protocol, synthesize the 
>>> body of `allValues` to return an appropriate sequence. If we imagine a 
>>> model like AnySequence, then the "state" can be the current case, and the 
>>> transition function can be a switch/case that returns it and advances to 
>>> the next one (finally returning nil).
>>> 
>>> There's an opportunity for optimization that may or may not be worth it: if 
>>> the enum is RawRepresentable with RawValue == Int, AND all the raw values 
>>> are in a contiguous range, AND declaration order is numerical order 
>>> (assuming we kept that constraint), then the synthesized state machine can 
>>> just be a simple integer incrementation and call to `init?(rawValue:)`. 
>>> When all the cases have been generated, that will return nil on its own.
>>> 
>>> So that covers enums without associated values. What about those with 
>>> associated values? I would argue that the "number of cases" isn't something 
>>> that's very useful here—if we consider that enum cases are really factory 
>>> functions for concrete values of the type, then we shouldn't think about 
>>> "what are all the cases of this enum" but "what are all the values of this 
>>> type". (For enums without associated values, those are synonymous.)
>>> 
>>> An enum with associated values can potentially have an infinite number of 
>>> values. Here's one:
>>> 
>>> ```
>>> enum BinaryTree {
>>>   case subtree(left: BinaryTree, right: BinaryTree)
>>>   case leaf
>>>   case empty
>>> }
>>> ```
>>> 
>>> Even without introducing an Element type in the leaf nodes, there are a 
>>> countably infinite number of binary trees. So first 

Re: [swift-evolution] [Proposal] Random Unification

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 2:30 PM, Ben Cohen via swift-evolution 
>  wrote:
> 
> Hi Alejandro,
> 
> I’m really happy to see someone pick this up. We had suggested some kind of 
> random support could be a goal for addition to the standard library in Swift 
> 4 phase 2 but didn’t manage it, so I definitely think a good proposal would 
> be given consideration for Swift 5.
> 
> Regarding the implementation – I would suggest exploring something along the 
> lines of an extension on RandomAccessCollection that adds a property for a 
> random element, rather than a pair of free functions. This would have a 
> number of benefits:
> 
>  - a very common use case is picking a random entry from a collection, which 
> this would do automatically
>  - it gives you a very natural way of expressing a ranged random number i.e. 
> (0..<10).randomElement (not necessarily recommending that name btw, it’s one 
> of various possibilities)
>  - since both kinds of countable ranges are collections, it sidesteps that 
> issue :)
>  - it allows for multiple different integers without the need for casting 
> i.e. in the above, if type context meant the result was a UInt16, that’s what 
> it would be
> 
> The one downside is that you’d have to write (0.. justification for a static property on one of the Integer protocols as 
> shorthand for that.
> 
> The tricky part (in addition to the cross-platform aspect) is ensuring 
> correct distribution across the possible distances. But since this is 
> something that people might easily get wrong, that reinforces the idea of 
> this being something that’s easy to use correctly in the std lib.
> 
> I’d also suggest proposing a shuffle implementation for 
> RandomAccessCollection+MutableCollection at the same time (probably as a 
> separate but linked proposal), since this is also something that is often 
> requested, easy to get wrong, and needs a cross-platform source of random 
> numbers.

How would this design address the relatively common use case of wanting a 
random floating point number in the range `0…1` or `0..<1`?  Floating point 
ranges are not countable.

> 
> Regards,
> Ben
> 
> 
>> On Sep 8, 2017, at 10:34 AM, Alejandro Alonso via swift-evolution 
>> > wrote:
>> 
>> Range support is something that came up, and I think it’s a great idea as 
>> well. My question now is do we support both `CountableRange` and 
>> `CountableClosedRange`?
>> 
>> On Sep 8, 2017, 12:08 PM -0500, Shawn Erickson > >, wrote:
>>> It would be nice to leverage range support instead of a start and end value 
>>> IMHO.
>>> On Fri, Sep 8, 2017 at 9:52 AM Alejandro Alonso via swift-evolution 
>>> > wrote:
>>> Hello swift evolution, I would like to propose a unified approach to 
>>> `random()` in Swift. I have a simple implementation here 
>>> https://gist.github.com/Azoy/5d294148c8b97d20b96ee64f434bb4f5 
>>> . This 
>>> implementation is a simple wrapper over existing random functions so 
>>> existing code bases will not be affected. Also, this approach introduces a 
>>> new random feature for Linux users that give them access to upper bounds, 
>>> as well as a lower bound for both Glibc and Darwin users. This change would 
>>> be implemented within Foundation.
>>> 
>>> I believe this simple change could have a very positive impact on new 
>>> developers learning Swift and experienced developers being able to write 
>>> single random declarations.
>>> 
>>> I’d like to hear about your ideas on this proposal, or any implementation 
>>> changes if need be.
>>> 
>>> - Alejando
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org 
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 2:17 PM, Robert Widmann <devteam.cod...@gmail.com> wrote:
> 
>> 
>> On Sep 4, 2017, at 11:35 AM, Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>>> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan <griotsp...@gmail.com 
>>> <mailto:griotsp...@gmail.com>> wrote:
>>> 
>>> I wasn't arguing for a strictly parallel syntax. I was arguing against 
>>> being able to omit labels. I don't view those as strictly tied together. 
>>> How are they?
>> 
>> Like Xiaodi I don’t think it would be productive to rehash the prior 
>> discussion so I’m going to try to be brief.  
>> 
>> In the discussion one idea that arose was to support two labels for 
>> associated values in a manner similar to parameters.  One would be used 
>> during construction and the other during matching.  
>> 
>> The idea behind this was that when creating a value a case is analagous to a 
>> factory method and it would be nice to be able provide labels using the same 
>> naming guidelines we use for external argument labels.  For example, if an 
>> associated value was an index `at` might be used for clarity at the call 
>> site.  Labels like this don’t necessarily make as much sense when 
>> destructuring the value.  The idea of the “internal” label of a case was 
>> that it would be used when matching and could be elided if the bound name 
>> was identical.  In the example, `index` might be used.
> 
> It’s an interesting idea, but I don’t know of too many cases where I wouldn’t 
> want the name for destructuring to serve as an API name somehow.  A function 
> may use labels to aid understanding, flow,  readability, etc. but an enum 
> case is not necessarily a function-like value, nor does this proposal want 
> them to be (modulo some internal modeling).

An enum case is *exactly* analogous to a static factory method or property when 
it is used to construct values.  It obviously plays a different role in pattern 
context.

> 
>> 
>> When matching, `let` is interspersed between the label and the name binding.
> 
> Good thing this works then
> 
> enum Foo {
>   case foo(x: Int, y: String, z: Float)
> }
> 
> func bar(_ x : Foo) {
>   switch x {
>   case let .foo(x: x, y: y, z: z): break
>   }
> }

I consider this syntax to be an anti-pattern.  It can be unclear where a new 
name is bound and where the value of a pre-existing name is matched.

> 
> Even better, John mentioned in the rationale that if the labels ever grow to 
> be clumsy we can come up with some kind of “ellipses-like” pattern to 
> indicate we intend to match all the labelled values as they are so named, 
> etc.  

It sounds like this would introduce name bindings without the name being 
explicitly declared.  That works fine where there is a standard pattern such as 
`oldValue` in a property observer.  I’m not sure I would like it in this 
context though.

> Or, and this is the far easier thing that can and should be done today, just 
> use a struct.

I generally agree with this advice.

> 
>>  Any label is already at a distance from the name it labels.  Instead of 
>> providing a label the important thing is that the semantic of the bound 
>> variable be clear at the match site.  Much of the time the label actually 
>> reduces clarity at a match site by adding verbosity and very often 
>> repetition.  If the bound name clearly communicates the purpose of the 
>> associated value a label cannot add any additional clarity, it can only 
>> reduce clarity.
> 
> I disagree.  This would make sense in a world where we didn’t allow 
> overloading.  But for the purpose of disambiguation, this kind of logic 
> breaks down.  Say we have this construction
> 
> func bar(_ x : Foo) {
>   switch x {
>   case let .foo(x, y, z): break
>   case let .foo(x, y, z, w): break
>   }
> }
> 
> Without the definition of the original enum, could you tell me what each of 
> these cases were for, and why they were named so similarly?  Eliding the 
> label does not enable clarity, it saves keystrokes and enables ambiguous 
> patterns.

As stated above, I strongly dislike the syntax that distributes the `let` as I 
find *that* to be unclear.  Let’s rewrite that example:

func bar(_ x : Foo) {
  switch x {
  case .foo(let x, let y, let z): break
  case .foo(let x, let y, let z, let w): break
  }
}

Now I can see exactly where names are being bound.  I know if a label exists it 
matches the name that is bound.  If two distinct cases might be matched I would 
expect a compiler error.  For example, if Foo was defined as follows the above 
sw

Re: [swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 11:32 AM, Tony Allevato  wrote:
> 
> 
> 
> On Fri, Sep 8, 2017 at 8:35 AM Matthew Johnson  > wrote:
>> On Sep 8, 2017, at 9:53 AM, Tony Allevato via swift-evolution 
>> > wrote:
>> 
>> Thanks for bringing this up, Logan! It's something I've been thinking about 
>> a lot lately after a conversation with some colleagues outside of this 
>> community. Some of my thoughts:
>> 
>> AFAIK, there are two major use cases here: (1) you need the whole collection 
>> of cases, like in your example, and (2) you just need the number of cases. 
>> The latter seems to occur somewhat commonly when people want to use an enum 
>> to define the sections of, say, a UITableView. They just return the count 
>> from numberOfSections(in:) and then switch over the cases in their 
>> cell-providing methods.
>> 
>> Because of #2, it would be nice to avoid instantiating the collection 
>> eagerly. (Also because of examples like Jonathan's, where the enum is 
>> large.) If all the user is ever really doing is iterating over them, there's 
>> no need to keep the entire collection in memory. This leads us to look at 
>> Sequence; we could use something like AnySequence to keep the current case 
>> as our state and a transition function to advance to the next one. If a user 
>> needs to instantiate the full array from that sequence they can do so, but 
>> they have to do it explicitly.
>> 
>> The catch is that Sequence only provides `underestimatedCount`, rather than 
>> `count`. Calling the former would be an awkward API (why is it 
>> underestimated? we know how many cases there are). I suppose we could create 
>> a concrete wrapper for Sequence (PrecountedSequence?) that provides a 
>> `count` property to make that cleaner, and then have `underestimatedCount` 
>> return the same thing if users passed this thing into a generic operation 
>> constrained over Sequence. (The standard library already has support 
>> wrappers like EnumeratedSequence, so maybe this is appropriate.)
>> 
>> Another question that would need to be answered is, how should the cases be 
>> ordered? Declaration order seems obvious and straightforward, but if you 
>> have a raw-value enum (say, integers), you could have the declaration order 
>> and the numeric order differ. Maybe that's not a problem. Tying the 
>> iteration order to declaration order also means that the behavior of a 
>> program could change simply by reördering the cases. Maybe that's not a big 
>> problem either, but it's something to call out.
>> 
>> If I were designing this, I'd start with the following approach. First, add 
>> a new protocol to the standard library:
>> 
>> ```
>> public protocol ValueEnumerable {
>>   associatedtype AllValuesSequence: Sequence where 
>> AllValuesSequence.Iterator.Element == Self
>> 
>>   static var allValues: AllValuesSequence { get }
>> }
>> ```
>> 
>> Then, for enums that declare conformance to that protocol, synthesize the 
>> body of `allValues` to return an appropriate sequence. If we imagine a model 
>> like AnySequence, then the "state" can be the current case, and the 
>> transition function can be a switch/case that returns it and advances to the 
>> next one (finally returning nil).
>> 
>> There's an opportunity for optimization that may or may not be worth it: if 
>> the enum is RawRepresentable with RawValue == Int, AND all the raw values 
>> are in a contiguous range, AND declaration order is numerical order 
>> (assuming we kept that constraint), then the synthesized state machine can 
>> just be a simple integer incrementation and call to `init?(rawValue:)`. When 
>> all the cases have been generated, that will return nil on its own.
>> 
>> So that covers enums without associated values. What about those with 
>> associated values? I would argue that the "number of cases" isn't something 
>> that's very useful here—if we consider that enum cases are really factory 
>> functions for concrete values of the type, then we shouldn't think about 
>> "what are all the cases of this enum" but "what are all the values of this 
>> type". (For enums without associated values, those are synonymous.)
>> 
>> An enum with associated values can potentially have an infinite number of 
>> values. Here's one:
>> 
>> ```
>> enum BinaryTree {
>>   case subtree(left: BinaryTree, right: BinaryTree)
>>   case leaf
>>   case empty
>> }
>> ```
>> 
>> Even without introducing an Element type in the leaf nodes, there are a 
>> countably infinite number of binary trees. So first off, we wouldn't be able 
>> to generate a meaningful `count` property for that. Since they're countably 
>> infinite, we *could* theoretically lazily generate a sequence of them! It 
>> would be a true statement to say "an enum with associated values can have 
>> all of its values enumerated if all of its associated values are also 
>> 

Re: [swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 9:53 AM, Tony Allevato via swift-evolution 
>  wrote:
> 
> Thanks for bringing this up, Logan! It's something I've been thinking about a 
> lot lately after a conversation with some colleagues outside of this 
> community. Some of my thoughts:
> 
> AFAIK, there are two major use cases here: (1) you need the whole collection 
> of cases, like in your example, and (2) you just need the number of cases. 
> The latter seems to occur somewhat commonly when people want to use an enum 
> to define the sections of, say, a UITableView. They just return the count 
> from numberOfSections(in:) and then switch over the cases in their 
> cell-providing methods.
> 
> Because of #2, it would be nice to avoid instantiating the collection 
> eagerly. (Also because of examples like Jonathan's, where the enum is large.) 
> If all the user is ever really doing is iterating over them, there's no need 
> to keep the entire collection in memory. This leads us to look at Sequence; 
> we could use something like AnySequence to keep the current case as our state 
> and a transition function to advance to the next one. If a user needs to 
> instantiate the full array from that sequence they can do so, but they have 
> to do it explicitly.
> 
> The catch is that Sequence only provides `underestimatedCount`, rather than 
> `count`. Calling the former would be an awkward API (why is it 
> underestimated? we know how many cases there are). I suppose we could create 
> a concrete wrapper for Sequence (PrecountedSequence?) that provides a `count` 
> property to make that cleaner, and then have `underestimatedCount` return the 
> same thing if users passed this thing into a generic operation constrained 
> over Sequence. (The standard library already has support wrappers like 
> EnumeratedSequence, so maybe this is appropriate.)
> 
> Another question that would need to be answered is, how should the cases be 
> ordered? Declaration order seems obvious and straightforward, but if you have 
> a raw-value enum (say, integers), you could have the declaration order and 
> the numeric order differ. Maybe that's not a problem. Tying the iteration 
> order to declaration order also means that the behavior of a program could 
> change simply by reördering the cases. Maybe that's not a big problem either, 
> but it's something to call out.
> 
> If I were designing this, I'd start with the following approach. First, add a 
> new protocol to the standard library:
> 
> ```
> public protocol ValueEnumerable {
>   associatedtype AllValuesSequence: Sequence where 
> AllValuesSequence.Iterator.Element == Self
> 
>   static var allValues: AllValuesSequence { get }
> }
> ```
> 
> Then, for enums that declare conformance to that protocol, synthesize the 
> body of `allValues` to return an appropriate sequence. If we imagine a model 
> like AnySequence, then the "state" can be the current case, and the 
> transition function can be a switch/case that returns it and advances to the 
> next one (finally returning nil).
> 
> There's an opportunity for optimization that may or may not be worth it: if 
> the enum is RawRepresentable with RawValue == Int, AND all the raw values are 
> in a contiguous range, AND declaration order is numerical order (assuming we 
> kept that constraint), then the synthesized state machine can just be a 
> simple integer incrementation and call to `init?(rawValue:)`. When all the 
> cases have been generated, that will return nil on its own.
> 
> So that covers enums without associated values. What about those with 
> associated values? I would argue that the "number of cases" isn't something 
> that's very useful here—if we consider that enum cases are really factory 
> functions for concrete values of the type, then we shouldn't think about 
> "what are all the cases of this enum" but "what are all the values of this 
> type". (For enums without associated values, those are synonymous.)
> 
> An enum with associated values can potentially have an infinite number of 
> values. Here's one:
> 
> ```
> enum BinaryTree {
>   case subtree(left: BinaryTree, right: BinaryTree)
>   case leaf
>   case empty
> }
> ```
> 
> Even without introducing an Element type in the leaf nodes, there are a 
> countably infinite number of binary trees. So first off, we wouldn't be able 
> to generate a meaningful `count` property for that. Since they're countably 
> infinite, we *could* theoretically lazily generate a sequence of them! It 
> would be a true statement to say "an enum with associated values can have all 
> of its values enumerated if all of its associated values are also 
> ValueEnumerable". But I don't think that's something we could have the 
> compiler synthesize generally: the logic to tie the sequences together would 
> be quite complex in the absence of a construct like coroutines/yield, and 
> what's worse, the compiler would have to do some deeper analysis to avoid 
> infinite recursion. 

Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-07 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Sep 7, 2017, at 7:45 AM, Tony Allevato <tony.allev...@gmail.com> wrote:
> 
> Right, let's make sure we're talking about the right thing here. Gwendal, 
> your issue isn't with synthesis in the form of Codable or the new additions 
> to Equatable/Hashable which are opt-in-by-conformance, it's with the specific 
> case of raw value enums or enums without associated values where the 
> synthesis is implicit with no way to opt-out. That's a big difference.
> 
> I can definitely see the latter being an issue if it were more widespread, 
> and I'd be supportive of those enums being required to declare their 
> conformance for consistency (though it would be source breaking).

Ahh, thanks for clearing that up Tony.  I missed this.  I agree that this could 
be problematic in some cases (as Gwendal found) and should be fixed.  Now that 
we have a well established model for synthesis we should follow it consistently.

> 
> However, I still haven't seen a real issue that has come up because of the 
> distinction being drawn here between default implementations vs. 
> implementations that can access other parts of the concrete type. It sounds 
> like this discussion is trying to protect against a hypothetical problem that 
> hasn't happened yet and may not happen; it would be helpful to show some 
> motivating real-world cases where this is indeed a severe problem.
>> On Thu, Sep 7, 2017 at 5:37 AM Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org> wrote:
>> 
>> 
>> Sent from my iPad
>> 
>>> On Sep 7, 2017, at 7:07 AM, Gwendal Roué via swift-evolution 
>>> <swift-evolution@swift.org> wrote:
>>> 
>>> Hello,
>>> 
>>> I'm interested in this debate because I've been bitten by automatic 
>>> synthesis recently.
>>> 
>>> I'm reading your discussion, but I don't have a strong opinion. I only have 
>>> an anecdote: implicit, automatic, and unavoidable code synthesis code can 
>>> make it difficult to write some DSLs (aka Domain-Specific Languages).
>>> 
>>> I did stumble against undesired Equatable synthesis while developping a 
>>> library[1] that generates SQL snippets. In this library, the `==` operator 
>>> does not return a Bool: it returns an SQL expression:
>>> 
>>> // SELECT * FROM players WHERE bestScore = 1000
>>> Player.filter(bestScore == 1000)
>>> 
>>> Since the library is free to define == as an operator that returns an SQL 
>>> expression, this works quite well. Even when both operands have the same 
>>> type:
>>> 
>>> // SELECT * FROM players WHERE lastScore = bestScore
>>> Player.filter(lastScore == bestScore)
>>> 
>>> However, as soon as the type is (also) Equatable, an ambiguity occurs, and 
>>> the DSL is basically broken:
>>> 
>>> Player.filter(lastScore == bestScore) // which == please?
>>> 
>>> In this case, the == from synthesized Equatable conformance is not welcome 
>>> at all. It prevents the library from controlling the return type of the == 
>>> operator. Equatable conformance is unavoidable for enums based on String or 
>>> generally any raw value type that adopts Equatable. The consequence is that 
>>> my library can't allow its users to define an enum of table columns.
>>> 
>>> This is not a deal breaker. Everybody can live with this little caveat, and 
>>> I guess I'm the only one who wishes things had been more *consistent*. But 
>>> still: this story helps realizing that code synthesis can bite in plenty of 
>>> unexpected ways.
>> 
>> I don't understand what this has to do with synthesized Equatable.  Wouldn't 
>> manually implemented Equatable have the same impact?  The design of a DSL 
>> should be able to accommodate conformance to basic protocols without 
>> ambiguity.
>> 
>> We generally want as many types to be Equatable and Hashable as possible.  
>> Synthesized conformance means more types will have these conformance and 
>> that's a good thing in all cases (so long as the implementation is correct). 
>>  
>> 
>>> 
>>> Thanks for reading,
>>> Gwendal Roué
>>> [1] http://github.com/groue/GRDB.swift
>>> 
>>>>> Le 7 sept. 2017 à 12:20, Haravikk via swift-evolution 
>>>>> <swift-evolution@swift.org> a écrit :
>>>>> 
>>>>> 
>>>>>> On 7 Sep 2017, at 00:11, Brent Royal-Gordon <br...@architechies.com> 
>>>>>> wrote:
>>>>>>

Re: [swift-evolution] [Proposal] Explicit Synthetic Behaviour

2017-09-07 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Sep 7, 2017, at 7:07 AM, Gwendal Roué via swift-evolution 
>  wrote:
> 
> Hello,
> 
> I'm interested in this debate because I've been bitten by automatic synthesis 
> recently.
> 
> I'm reading your discussion, but I don't have a strong opinion. I only have 
> an anecdote: implicit, automatic, and unavoidable code synthesis code can 
> make it difficult to write some DSLs (aka Domain-Specific Languages).
> 
> I did stumble against undesired Equatable synthesis while developping a 
> library[1] that generates SQL snippets. In this library, the `==` operator 
> does not return a Bool: it returns an SQL expression:
> 
>   // SELECT * FROM players WHERE bestScore = 1000
>   Player.filter(bestScore == 1000)
> 
> Since the library is free to define == as an operator that returns an SQL 
> expression, this works quite well. Even when both operands have the same type:
> 
>   // SELECT * FROM players WHERE lastScore = bestScore
>   Player.filter(lastScore == bestScore)
> 
> However, as soon as the type is (also) Equatable, an ambiguity occurs, and 
> the DSL is basically broken:
> 
>   Player.filter(lastScore == bestScore) // which == please?
> 
> In this case, the == from synthesized Equatable conformance is not welcome at 
> all. It prevents the library from controlling the return type of the == 
> operator. Equatable conformance is unavoidable for enums based on String or 
> generally any raw value type that adopts Equatable. The consequence is that 
> my library can't allow its users to define an enum of table columns.
> 
> This is not a deal breaker. Everybody can live with this little caveat, and I 
> guess I'm the only one who wishes things had been more *consistent*. But 
> still: this story helps realizing that code synthesis can bite in plenty of 
> unexpected ways.

I don't understand what this has to do with synthesized Equatable.  Wouldn't 
manually implemented Equatable have the same impact?  The design of a DSL 
should be able to accommodate conformance to basic protocols without ambiguity.

We generally want as many types to be Equatable and Hashable as possible.  
Synthesized conformance means more types will have these conformance and that's 
a good thing in all cases (so long as the implementation is correct).  

> 
> Thanks for reading,
> Gwendal Roué
> [1] http://github.com/groue/GRDB.swift
> 
>>> Le 7 sept. 2017 à 12:20, Haravikk via swift-evolution 
>>>  a écrit :
>>> 
>>> 
 On 7 Sep 2017, at 00:11, Brent Royal-Gordon  wrote:
 
 On Sep 5, 2017, at 1:02 PM, Haravikk via swift-evolution 
  wrote:
 
 This proposal idea is essentially for a new attribute @synthetic (name is 
 up for debate). This attribute is required for any default implementation 
 that includes reflective type compiler magic, use of the reflection API 
 against `self` or, in future, any native Swift macros within the method 
 (possibly limited to specific features, will depend on the macro language 
 and its capabilities).
>>> 
>>> 
>>> "Use of the reflection API against `self`"? `String(describing:)` and 
>>> `String(reflecting:)` sometimes do that.
>>> 
>>> I see zero justification for having @synthetic cover all of these random 
>>> things, but not ordinary default implementations—they have the same amount 
>>> of dangerous implicitness.
>> 
>> Actually they don't; the problem here is that through reflection you are 
>> accessing and manipulating concrete types. A non-reflective default 
>> implementation only has access to what the protocol itself has defined. The 
>> synthetic alternatives are instead diving into parts of a concrete type that 
>> may have nothing to do with the protocol at all, and must therefore make 
>> assumptions that cannot be guaranteed to be correct, this is what makes them 
>> dangerous.
>> 
 On 6 Sep 2017, at 23:43, Nevin Brackett-Rozinsky 
  wrote:
> On Wed, Sep 6, 2017 at 5:42 PM, Haravikk via swift-evolution 
>  wrote:
> the issue I'm trying to raise is that when those, and similar features, 
> are used in synthesised behaviour (default implementations based upon the 
> concrete type), that these behaviours should be opted into explicitly, 
> otherwise they open up potential for all kinds of bugs, even when the 
> assumptions being made about the concrete type are simple such as in the 
> case for Equatable/Hashable. There's just too much potential for this 
> kind of reflective protocol implementation to overreach; to me it feels 
> very much like going into a restaurant and the waiter coming across and 
> force-feeding me something I don't want instead of taking my order.
>>> 
>>> I might suggest that instead it is like you have gone into a pizza shop and 
>>> said, “I’d like a large 

Re: [swift-evolution] Enums and Source Compatibility

2017-09-06 Thread Matthew Johnson via swift-evolution
Hi Jordan,

The proposal looks very reasonable to me.

I don’t have too strong an opinion on this topic, but it occurred to me that 
your discussion of `future` left out one possible design approach.  We could 
restrict code in the `future` clause to be `break` or `fatalError()`.  One of 
these is probably what most people would do any way and neither really requires 
testing.  As you noted, it will be possible to have untestable code in a 
`default` clause which is probably what people asking for `future` will have in 
the relevant switch statements.  

Supporting `future` does seem like a nice way to allow libraries to add cases 
without a breaking change while allowing users to opt-in to a breaking change 
when that happens.  It’s a nice compromise that doesn’t appear to harm anyone.  

The main argument against it is: what are the use cases?  I haven’t thought 
enough about it to answer that question.  I would challenge people asking for 
`future` to try to provide some concrete examples, probably referencing enums 
in Apple frameworks.  Maybe if sufficient motivation can be demonstrated we 
should reconsider the more limited form of `future` that doesn’t involve 
untestable code.  On the other hand, `future` is something that can always be 
added later.

As I said, I don’t have a strong opinion about this either way at the moment.

Matthew

> On Sep 5, 2017, at 7:19 PM, Jordan Rose  wrote:
> 
> I've taken everyone's feedback into consideration and written this up as a 
> proposal: 
> https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/-non-exhaustive-enums.md
>  
> .
>  The next step is working on an implementation, but if people have further 
> pre-review comments I'd be happy to hear them.
> 
> Jordan
> 
> 
>> On Aug 8, 2017, at 15:27, Jordan Rose > > wrote:
>> 
>> Hi, everyone. Now that Swift 5 is starting up, I'd like to circle back to an 
>> issue that's been around for a while: the source compatibility of enums. 
>> Today, it's an error to switch over an enum without handling all the cases, 
>> but this breaks down in a number of ways:
>> 
>> - A C enum may have "private cases" that aren't defined inside the original 
>> enum declaration, and there's no way to detect these in a switch without 
>> dropping down to the rawValue.
>> - For the same reason, the compiler-synthesized 'init(rawValue:)' on an 
>> imported enum never produces 'nil', because who knows how anyone's using C 
>> enums anyway?
>> - Adding a new case to a Swift enum in a library breaks any client code that 
>> was trying to switch over it.
>> 
>> (This list might sound familiar, and that's because it's from a message of 
>> mine on a thread started by Matthew Johnson back in February called "[Pitch] 
>> consistent public access modifiers". Most of the rest of this email is going 
>> to go the same way, because we still need to make progress here.)
>> 
>> At the same time, we really like our exhaustive switches, especially over 
>> enums we define ourselves. And there's a performance side to this whole 
>> thing too; if all cases of an enum are known, it can be passed around much 
>> more efficiently than if it might suddenly grow a new case containing a 
>> struct with 5000 Strings in it.
>> 
>> 
>> Behavior
>> 
>> I think there's certain behavior that is probably not terribly controversial:
>> 
>> - When enums are imported from Apple frameworks, they should always require 
>> a default case, except for a few exceptions like NSRectEdge. (It's Apple's 
>> job to handle this and get it right, but if we get it wrong with an imported 
>> enum there's still the workaround of dropping down to the raw value.)
>> - When I define Swift enums in the current framework, there's obviously no 
>> compatibility issues; we should allow exhaustive switches.
>> 
>> Everything else falls somewhere in the middle, both for enums defined in 
>> Objective-C:
>> 
>> - If I define an Objective-C enum in the current framework, should it allow 
>> exhaustive switching, because there are no compatibility issues, or not, 
>> because there could still be private cases defined in a .m file?
>> - If there's an Objective-C enum in another framework (that I built locally 
>> with Xcode, Carthage, CocoaPods, SwiftPM, etc.), should it allow exhaustive 
>> switching, because there are no binary compatibility issues, or not, because 
>> there may be source compatibility issues? We'd really like adding a new enum 
>> case to not be a breaking change even at the source level.
>> - If there's an Objective-C enum coming in through a bridging header, should 
>> it allow exhaustive switching, because I might have defined it myself, or 
>> not, because it might be non-modular content I've used the bridging header 
>> to import?
>> 
>> And in Swift:

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-05 Thread Matthew Johnson via swift-evolution

> On Sep 5, 2017, at 3:07 AM, gs. via swift-evolution 
>  wrote:
> 
> 
> This becomes false in exactly the situation that you described where there 
> are two projections with similar structure, no? Labels would remove ambiguity 
> here. 
> TJ 

That depends on what names are bound.  If the bound names clearly indicate 
which projection is matched that is not the case.  Further, the projections 
themselves would probable have a different base name which was used in the 
pattern.

> 
>> On Sep 4, 2017, at 19:35, Matthew Johnson  wrote:
>> 
>> If the bound name clearly communicates the purpose of the associated value a 
>> label cannot add any additional clarity, it can only reduce clarity
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread Matthew Johnson via swift-evolution

> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan  wrote:
> 
> I wasn't arguing for a strictly parallel syntax. I was arguing against being 
> able to omit labels. I don't view those as strictly tied together. How are 
> they?

Like Xiaodi I don’t think it would be productive to rehash the prior discussion 
so I’m going to try to be brief.  

In the discussion one idea that arose was to support two labels for associated 
values in a manner similar to parameters.  One would be used during 
construction and the other during matching.  

The idea behind this was that when creating a value a case is analagous to a 
factory method and it would be nice to be able provide labels using the same 
naming guidelines we use for external argument labels.  For example, if an 
associated value was an index `at` might be used for clarity at the call site.  
Labels like this don’t necessarily make as much sense when destructuring the 
value.  The idea of the “internal” label of a case was that it would be used 
when matching and could be elided if the bound name was identical.  In the 
example, `index` might be used.

When matching, `let` is interspersed between the label and the name binding.  
Any label is already at a distance from the name it labels.  Instead of 
providing a label the important thing is that the semantic of the bound 
variable be clear at the match site.  Much of the time the label actually 
reduces clarity at a match site by adding verbosity and very often repetition.  
If the bound name clearly communicates the purpose of the associated value a 
label cannot add any additional clarity, it can only reduce clarity.

The proposal acknowledges most of this by allowing us to elide labels when the 
bound name matches the label.  It doesn’t allow for a distinction between the 
call-site label used when creating a value from the match-site name that allows 
elision.  My recollection of the discussion leads me to believe that is 
unlikely to ever be accepted as an enhancement.  That said, nothing in the 
current design strictly prevents us from considering that in the future if 
experience demonstrates that it would be useful.

> 
> On Mon, Sep 4, 2017 at 12:38 PM, Matthew Johnson  > wrote:
> 
>> On Sep 4, 2017, at 10:52 AM, T.J. Usiyan via swift-evolution 
>> > wrote:
>> 
>> While re-litigating has it's issues, I am for simplifying the rule and 
>> always requiring the labels if they exist. This is similar to the change 
>> around external labels. Yes, it is slightly less convenient, but it removes 
>> a difficult to motivate caveat for beginners.
> 
> I disagree.  Creating a value and destructuring it are two very different 
> operations and I believe it is a mistake to require them to have parallel 
> syntax.  
> 
> Imagine a future enhancement to the language that supports destructuring a 
> struct.  A struct might not have a strictly memberwise initializer.  It might 
> not even be possible to reconstruct initializer arguments for the sake of 
> parallel destructuring syntax.  There might even be more than one projection 
> that is reasonable to use when destructuring the value in a pattern (such as 
> cartesian and polar coordinates).
> 
> FWIW, I made this case in more detail during the discussion and review of 
> this proposal.
> 
>> 
>> On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution 
>> > wrote:
>> The desired behavior was the major topic of controversy during review; I’m 
>> wary of revisiting this topic as we are essentially relitigating the 
>> proposal.
>> 
>> To start off, the premise, if I recall, going into review was that the 
>> author **rejected** the notion that pattern matching should mirror creation. 
>> I happen to agree with you on this point, but it was not the prevailing 
>> argument. Fortunately, we do not need to settle this to arrive at some 
>> clarity for the issues at hand.
>> 
>> From a practical standpoint, a requirement for labels in all cases would be 
>> much more source-breaking, whereas the proposal as it stands would allow 
>> currently omitted labels to continue being valid. Moreover, and I think this 
>> is a worthy consideration, one argument for permitting the omission of 
>> labels during pattern matching is to encourage API designers to use labels 
>> to clarify initialization without forcing its use by API consumers during 
>> every pattern matching operation.
>> 
>> In any case, the conclusion reached is precedented in the world of functions:
>> 
>> func g(a: Int, b: Int) { ... }
>> let f = g
>> f(1, 2)
>> 
>> On Sun, Sep 3, 2017 at 15:13 Robert Widmann via swift-evolution 
>> > wrote:
>> Hello Swift Evolution,
>> 
>> I took up the cause of implementing SE-0155 
>> 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread Matthew Johnson via swift-evolution

> On Sep 4, 2017, at 10:52 AM, T.J. Usiyan via swift-evolution 
>  wrote:
> 
> While re-litigating has it's issues, I am for simplifying the rule and always 
> requiring the labels if they exist. This is similar to the change around 
> external labels. Yes, it is slightly less convenient, but it removes a 
> difficult to motivate caveat for beginners.

I disagree.  Creating a value and destructuring it are two very different 
operations and I believe it is a mistake to require them to have parallel 
syntax.  

Imagine a future enhancement to the language that supports destructuring a 
struct.  A struct might not have a strictly memberwise initializer.  It might 
not even be possible to reconstruct initializer arguments for the sake of 
parallel destructuring syntax.  There might even be more than one projection 
that is reasonable to use when destructuring the value in a pattern (such as 
cartesian and polar coordinates).

FWIW, I made this case in more detail during the discussion and review of this 
proposal.

> 
> On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution 
> > wrote:
> The desired behavior was the major topic of controversy during review; I’m 
> wary of revisiting this topic as we are essentially relitigating the proposal.
> 
> To start off, the premise, if I recall, going into review was that the author 
> **rejected** the notion that pattern matching should mirror creation. I 
> happen to agree with you on this point, but it was not the prevailing 
> argument. Fortunately, we do not need to settle this to arrive at some 
> clarity for the issues at hand.
> 
> From a practical standpoint, a requirement for labels in all cases would be 
> much more source-breaking, whereas the proposal as it stands would allow 
> currently omitted labels to continue being valid. Moreover, and I think this 
> is a worthy consideration, one argument for permitting the omission of labels 
> during pattern matching is to encourage API designers to use labels to 
> clarify initialization without forcing its use by API consumers during every 
> pattern matching operation.
> 
> In any case, the conclusion reached is precedented in the world of functions:
> 
> func g(a: Int, b: Int) { ... }
> let f = g
> f(1, 2)
> 
> On Sun, Sep 3, 2017 at 15:13 Robert Widmann via swift-evolution 
> > wrote:
> Hello Swift Evolution,
> 
> I took up the cause of implementing SE-0155 
> ,
>  and am most of the way through the larger points of the proposal.  One thing 
> struck me when I got to the part about normalizing the behavior of pattern 
> matching 
> .
>   The Core Team indicated in their rationale 
> 
>  that the proposal’s suggestion that a variable binding sub in for a label 
> was a little much as in this example:
> 
> enum Foo {
>   case foo(x: Int, y: Int)
> }
> if case let .foo(x: x, y: y) {} // Fine!  Labels match and are in order
> if case let .foo(x, y: y) {} // Bad!  Missing label 'x'
> if case let .foo(x, y) {} // Fine?  Missing labels, but variable names match 
> labels
> 
> They instead suggested the following behavior:
> 
> enum Foo {
>   case foo(x: Int, y: Int)
> }
> if case let .foo(x: x, y: y) {} // Fine!  Labels match and are in order
> if case let .foo(x, y: y) {} // Bad!  Missing label 'x'
> if case let .foo(x, y) {} // Fine?  Missing labels, and full name of case is 
> unambiguous
> 
> Which, for example, would reject this:
> 
> enum Foo {
>   case foo(x: Int, y: Int) // Note: foo(x:y:)
>   case foo(x: Int, z: Int) // Note: foo(x:z:)
> }
> if case let .foo(x, y) {} // Bad!  Are we matching foo(x:y:) or foo(x:z:)?
> 
> With this reasoning:
> 
>>  - While an associated-value label can indeed contribute to the readability 
>> of the pattern, the programmer can also choose a meaningful name to bind to 
>> the associated value.  This binding name can convey at least as much 
>> information as a label would.
>> 
>>   - The risk of mis-labelling an associated value grows as the number of 
>> associated values grows.  However, very few cases carry a large number of 
>> associated values.  As the amount of information which the case should carry 
>> grows, it becomes more and more interesting to encapsulate that information 
>> in its own struct — among other reasons, to avoid the need to revise every 
>> matching case-pattern in the program.  Furthermore, when a case does carry a 
>> significant number of associated values, there is often a positional 
>> conventional between them that lowers the risk of re-ordering: for example, 
>> the 

Re: [swift-evolution] Constrained Protocol Aliases

2017-08-21 Thread Matthew Johnson via swift-evolution

> On Aug 21, 2017, at 10:31 AM, Adrian Zubarev 
>  wrote:
> 
> 
> Hi Matthew thank you for remembering us about that draft. I’ll re-read it 
> soon. At the a quick glance I noticed the extent use of the `where` clause. 
> Wouldn’t make sense to simplify the main proposal and just focus on the 
> `where` clause for typealises only? It’s already a complex feature on its 
> own. Permitting the `where` clause in different places can sill be added 
> later in the future.

At first glance, it looks to me like the typealias would need to refer to a 
generalized existential anyway and if we can do that through a typealias we 
should probably be able to do it directly as well.  That said, if it simplifies 
the implementation in some way it might make sense as a first step.  Whether or 
not that would be the case is something I can’t speak to with any confidence.

> 
> Am 21. August 2017 um 15:10:34, Matthew Johnson (matt...@anandabits.com 
> ) schrieb:
> 
>> If anyone is thinking about spending time on this topic I recommend 
>> beginning by reviewing the prior work that was done by Austin Zheng.  He has 
>> a proposal draft for enhanced existential that is very thorough.  Even if 
>> you're not planning to propose everything that's included in his draft it 
>> would be a good idea to be familiar with it.  Here's the link: 
>> https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/-enhanced-existentials.md
>>  
>> .
>> 
>> Sent from my iPad
>> 
>> On Aug 21, 2017, at 6:36 AM, Adrian Zubarev via swift-evolution 
>> > wrote:
>> 
>>> It’s part of Generalized Existentials, but does not make it complete. I 
>>> think it would be worth adding more and more functionality to existentials 
>>> every year. We started first with reshaping the syntax. This year we added 
>>> support for classes. I think next year would be good to have where clause 
>>> support for typealiases.
>>> 
>>> I understand the complexity of that particular feature, and it’s a no-go 
>>> for me to help on the implementation, but I’m willing to drive the 
>>> discussion and the proposal forward with other co-authors. :)
>>> 
>>> Hasn’t it been said that the implementation must be at least a 
>>> *proof-of-concept* if the complexity is very high?
>>> 
>>> And my second question is: Wouldn’t the existence of this feature reshape 
>>> some parts of the standard library, isn’t that affecting some major goals 
>>> of Swift 5?
>>> 
>>> It would be nice if someone from the core team can clarify if the where 
>>> clause is out of scope for Swift 5 or not.
>>> 
>>> 
>>> 
>>> 
>>> Am 21. August 2017 um 12:51:48, David Hart (da...@hartbit.com 
>>> ) schrieb:
>>> 
 
> On 21 Aug 2017, at 11:41, Adrian Zubarev  > wrote:
> 
> Yes, `where` clause is welcome to typealises (including generic ones) and 
> existentials in general. I would love to help on such proposal. I think 
> David Hart is also interested in this one. (cc)
 
 Yes, this basically seems like Generalized Existentials to me and is 
 mentioned in the Generics Manifesto 
 . 
 It’s a feature I hold very dear but:
 
 It’s a very difficult feature to implement and I think Doug Gregor is the 
 only/best person to do it
 I think its pretty much out of scope for Swift 5 (it’s not required for 
 ABI Stability)
 
 As a result, I’d be very surprised if this topic got any discussion or 
 implementation time during the Swift 5 timeframe.
> Am 21. August 2017 um 11:38:14, Gor Gyolchanyan via swift-evolution 
> (swift-evolution@swift.org ) schrieb:
> 
>> Hello, Swift community!
>> 
>> I'd like to start a discussion about a possibility of constrained 
>> protocol aliases. The declaration would look like this:
>> 
>> typealias BinaryProtocol = RandomAccessCollection & MutablCollection & 
>> RangeReplaceableCollection where Binary.Index == Int, Binary.Element == 
>> Bool
>> 
>> The syntax and semantics of this declaration are exactly the same as an 
>> analogous associatedtype declaration inside a protocol.
>> In the example above, the type BinaryProtocol represents a logical array 
>> of bits and is a generic-only protocol that is usable in any context 
>> where an integer-indexed mutable range-replaceable random-access 
>> collection is expected.
>> Now, it can be used in a very concise and elegant way:
>> 
>> public protocol BinaryInitializable {
>> init(binary: Binary) where Binary: 

Re: [swift-evolution] Constrained Protocol Aliases

2017-08-21 Thread Matthew Johnson via swift-evolution
If anyone is thinking about spending time on this topic I recommend beginning 
by reviewing the prior work that was done by Austin Zheng.  He has a proposal 
draft for enhanced existential that is very thorough.  Even if you're not 
planning to propose everything that's included in his draft it would be a good 
idea to be familiar with it.  Here's the link: 
https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/-enhanced-existentials.md.

Sent from my iPad

> On Aug 21, 2017, at 6:36 AM, Adrian Zubarev via swift-evolution 
>  wrote:
> 
> It’s part of Generalized Existentials, but does not make it complete. I think 
> it would be worth adding more and more functionality to existentials every 
> year. We started first with reshaping the syntax. This year we added support 
> for classes. I think next year would be good to have where clause support for 
> typealiases.
> 
> I understand the complexity of that particular feature, and it’s a no-go for 
> me to help on the implementation, but I’m willing to drive the discussion and 
> the proposal forward with other co-authors. :)
> 
> Hasn’t it been said that the implementation must be at least a 
> *proof-of-concept* if the complexity is very high?
> 
> And my second question is: Wouldn’t the existence of this feature reshape 
> some parts of the standard library, isn’t that affecting some major goals of 
> Swift 5?
> 
> It would be nice if someone from the core team can clarify if the where 
> clause is out of scope for Swift 5 or not.
> 
> 
> 
> 
> Am 21. August 2017 um 12:51:48, David Hart (da...@hartbit.com) schrieb:
> 
>> 
>>> On 21 Aug 2017, at 11:41, Adrian Zubarev  
>>> wrote:
>>> 
>>> Yes, `where` clause is welcome to typealises (including generic ones) and 
>>> existentials in general. I would love to help on such proposal. I think 
>>> David Hart is also interested in this one. (cc)
>> 
>> Yes, this basically seems like Generalized Existentials to me and is 
>> mentioned in the Generics Manifesto. It’s a feature I hold very dear but:
>> 
>> It’s a very difficult feature to implement and I think Doug Gregor is the 
>> only/best person to do it
>> I think its pretty much out of scope for Swift 5 (it’s not required for ABI 
>> Stability)
>> 
>> As a result, I’d be very surprised if this topic got any discussion or 
>> implementation time during the Swift 5 timeframe.
>>> Am 21. August 2017 um 11:38:14, Gor Gyolchanyan via swift-evolution 
>>> (swift-evolution@swift.org) schrieb:
>>> 
 Hello, Swift community!
 
 I'd like to start a discussion about a possibility of constrained protocol 
 aliases. The declaration would look like this:
 
 typealias BinaryProtocol = RandomAccessCollection & MutablCollection & 
 RangeReplaceableCollection where Binary.Index == Int, Binary.Element == 
 Bool
 
 The syntax and semantics of this declaration are exactly the same as an 
 analogous associatedtype declaration inside a protocol.
 In the example above, the type BinaryProtocol represents a logical array 
 of bits and is a generic-only protocol that is usable in any context where 
 an integer-indexed mutable range-replaceable random-access collection is 
 expected.
 Now, it can be used in a very concise and elegant way:
 
 public protocol BinaryInitializable {
 init(binary: Binary) where Binary: BinaryProtocol
 }
 
 which would otherwise look very verbose and inelegant:
 
 public protocol BinaryInitializable {
 init(binary: Binary) where Binary: RandomAccessCollection & 
 MutablCollection & RangeReplaceableCollection, Binary.Index == Int, 
 Binary.Element == Bool
 }
 
 Considering that smaller sets of constraints could be aliased to their own 
 protocol and then composited into more complex aliases, this feature would 
 dramatically improve readability and maintainability of code that uses 
 complex constraints, that currently leads to arcane mess:
 
 struct Mirror {
 /// ...
 init(_ subject: Subject, 
 children: C, displayStyle: Mirror.DisplayStyle? = default, 
 ancestorRepresentation: Mirror.AncestorRepresentation = default)
 /// ...
 }
 
 
 /// A collection that is its own sub-sequence
 typealias RecursivelySliceableCollection = 

Re: [swift-evolution] [Concurrency] async/await + actors

2017-08-19 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Aug 19, 2017, at 9:33 PM, Brent Royal-Gordon  
> wrote:
> 
>> On Aug 19, 2017, at 7:41 AM, Matthew Johnson  wrote:
>> 
>> Regardless of which approach we take, it feels like something that needs to 
>> be implicit for structs and enums where value semantics is trivially 
>> provable by way of transitivity. When that is not the case we could require 
>> an explicit `value` or `nonvalue` annotation (specific keywords subject to 
>> bikeshedding of course).
> 
> There is no such thing as "trivially provable by way of transitivity". This 
> type is comprised of only value types, and yet it has reference semantics:
> 
>   struct EntryRef {
>   private var index: Int
>   
>   var entry: Entry {
>   get { return entries[index] }
>   set { entries[index] = newValue }
>   }
>   }

This type uses global mutable state in its implementation.  This is not hard 
for the compiler to detect and is pretty rare in most code.

> 
> This type is comprised of only reference types, and yet it has value 
> semantics:
> 
>   struct OpaqueToken: Equatable {
>   class Token {}
>   private let token: Token
>   
>   static func == (lhs: OpaqueToken, rhs: OpaqueToken) -> Bool {
>   return lhs.token === rhs.token
>   }
>   }

Yes, of course this is possible.  I believe this type should have to include an 
annotation declaring value semantics and should also need to annotate the 
`token` property with an acknowledgement that value semantics is being 
preserved by the implementation of the type despite this member not having 
value semantics.  The annotation on the property is to prevent bugs that might 
occur because the programmer didn't realize this type does not have value 
semantics.

> 
> I think it's better to have types explicitly declare that they have value 
> semantics if they want to make that promise, and otherwise not have the 
> compiler make any assumptions either way. Safety features should not be 
> *guessing* that your code is safe. If you can somehow *prove* it safe, go 
> ahead—but I don't see how that can work without a lot of manual annotations 
> on bridged code.

I agree with you that *public* types should have to declare that they have 
value semantics.  And I'm not suggesting we attempt to *prove* value semantics 
everywhere. 

I'm suggesting that the proportion of value types in most applications for 
which we can reasonably infer value semantics is pretty large.  If the stored 
properties of a value type all have value semantics and the implementation of 
the type does not use global mutable state it has value semantics.  

Whether we require annotation or not, value semantics will be decided by the 
declaring module.  If we don't infer it we'll end up having to write `value 
struct` and `value enum` a lot.  The design of Swift has been vigorous in 
avoiding keyword soup and I really believe that rule applies here.  The primary 
argument I can think of against inferring value semantics for non-public value 
types in these cases is if proving a type does not use global mutable state in 
its implementation would have too large an impact on build times.

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Concurrency] async/await + actors

2017-08-19 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Aug 19, 2017, at 3:29 PM, Michel Fortin  wrote:
> 
> 
>> Le 19 août 2017 à 11:38, Matthew Johnson  a écrit :
>> 
>> 
>> 
>> Sent from my iPad
>> 
>> On Aug 19, 2017, at 8:16 AM, Michel Fortin via swift-evolution 
>>  wrote:
>> 
> For instance, has Array value semantics? 
 
 By the commonly accepted definition, Array does not provide value 
 semantics.
 
> You might be tempted to say that it does not because it contains class 
> references, but in reality that depends on what you do with those UIViews.
 
 An aspect of the type (“does it have value semantics or not”) should not 
 depend on the clients.  By your definition, every type has value semantics 
 if none of the mutating operations are called :-)
>>> 
>>> No, not mutating operations. Access to mutable memory shared by multiple 
>>> "values" is what breaks value semantics. You can get into this situation 
>>> using pointers, object references, or global variables. It's all the same 
>>> thing in the end: shared memory that can mutate.
>>> 
>>> For demonstration's sake, here's a silly example of how you can give 
>>> Array literally the same semantics as Array:
>>> 
>>> // shared UIView instances in global memory
>>> var instances: [UIView] = []
>>> 
>>> extension Array where Element == Int {
>>> 
>>> // append a new integer to the array pointing to our UIView 
>>> instance
>>> func append(view: UIView) {
>>> self.append(instances.count)
>>> instances.append(newValue)
>>> }
>>> 
>>> // access views pointed to by the integers in the array
>>> subscript(viewAt index: Int) -> UIView {
>>> get {
>>> return instances[self[index]]
>>> }
>>> set {
>>> self[index] = instances.count
>>> instances.append(newValue)
>>> }
>>> }
>>> }
>>> 
>>> And now you need to worry about passing Array to other thread. ;-)
>>> 
>>> It does not really matter whether the array contains pointers or wether it 
>>> contains indices into a global table: in both cases access to the same 
>>> mutable memory is accessible through multiple copies of an array, and this 
>>> is what breaks value semantics.
>>> 
>>> Types cannot enforce value semantics. Its the functions you choose to call 
>>> that matters. This is especially important to realize in a language with 
>>> extensions where you can't restrict what functions gets attached to a type.
>> 
>> This gets deeper into the territory of the conversation Dave A and I had a 
>> while ago.  I think this conflates value semantics with pure functions, 
>> which I think is a mistake.  
>> 
>> I agree that if you assume away reference counting a function that takes 
>> Array but never dereferences the pointers can still be a pure 
>> function.  However, I disagree that Array has value semantics.
>> 
> 
>> The relationship of value semantics to purity is that value semantics can be 
>> defined in terms of the purity of the "salient operations" of the type - 
>> those which represent the meaning of the value represented by the type.  The 
>> purity of these operations is what gives the value independence from copies 
>> in terms of its meaning.  If somebody chooses to add a new impure operation 
>> in an extension of a type with value semantics it does not mean that the 
>> type itself no longer has value semantics.  The operation in the extension 
>> is not "salient".
>> 
>> This still begs the question: what operations are "salient"?  I think 
>> everyone can agree that those used in the definition of equality absolutely 
>> must be included.  If two values don't compare equal they clearly do not 
>> have the same meaning.  Thread safety is also usually implied for practical 
>> reasons as is the case in Chris's manifesto.  These properties are generally 
>> considered necessary for value semantics.
>> 
>> While these conditions are *necessary* for value semantics I do not believe 
>> they are *sufficient* for value semantics.  Independence of the value is 
>> also required.  When a reference type defines equality in terms of object 
>> identity copies of the reference are not truly independent.  
>> 
>> This is especially true in a language like Swift where dereference is 
>> implicit.  I argue that when equality is defined in terms of object identity 
>> copies of the reference are *not* independent.  The meaning of the reference 
>> is inherently tied up with the resource it references.  The resource has to 
>> be considered "salient" for the independence to be a useful property.  On 
>> the other hand, if all you really care about is the identity and not the 
>> resource, ObjectIdentifier is available and 

Re: [swift-evolution] typed throws

2017-08-19 Thread Matthew Johnson via swift-evolution
ng here).
> 
> If the compiler is to support typed errors, then certainly it must check what 
> errors are thrown. I'm just saying it doesn't require the additional human 
> labor of typed error annotations to reap the desired documentation benefit; 
> the compiler need only expose that information.

Sure, on this we can agree.  

However, if there is no way to invoke an algorithm that categorizes errors 
during propagation without an annotation that specifies what that algorithm is. 
 Using initializers and cases to perform categorization and a type annotation 
to drive the machinery seems like a reasonable approach.  

On the other hand, this does make the assumption that an enum with a case per 
category is used for categorization.  Perhaps some other solution that allowed 
for a distinct type (perhaps an existential) per category could be identified 
and may even be more flexible.  I'm not sure what that would look like though.

> 
>>>> Error handling is an afterthought all too often.  The value of making it 
>>>> immediately clear how to match important categories of errors should not 
>>>> be understated.
>>> 
>>> See, this is probably where I'm failing to understand you. Every library 
>>> that has its own Error-conforming types offers an ontology of errors that, 
>>> at least to its authors, make some sort of sense.  At the call site, you 
>>> can `catch` specific categories of errors or `switch` over specific errors. 
>>> Yes, this can become a little annoying if your own classification of errors 
>>> differs from the library authors' classification. However, I fail to see 
>>> how typed errors makes this any better, other than that you'd `catch` only 
>>> one type of error but have to `switch` over cases and then `switch` over 
>>> the underlying error. Only now, you've introduced this issue where, for the 
>>> library authors, FooErrors have to be reclassified into BarErrors, and then 
>>> into BazErrors, and then into BooErrors--to what end? It seems only to 
>>> accomplish the goal of making error handling not an afterthought by causing 
>>> the compiler to make it more of a nuisance.
>> 
>> If the only use of this was to move from throwing independent types to 
>> throwing a single type with a bunch of cases you are right, there wouldn't 
>> be much value.  However, the contract for individual functions in a library 
>> may vary and there are also errors from dependencies of the library that may 
>> also be thrown.  
>> 
>> Let's assume for a moment that the error types of a library are carefully 
>> designed to offer meaningful categorization.  Even then it is still very 
>> useful to know which categories may occur at a given call site.  Yes, this 
>> is only documentation so we'll set it aside and not give it too much weight.
>> 
>> More importantly, if I depend on library X it may depend on library Y as an 
>> implementation detail which is not intended to be part of its API contract.  
>> As a user of X I should not need to be aware that Y even exists.  I 
>> certainly am not going to import it and have access to its error types - I 
>> don't want a direct dependency on Y.  Untyped errors are likely to lead to 
>> errors from Y leaking through the interface of X.  They may be errors which 
>> I would have a meaningful recovery strategy if my code was able to properly 
>> understand them, but it won't because I my code doesn't know anything about 
>> Y.  Yes, these are bugs in X but they are bugs that the language could help 
>> to prevent.
> 
> This is a good point which I hadn't considered. The compiler should warn if 
> the public API of one library leaks non-stdlib third-party errors without 
> re-exporting the third-party library. But again, this doesn't require typed 
> errors.
> 
>> As I have said before, none of this *requires* typed errors, they are just a 
>> natural way to approach the problem.  Any solution that allows for 
>> categorization during propagation that can be matched at call sites would be 
>> acceptable.
>> 
>>> 
>>>> I really believe language support of some kind is warranted and would have 
>>>> an impact on the quality of software.  Maybe types aren't the right 
>>>> solution, but we do need one.
>>>> 
>>>> Deciding what categories are important is obviously subjective, but I do 
>>>> believe that libraries focused on a specific domain can often make 
>>>> reasonable guesses that are pretty close in the majority of use cases.  
>>>> This is especially true for internal libraries where part of the purpose 
&

Re: [swift-evolution] typed throws

2017-08-19 Thread Matthew Johnson via swift-evolution
ay also be 
thrown.  

Let's assume for a moment that the error types of a library are carefully 
designed to offer meaningful categorization.  Even then it is still very useful 
to know which categories may occur at a given call site.  Yes, this is only 
documentation so we'll set it aside and not give it too much weight.

More importantly, if I depend on library X it may depend on library Y as an 
implementation detail which is not intended to be part of its API contract.  As 
a user of X I should not need to be aware that Y even exists.  I certainly am 
not going to import it and have access to its error types - I don't want a 
direct dependency on Y.  Untyped errors are likely to lead to errors from Y 
leaking through the interface of X.  They may be errors which I would have a 
meaningful recovery strategy if my code was able to properly understand them, 
but it won't because I my code doesn't know anything about Y.  Yes, these are 
bugs in X but they are bugs that the language could help to prevent.

As I have said before, none of this *requires* typed errors, they are just a 
natural way to approach the problem.  Any solution that allows for 
categorization during propagation that can be matched at call sites would be 
acceptable.

> 
>> I really believe language support of some kind is warranted and would have 
>> an impact on the quality of software.  Maybe types aren't the right 
>> solution, but we do need one.
>> 
>> Deciding what categories are important is obviously subjective, but I do 
>> believe that libraries focused on a specific domain can often make 
>> reasonable guesses that are pretty close in the majority of use cases.  This 
>> is especially true for internal libraries where part of the purpose of the 
>> library may be to establish conventions for the app that are intended to be 
>> used (almost) everywhere.
>> 
>>>  
>>>> The kind of categorization I want to be able to do requires a custom 
>>>> algorithm.  The specific algorithm is used to categorize errors depends on 
>>>> the dynamic context (i.e. the function that is propagating it).  The way I 
>>>> usually think about this categorization is as a conversion initializer as 
>>>> I showed in the example, but it certainly wouldn't need to be accomplished 
>>>> that way.  The most important thing IMO is the ability to categorize 
>>>> during error propagation and make information about that categorization 
>>>> easy for callers to discover.
>>>> 
>>>> The output of the algorithm could use various mechanisms for 
>>>> categorization - an enum is one mechanism, distinct types conforming to 
>>>> appropriate categorization protocols is another.  Attaching some kind of 
>>>> category value to the original error or propagating the category along 
>>>> with it might also work (although might be rather clunky).
>>>> 
>>>> It is trivial to make the original error immediately available via an 
>>>> `underlyingError` property so I really don't understand the resistance to 
>>>> wrapping errors.  The categorization can easily be ignored at the catch 
>>>> site if desired.  That said, if we figure out some other mechanism for 
>>>> categorizing errors, including placing different error values of the same 
>>>> type into different categories, and matching them based on this 
>>>> categorization I think I would be ok with that.  Using wrapper types is 
>>>> not essential to solving the problem.
>>>> 
>>>> Setting all of this aside, surely you had you had your own reasons for 
>>>> supporting typed errors in the past.  What were those and why do you no 
>>>> longer consider them important?
>>> 
>>> My memory is certainly spotty, but as far as I can recall, I had no 
>>> distinct reasons; it just seemed like a reasonable and "natural" next step 
>>> that other people wanted for which I had no use case of my own in mind. 
>>> Having seen the argumentation that there aren't very many use cases in 
>>> general, I'm warming to the view that it's probably not such a great next 
>>> step.
>>> 
>>> 
>>>>>> On Fri, Aug 18, 2017 at 6:46 PM, Matthew Johnson 
>>>>>> <matt...@anandabits.com> wrote:
>>>>>> 
>>>>>>> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>>>>>>> 
>>>>>>>> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson 
>>>>>>>> <matt...@anandabits.com> wrote:
>>>>>>&g

Re: [swift-evolution] [Concurrency] async/await + actors

2017-08-19 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Aug 19, 2017, at 8:16 AM, Michel Fortin via swift-evolution 
>  wrote:
> 
>>> For instance, has Array value semantics?
>> 
>> By the commonly accepted definition, Array does not provide value 
>> semantics.
>> 
>>> You might be tempted to say that it does not because it contains class 
>>> references, but in reality that depends on what you do with those UIViews.
>> 
>> An aspect of the type (“does it have value semantics or not”) should not 
>> depend on the clients.  By your definition, every type has value semantics 
>> if none of the mutating operations are called :-)
> 
> No, not mutating operations. Access to mutable memory shared by multiple 
> "values" is what breaks value semantics. You can get into this situation 
> using pointers, object references, or global variables. It's all the same 
> thing in the end: shared memory that can mutate.
> 
> For demonstration's sake, here's a silly example of how you can give 
> Array literally the same semantics as Array:
> 
>   // shared UIView instances in global memory
>   var instances: [UIView] = []
> 
>   extension Array where Element == Int {
> 
>   // append a new integer to the array pointing to our UIView 
> instance
>   func append(view: UIView) {
>   self.append(instances.count)
>   instances.append(newValue)
>   }
> 
>   // access views pointed to by the integers in the array
>   subscript(viewAt index: Int) -> UIView {
>   get {
>   return instances[self[index]]
>   }
>   set {
>   self[index] = instances.count
>   instances.append(newValue)
>   }
>   }
>   }
> 
> And now you need to worry about passing Array to other thread. ;-)
> 
> It does not really matter whether the array contains pointers or wether it 
> contains indices into a global table: in both cases access to the same 
> mutable memory is accessible through multiple copies of an array, and this is 
> what breaks value semantics.
> 
> Types cannot enforce value semantics. Its the functions you choose to call 
> that matters. This is especially important to realize in a language with 
> extensions where you can't restrict what functions gets attached to a type.

This gets deeper into the territory of the conversation Dave A and I had a 
while ago.  I think this conflates value semantics with pure functions, which I 
think is a mistake.  

I agree that if you assume away reference counting a function that takes 
Array but never dereferences the pointers can still be a pure function. 
 However, I disagree that Array has value semantics.

The relationship of value semantics to purity is that value semantics can be 
defined in terms of the purity of the "salient operations" of the type - those 
which represent the meaning of the value represented by the type.  The purity 
of these operations is what gives the value independence from copies in terms 
of its meaning.  If somebody chooses to add a new impure operation in an 
extension of a type with value semantics it does not mean that the type itself 
no longer has value semantics.  The operation in the extension is not "salient".

This still begs the question: what operations are "salient"?  I think everyone 
can agree that those used in the definition of equality absolutely must be 
included.  If two values don't compare equal they clearly do not have the same 
meaning.  Thread safety is also usually implied for practical reasons as is the 
case in Chris's manifesto.  These properties are generally considered necessary 
for value semantics.

While these conditions are *necessary* for value semantics I do not believe 
they are *sufficient* for value semantics.  Independence of the value is also 
required.  When a reference type defines equality in terms of object identity 
copies of the reference are not truly independent.  

This is especially true in a language like Swift where dereference is implicit. 
 I argue that when equality is defined in terms of object identity copies of 
the reference are *not* independent.  The meaning of the reference is 
inherently tied up with the resource it references.  The resource has to be 
considered "salient" for the independence to be a useful property.  On the 
other hand, if all you really care about is the identity and not the resource, 
ObjectIdentifier is available and does have value semantics.  There is a very 
good reason this type exists.

I'm happy to see this topic emerging again and looking forward to seeing value 
semantics and pure functions eventually receive language support.  There are a 
lot of subtleties involved.  Working through them and clearly defining what 
they mean in Swift is really important.

> 
> 
>>> If you treat the class 

Re: [swift-evolution] [Concurrency] async/await + actors

2017-08-19 Thread Matthew Johnson via swift-evolution


Sent from my iPad

On Aug 19, 2017, at 12:29 AM, Brent Royal-Gordon via swift-evolution 
 wrote:

>> On Aug 18, 2017, at 12:35 PM, Chris Lattner  wrote:
>> 
>>> (Also, I notice that a fire-and-forget message can be thought of as an 
>>> `async` method returning `Never`, even though the computation *does* 
>>> terminate eventually. I'm not sure how to handle that, though)
>> 
>> Yeah, I think that actor methods deserve a bit of magic:
>> 
>> - Their bodies should be implicitly async, so they can call async methods 
>> without blocking their current queue or have to use beginAsync.
>> - However, if they are void “fire and forget” messages, I think the caller 
>> side should *not* have to use await on them, since enqueuing the message 
>> will not block.
> 
> I think we need to be a little careful here—the mere fact that a message 
> returns `Void` doesn't mean the caller shouldn't wait until it's done to 
> continue. For instance:
> 
>listActor.delete(at: index)// Void, so it doesn't wait
>let count = await listActor.getCount()// But we want the count *after* 
> the deletion!
> 
> Perhaps we should depend on the caller to use a future (or a `beginAsync(_:)` 
> call) when they want to fire-and-forget? And yet sometimes a message truly 
> *can't* tell you when it's finished, and we don't want APIs to over-promise 
> on when they tell you they're done. I don't know.
> 
>> I agree.  That is one reason that I think it is important for it to have a 
>> (non-defaulted) protocol requirement.  Requiring someone to implement some 
>> code is a good way to get them to think about the operation… at least a 
>> little bit.
> 
> I wondered if that might have been your reasoning.
> 
>> That said, the design does not try to *guarantee* memory safety, so there 
>> will always be an opportunity for error.
> 
> True, but I think we could mitigate that by giving this protocol a relatively 
> narrow purpose. If we eventually build three different features on 
> `ValueSemantical`, we don't want all three of those features to break when 
> someone abuses the protocol to gain access to actors.
> 
>>> I also worry that the type behavior of a protocol is a bad fit for 
>>> `ValueSemantical`. Retroactive conformance to `ValueSemantical` is almost 
>>> certain to be an unprincipled hack; subclasses can very easily lose the 
>>> value-semantic behavior of their superclasses, but almost certainly can't 
>>> have value semantics unless their superclasses do. And yet having 
>>> `ValueSemantical` conformance somehow be uninherited would destroy Liskov 
>>> substitutability.
>> 
>> Indeed.  See NSArray vs NSMutableArray.
>> 
>> OTOH, I tend to think that retroactive conformance is really a good thing, 
>> particularly in the transition period where you’d be dealing with other 
>> people’s packages who haven’t adopted the model.  You may be adopting it for 
>> their structs afterall.
>> 
>> An alternate approach would be to just say “no, you can’t do that.  If you 
>> want to work around someone else’s problem, define a wrapper struct and mark 
>> it as ValueSemantical”.  That design could also work.
> 
> Yeah, I think wrapper structs are a workable alternative to retroactive 
> conformance.
> 
> What I basically envision (if we want to go with a general 
> `ValueSemantical`-type solution) is that, rather than being a protocol, we 
> would have a `value` keyword that went before the `enum`, `struct`, `class`, 
> or `protocol` keyword. (This is somewhat similar to the proposed `moveonly` 
> keyword.) It would not be valid before `extension`, except perhaps on a 
> conditional extension that only applied when a generic or associated type was 
> `value`, so retroactive conformance wouldn't really be possible. You could 
> also use `value` in a generic constraint list just as you can use `class` 
> there.

A modifier on the type feels like the right approach to specifying value 
semantics to me.  Regardless of which approach we take, it feels like something 
that needs to be implicit for structs and enums where value semantics is 
trivially provable by way of transitivity.  When that is not the case we could 
require an explicit `value` or `nonvalue` annotation (specific keywords subject 
to bikeshedding of course).

> 
> I'm not totally sure how to reconcile this with mutable subclasses, but I 
> have a very vague sense it might be possible if `value` required some kind of 
> *non*-inheritable initializer, and passing to a `value`-constrained parameter 
> implicitly passed the value through that initializer. That is, if you had:
> 
>// As imported--in reality this would be an NS_SWIFT_VALUE_TYPE annotation 
> on the Objective-C definition
>value class NSArray: NSObject {
>init(_ array: NSArray) { self = array.copy() as! NSArray }
>}
> 
> Then Swift would implicitly add some code to an actor method like this:
> 
>actor Foo {
>actor func 

Re: [swift-evolution] typed throws

2017-08-19 Thread Matthew Johnson via swift-evolution
f the library may be to 
establish conventions for the app that are intended to be used (almost) 
everywhere.

>  
>> The kind of categorization I want to be able to do requires a custom 
>> algorithm.  The specific algorithm is used to categorize errors depends on 
>> the dynamic context (i.e. the function that is propagating it).  The way I 
>> usually think about this categorization is as a conversion initializer as I 
>> showed in the example, but it certainly wouldn't need to be accomplished 
>> that way.  The most important thing IMO is the ability to categorize during 
>> error propagation and make information about that categorization easy for 
>> callers to discover.
>> 
>> The output of the algorithm could use various mechanisms for categorization 
>> - an enum is one mechanism, distinct types conforming to appropriate 
>> categorization protocols is another.  Attaching some kind of category value 
>> to the original error or propagating the category along with it might also 
>> work (although might be rather clunky).
>> 
>> It is trivial to make the original error immediately available via an 
>> `underlyingError` property so I really don't understand the resistance to 
>> wrapping errors.  The categorization can easily be ignored at the catch site 
>> if desired.  That said, if we figure out some other mechanism for 
>> categorizing errors, including placing different error values of the same 
>> type into different categories, and matching them based on this 
>> categorization I think I would be ok with that.  Using wrapper types is not 
>> essential to solving the problem.
>> 
>> Setting all of this aside, surely you had you had your own reasons for 
>> supporting typed errors in the past.  What were those and why do you no 
>> longer consider them important?
> 
> My memory is certainly spotty, but as far as I can recall, I had no distinct 
> reasons; it just seemed like a reasonable and "natural" next step that other 
> people wanted for which I had no use case of my own in mind. Having seen the 
> argumentation that there aren't very many use cases in general, I'm warming 
> to the view that it's probably not such a great next step.
> 
> 
>>>> On Fri, Aug 18, 2017 at 6:46 PM, Matthew Johnson <matt...@anandabits.com> 
>>>> wrote:
>>>> 
>>>>> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>>>>> 
>>>>>> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson 
>>>>>> <matt...@anandabits.com> wrote:
>>>>>> 
>>>>>>> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>>>>>>> 
>>>>>>>> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
>>>>>>>> <swift-evolution@swift.org> wrote:
>>>>>>>> 
>>>>>>>> 
>>>>>>>> Sent from my iPad
>>>>>>>> 
>>>>>>>> On Aug 18, 2017, at 1:27 AM, John McCall <rjmcc...@apple.com> wrote:
>>>>>>>> 
>>>>>>>> >> On Aug 18, 2017, at 12:58 AM, Chris Lattner via swift-evolution 
>>>>>>>> >> <swift-evolution@swift.org> wrote:
>>>>>>>> >> Splitting this off into its own thread:
>>>>>>>> >>
>>>>>>>> >>> On Aug 17, 2017, at 7:39 PM, Matthew Johnson 
>>>>>>>> >>> <matt...@anandabits.com> wrote:
>>>>>>>> >>> One related topic that isn’t discussed is type errors.  Many third 
>>>>>>>> >>> party libraries use a Result type with typed errors.  Moving to an 
>>>>>>>> >>> async / await model without also introducing typed errors into 
>>>>>>>> >>> Swift would require giving up something that is highly valued by 
>>>>>>>> >>> many Swift developers.  Maybe Swift 5 is the right time to tackle 
>>>>>>>> >>> typed errors as well.  I would be happy to help with design and 
>>>>>>>> >>> drafting a proposal but would need collaborators on the 
>>>>>>>> >>> implementation side.
>>>>>>>> >>
>>>>>>>> >> Typed throws is something we need to settle one way or the other, 
>>>>>>>> >> and I agree it would be nice to do that in the Swift 5 cycle.

Re: [swift-evolution] typed throws

2017-08-18 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
> Joe Groff wrote:
> 
> An alternative approach that embraces the open nature of errors could be to 
> represent domains as independent protocols, and extend the error types that 
> are relevant to that domain to conform to the protocol. That way, you don't 
> obscure the structure of the underlying error value with wrappers. If you 
> expect to exhaustively handle all errors in a domain, well, you'd almost 
> certainly going to need to have a fallback case in your wrapper type for 
> miscellaneous errors, but you could represent that instead without wrapping 
> via a catch-all, and as?-casting to your domain protocol with a ??-default 
> for errors that don't conform to the protocol. For example, instead of 
> attempting something like this:
> 
> enum DatabaseError {
>   case queryError(QueryError)
>   case ioError(IOError)
>   case other(Error)
> 
>   var errorKind: String {
> switch self {
>   case .queryError(let q): return "query error: \(q.query)"
>   case .ioError(let i): return "io error: \(i.filename)"
>   case .other(let e): return "\(e)"
> }
>   }
> }
> 
> func queryDatabase(_ query: String) throws /*DatabaseError*/ -> Table
> 
> do {
>   queryDatabase("delete * from users")
> } catch let d as DatabaseError {
>   os_log(d.errorKind)
> } catch {
>   fatalError("unexpected non-database error")
> }
> 
> You could do this:
> 
> protocol DatabaseError {
>   var errorKind: String { get }
> }
> 
> extension QueryError: DatabaseError {
>   var errorKind: String { return "query error: \(q.query)" }
> }
> extension IOError: DatabaseError {
>   var errorKind: String ( return "io error: \(i.filename)" }
> }
> 
> extension Error {
>   var databaseErrorKind: String {
> return (error as? DatabaseError)?.errorKind ?? "unexpected non-database 
> error"
>   }
> }
> 
> func queryDatabase(_ query: String) throws -> Table
> 
> do {
>   queryDatabase("delete * from users")
> } catch {
>   os_log(error.databaseErrorKind)
> }

This approach isn't sufficient for several reasons.  Notably, it requires the 
underlying errors to already have a distinct type for every category we wish to 
place them in.  If all network errors have the same type and I want to 
categorize them based on network availability, authentication, dropped 
connection, etc I am not able to do that.  

The kind of categorization I want to be able to do requires a custom algorithm. 
 The specific algorithm is used to categorize errors depends on the dynamic 
context (i.e. the function that is propagating it).  The way I usually think 
about this categorization is as a conversion initializer as I showed in the 
example, but it certainly wouldn't need to be accomplished that way.  The most 
important thing IMO is the ability to categorize during error propagation and 
make information about that categorization easy for callers to discover.

The output of the algorithm could use various mechanisms for categorization - 
an enum is one mechanism, distinct types conforming to appropriate 
categorization protocols is another.  Attaching some kind of category value to 
the original error or propagating the category along with it might also work 
(although might be rather clunky).

It is trivial to make the original error immediately available via an 
`underlyingError` property so I really don't understand the resistance to 
wrapping errors.  The categorization can easily be ignored at the catch site if 
desired.  That said, if we figure out some other mechanism for categorizing 
errors, including placing different error values of the same type into 
different categories, and matching them based on this categorization I think I 
would be ok with that.  Using wrapper types is not essential to solving the 
problem.

Setting all of this aside, surely you had you had your own reasons for 
supporting typed errors in the past.  What were those and why do you no longer 
consider them important?

> 
> 
>> On Fri, Aug 18, 2017 at 6:46 PM, Matthew Johnson <matt...@anandabits.com> 
>> wrote:
>> 
>>> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>>> 
>>>> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson <matt...@anandabits.com> 
>>>> wrote:
>>>> 
>>>>> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>>>>> 
>>>>>> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
>>>>>> <swift-evolution@swift.org> wrote:
>>>>

Re: [swift-evolution] typed throws

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson <matt...@anandabits.com 
> <mailto:matt...@anandabits.com>> wrote:
> 
>> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu <xiaodi...@gmail.com 
>> <mailto:xiaodi...@gmail.com>> wrote:
>> 
>> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>> Sent from my iPad
>> 
>> On Aug 18, 2017, at 1:27 AM, John McCall <rjmcc...@apple.com 
>> <mailto:rjmcc...@apple.com>> wrote:
>> 
>> >> On Aug 18, 2017, at 12:58 AM, Chris Lattner via swift-evolution 
>> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> >> Splitting this off into its own thread:
>> >>
>> >>> On Aug 17, 2017, at 7:39 PM, Matthew Johnson <matt...@anandabits.com 
>> >>> <mailto:matt...@anandabits.com>> wrote:
>> >>> One related topic that isn’t discussed is type errors.  Many third party 
>> >>> libraries use a Result type with typed errors.  Moving to an async / 
>> >>> await model without also introducing typed errors into Swift would 
>> >>> require giving up something that is highly valued by many Swift 
>> >>> developers.  Maybe Swift 5 is the right time to tackle typed errors as 
>> >>> well.  I would be happy to help with design and drafting a proposal but 
>> >>> would need collaborators on the implementation side.
>> >>
>> >> Typed throws is something we need to settle one way or the other, and I 
>> >> agree it would be nice to do that in the Swift 5 cycle.
>> >>
>> >> For the purposes of this sub-discussion, I think there are three kinds of 
>> >> code to think about:
>> >> 1) large scale API like Cocoa which evolve (adding significant 
>> >> functionality) over the course of many years and can’t break clients.
>> >> 2) the public API of shared swiftpm packages, whose lifecycle may rise 
>> >> and fall - being obsoleted and replaced by better packages if they 
>> >> encounter a design problem.
>> >> 3) internal APIs and applications, which are easy to change because the 
>> >> implementations and clients of the APIs are owned by the same people.
>> >>
>> >> These each have different sorts of concerns, and we hope that something 
>> >> can start out as #3 but work its way up the stack gracefully.
>> >>
>> >> Here is where I think things stand on it:
>> >> - There is consensus that untyped throws is the right thing for a large 
>> >> scale API like Cocoa.  NSError is effectively proven here.  Even if typed 
>> >> throws is introduced, Apple is unlikely to adopt it in their APIs for 
>> >> this reason.
>> >> - There is consensus that untyped throws is the right default for people 
>> >> to reach for for public package (#2).
>> >> - There is consensus that Java and other systems that encourage lists of 
>> >> throws error types lead to problematic APIs for a variety of reasons.
>> >> - There is disagreement about whether internal APIs (#3) should use it.  
>> >> It seems perfect to be able to write exhaustive catches in this 
>> >> situation, since everything in knowable. OTOH, this could encourage abuse 
>> >> of error handling in cases where you really should return an enum instead 
>> >> of using throws.
>> >> - Some people are concerned that introducing typed throws would cause 
>> >> people to reach for it instead of using untyped throws for public package 
>> >> APIs.
>> >
>> > Even for non-public code.  The only practical merit of typed throws I have 
>> > ever seen someone demonstrate is that it would let them use contextual 
>> > lookup in a throw or catch.  People always say "I'll be able to 
>> > exhaustively switch over my errors", and then I ask them to show me where 
>> > they want to do that, and they show me something that just logs the error, 
>> > which of course does not require typed throws.  Every.  Single.  Time.
>> 
>> I agree that exhaustive switching over errors is something that people are 
>> extremely likely to actually want to do.  I also think it's a bit of a red 
>> herring.  The value of typed errors is *not* in exhaustive switching.  It is 

Re: [swift-evolution] typed throws

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> 
> 
> Sent from my iPad
> 
> On Aug 18, 2017, at 1:27 AM, John McCall <rjmcc...@apple.com 
> <mailto:rjmcc...@apple.com>> wrote:
> 
> >> On Aug 18, 2017, at 12:58 AM, Chris Lattner via swift-evolution 
> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> >> Splitting this off into its own thread:
> >>
> >>> On Aug 17, 2017, at 7:39 PM, Matthew Johnson <matt...@anandabits.com 
> >>> <mailto:matt...@anandabits.com>> wrote:
> >>> One related topic that isn’t discussed is type errors.  Many third party 
> >>> libraries use a Result type with typed errors.  Moving to an async / 
> >>> await model without also introducing typed errors into Swift would 
> >>> require giving up something that is highly valued by many Swift 
> >>> developers.  Maybe Swift 5 is the right time to tackle typed errors as 
> >>> well.  I would be happy to help with design and drafting a proposal but 
> >>> would need collaborators on the implementation side.
> >>
> >> Typed throws is something we need to settle one way or the other, and I 
> >> agree it would be nice to do that in the Swift 5 cycle.
> >>
> >> For the purposes of this sub-discussion, I think there are three kinds of 
> >> code to think about:
> >> 1) large scale API like Cocoa which evolve (adding significant 
> >> functionality) over the course of many years and can’t break clients.
> >> 2) the public API of shared swiftpm packages, whose lifecycle may rise and 
> >> fall - being obsoleted and replaced by better packages if they encounter a 
> >> design problem.
> >> 3) internal APIs and applications, which are easy to change because the 
> >> implementations and clients of the APIs are owned by the same people.
> >>
> >> These each have different sorts of concerns, and we hope that something 
> >> can start out as #3 but work its way up the stack gracefully.
> >>
> >> Here is where I think things stand on it:
> >> - There is consensus that untyped throws is the right thing for a large 
> >> scale API like Cocoa.  NSError is effectively proven here.  Even if typed 
> >> throws is introduced, Apple is unlikely to adopt it in their APIs for this 
> >> reason.
> >> - There is consensus that untyped throws is the right default for people 
> >> to reach for for public package (#2).
> >> - There is consensus that Java and other systems that encourage lists of 
> >> throws error types lead to problematic APIs for a variety of reasons.
> >> - There is disagreement about whether internal APIs (#3) should use it.  
> >> It seems perfect to be able to write exhaustive catches in this situation, 
> >> since everything in knowable. OTOH, this could encourage abuse of error 
> >> handling in cases where you really should return an enum instead of using 
> >> throws.
> >> - Some people are concerned that introducing typed throws would cause 
> >> people to reach for it instead of using untyped throws for public package 
> >> APIs.
> >
> > Even for non-public code.  The only practical merit of typed throws I have 
> > ever seen someone demonstrate is that it would let them use contextual 
> > lookup in a throw or catch.  People always say "I'll be able to 
> > exhaustively switch over my errors", and then I ask them to show me where 
> > they want to do that, and they show me something that just logs the error, 
> > which of course does not require typed throws.  Every.  Single.  Time.
> 
> I agree that exhaustive switching over errors is something that people are 
> extremely likely to actually want to do.  I also think it's a bit of a red 
> herring.  The value of typed errors is *not* in exhaustive switching.  It is 
> in categorization and verified documentation.
> 
> Here is a concrete example that applies to almost every app.  When you make a 
> network request there are many things that could go wrong to which you may 
> want to respond differently:
> * There might be no network available.  You might recover by updating the UI 
> to indicate that and start monitoring for a reachability change.
> * There might have been a server error that should eventually be resolved 
> (500).  You might update the UI and provide 

Re: [swift-evolution] [Concurrency] async/await + actors

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 2:15 PM, Chris Lattner via swift-evolution 
>  wrote:
> 
> 
>> On Aug 18, 2017, at 7:19 AM, Michel Fortin > > wrote:
>> 
>> Great writeup. Here's a few comments about the manifesto, actors and value 
>> semantics specifically.
>> 
>> 
>> # About actors and data isolation
>> 
>> Can I call global functions like sin(x) in an actor? Surely you need to be 
>> able to do that. But how can the compiler know which functions are safe to 
>> use and which are out of bound for an actor?
> 
> The design I outline allows you to call it, and punts on the problem of 
> safety:
> https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782#global-mutable-state
>  
> 
> 
>> Actors shouldn't access the global mutable state and thus should only call 
>> functions that do not access the global mutable state. We probably need a 
>> concept of a functions being pure (as in not accessing the global mutable 
>> state) for that.
> 
> I’m not aware of a practical model to achieve that, but if there were, more 
> safety would provide more goodness :-)
> 
> 
>> # About the part "Does a type provide proper value semantics?"
>> 
>> I would argue that this is the wrong question. Most types are a hybrid form 
>> of value and reference semantics. All you need is to limit what you do to 
>> what is proper value semantics and forbid the parts that use reference 
>> semantics. Otherwise you are pessimising the capabilities of the types.
>> 
>> For instance, has Array value semantics?
> 
> By the commonly accepted definition, Array does not provide value 
> semantics.

Dave Abrahams and I had an extremely long exchange at one point where he was 
taking the opposite position (if I understood it correctly).  It would be nice 
to have the Swift community adopt a standard definition of value semantics and 
document it on swift.org .  :)

> 
>> You might be tempted to say that it does not because it contains class 
>> references, but in reality that depends on what you do with those UIViews.
> 
> An aspect of the type (“does it have value semantics or not”) should not 
> depend on the clients.  By your definition, every type has value semantics if 
> none of the mutating operations are called :-)
> 
>> If you treat the class references as opaque pointers (never dereferencing 
>> them), you preserve value semantics. You can count the elements, shuffle 
>> them, all without dereferencing the UIViews it contains. Value semantics 
>> only end when you dereference the class references. And even then, there are 
>> some exceptions.
> 
> I agree with you that the model could permit all values to be sent in actor 
> messages, but doing so would give up the principle advantages of mutable 
> state separation.  You’d have to do synchronization, you’d have the same bugs 
> that have always existed, etc.
> 
> -Chris
> 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


Re: [swift-evolution] Fast enums (was: typed throws)

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 2:19 PM, Adrian Zubarev  
> wrote:
> 
> Wasn’t Joe Groff and Daniel Duan proposing anonymous enum cases in some of 
> the early draft of the ‘Normalize Enum Case Representation’ proposal? 
> 
> Maybe it’s time to revive that topic.
> 
> Matthew Johnson has also some interesting ideas in hist gist: 
> https://gist.github.com/anandabits/5b7f8e3836387e893e3a1197a4bf144d#structural-unions
>  
> As
>  far as I know that turns out to be equivalent to the commonly rejected 
> feature.  :)
> 
> 
> 
> 
> Am 18. August 2017 um 21:08:22, Robert Bennett via swift-evolution 
> (swift-evolution@swift.org ) schrieb:
> 
>> The better solution would be to allow the creation of new enums from the 
>> union of existing enums, which was proposed recently.
>> 
>> On Aug 18, 2017, at 2:36 PM, John McCall via swift-evolution 
>> > wrote:
>> 
>> >> On Aug 18, 2017, at 6:36 AM, Jonathan Hull via swift-evolution 
>> >> > wrote:
>> >> The typed throws discussion brought me back to an old thought.
>> >> 
>> >> I would really like to see a new structural type, similar to tuples, 
>> >> which act as an anonymous enum. These would actually be a distinct type 
>> >> from enums (not sure what to call them), in the same way that structs and 
>> >> tuples are different. They would have a very similar syntax to enums 
>> >> though, so they would be easy to learn.
>> > 
>> > This is the commonly-rejected "Disjunctions in type constraints" feature.
>> > 
>> > John.
>> > 
>> >> 
>> >> There would be two major difference from enums:
>> >> 
>> >> 1) Because they are structural, they can’t have associated functions or 
>> >> extensions
>> >> 
>> >> 2) They can concatenate with one another freely 
>> >> 
>> >> For example:
>> >> 
>> >> func foo( speed: .slow | .med | .fast ){
>> >> bar(speed: speed)
>> >> }
>> >> 
>> >> func bar(speed: .slow | .med | .fast | .ludicrous) {
>> >> //but we couldn't call foo here because it doesn’t take .ludicrous
>> >> }
>> >> 
>> >> Each case is it’s own mini-type in a way. One ‘.slow’ is equivalent to 
>> >> any ‘.slow’ (even one from a regular enum). Essentially, it is a loosely 
>> >> bound group of cases, and type checking just means seeing if the 
>> >> list/value being passed is a subset of the list of possible cases.
>> >> 
>> >> I’d also like to see sugar for quick conversion from normal Swift enums:
>> >> 
>> >> enum Speed {
>> >> case slow
>> >> case med
>> >> case fast
>> >> }
>> >> 
>> >> func foo(speed: Speed | .ludicrous) {
>> >> //we can’t call any functions/extensions of Speed, just like we can’t 
>> >> call a func from int on (Int, Int) 
>> >> }
>> >> 
>> >> In the above case, Speed gets converted via sugar to “.speed(Speed)” and 
>> >> then gets concatenated with .ludicrous. Ideally, it would have the added 
>> >> ability to truly convert to ".slow | .med | .fast | .ludicrous” when 
>> >> passed to something that doesn’t know about Speed:
>> >> 
>> >> func foo(speed: Speed | .ludicrous) {
>> >> switch speed {
>> >> case .speed(let s): //Do something with the Speed value
>> >> case .ludicrous: //Do something ludicrous
>> >> } 
>> >> bar(speed: speed) //This can convert to pass by unwrapping Speed to a bag 
>> >> of cases
>> >> }
>> >> 
>> >> func bar(speed: .slow | .med | .fast | .ludicrous) {
>> >> switch speed {
>> >> case .slow: //
>> >> case .med: //
>> >> case .fast: //
>> >> case .ludicrous: //
>> >> }
>> >> //We can’t reference Speed above because we just passed a bag of 
>> >> potential cases
>> >> }
>> >>  
>> >> 
>> >> The end result here is that in addition to building one-off enums 
>> >> quickly, it lets us concatenate and extend enums for use in a limited 
>> >> scope. I don’t know about you, but I run into the situation of “I want 
>> >> exactly this enum, but with one extra case” all the time.
>> >> 
>> >> I don’t know if we want typed throws, but this type of quick 
>> >> concatability would be very useful for adding/merging potential errors. 
>> >> With the same sugar used on Speed above, it would also allow something 
>> >> similar to Union types, but without the most of the implementation 
>> >> headache that would cause. You can take in multiple types, and you get 
>> >> back something you can switch on to recover the type which was passed:
>> >> 
>> >> func myFakeUnion(_ intOrStr: Int | String){
>> >> switch intOrStr {
>> >> case .int(let i): //Do something with int
>> >> case .string(let s): //Do something with string
>> >> }
>> >> } 
>> >> 
>> >> myFakeUnion(12) //Sugar!
>> >> myFakeUnion(.string(“Hey”)) //This works too
>> >> 
>> >> 
>> >> Finally, I would love to see the switch equivalent of ‘a ? b : c’ in 
>> >> Swift. I am not sure what the best syntax would be, but it would 
>> 

Re: [swift-evolution] typed throws

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 1:09 PM, John McCall  wrote:
> 
>> 
>> On Aug 18, 2017, at 10:19 AM, Matthew Johnson  wrote:
>> 
>> 
>> 
>> Sent from my iPad
>> 
>> On Aug 18, 2017, at 1:27 AM, John McCall  wrote:
>> 
 On Aug 18, 2017, at 12:58 AM, Chris Lattner via swift-evolution 
  wrote:
 Splitting this off into its own thread:
 
> On Aug 17, 2017, at 7:39 PM, Matthew Johnson  
> wrote:
> One related topic that isn’t discussed is type errors.  Many third party 
> libraries use a Result type with typed errors.  Moving to an async / 
> await model without also introducing typed errors into Swift would 
> require giving up something that is highly valued by many Swift 
> developers.  Maybe Swift 5 is the right time to tackle typed errors as 
> well.  I would be happy to help with design and drafting a proposal but 
> would need collaborators on the implementation side.
 
 Typed throws is something we need to settle one way or the other, and I 
 agree it would be nice to do that in the Swift 5 cycle.
 
 For the purposes of this sub-discussion, I think there are three kinds of 
 code to think about: 
 1) large scale API like Cocoa which evolve (adding significant 
 functionality) over the course of many years and can’t break clients. 
 2) the public API of shared swiftpm packages, whose lifecycle may rise and 
 fall - being obsoleted and replaced by better packages if they encounter a 
 design problem.  
 3) internal APIs and applications, which are easy to change because the 
 implementations and clients of the APIs are owned by the same people.
 
 These each have different sorts of concerns, and we hope that something 
 can start out as #3 but work its way up the stack gracefully.
 
 Here is where I think things stand on it:
 - There is consensus that untyped throws is the right thing for a large 
 scale API like Cocoa.  NSError is effectively proven here.  Even if typed 
 throws is introduced, Apple is unlikely to adopt it in their APIs for this 
 reason.
 - There is consensus that untyped throws is the right default for people 
 to reach for for public package (#2).
 - There is consensus that Java and other systems that encourage lists of 
 throws error types lead to problematic APIs for a variety of reasons.
 - There is disagreement about whether internal APIs (#3) should use it.  
 It seems perfect to be able to write exhaustive catches in this situation, 
 since everything in knowable. OTOH, this could encourage abuse of error 
 handling in cases where you really should return an enum instead of using 
 throws.
 - Some people are concerned that introducing typed throws would cause 
 people to reach for it instead of using untyped throws for public package 
 APIs.
>>> 
>>> Even for non-public code.  The only practical merit of typed throws I have 
>>> ever seen someone demonstrate is that it would let them use contextual 
>>> lookup in a throw or catch.  People always say "I'll be able to 
>>> exhaustively switch over my errors", and then I ask them to show me where 
>>> they want to do that, and they show me something that just logs the error, 
>>> which of course does not require typed throws.  Every.  Single.  Time.
>> 
>> I agree that exhaustive switching over errors is something that people are 
>> extremely likely to actually want to do.  I also think it's a bit of a red 
>> herring.  The value of typed errors is *not* in exhaustive switching.  It is 
>> in categorization and verified documentation.
>> 
>> Here is a concrete example that applies to almost every app.  When you make 
>> a network request there are many things that could go wrong to which you may 
>> want to respond differently:
>> * There might be no network available.  You might recover by updating the UI 
>> to indicate that and start monitoring for a reachability change.
>> * There might have been a server error that should eventually be resolved 
>> (500).  You might update the UI and provide the user the ability to retry.
>> * There might have been an unrecoverable server error (404).  You will 
>> update the UI.
>> * There might have been a low level parsing error (bad JSON, etc).  Recovery 
>> is perhaps similar in nature to #2, but the problem is less likely to be 
>> resolved quickly so you may not provide a retry option.  You might also want 
>> to do something to notify your dev team that the server is returning JSON 
>> that can't be parsed.
>> * There might have been a higher-level parsing error (converting JSON to 
>> model types).  This might be treated the same as bad JSON.  On the other 
>> hand, depending on the specifics of the app, you might take an alternate 
>> path that only parses the most essential model data in 

Re: [swift-evolution] typed throws

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 12:05 PM, Joe Groff  wrote:
> 
> 
>> On Aug 17, 2017, at 9:58 PM, Chris Lattner via swift-evolution 
>> > wrote:
>> 
>>> On Aug 17, 2017, at 7:39 PM, Matthew Johnson >> > wrote:
>>> One related topic that isn’t discussed is type errors.  Many third party 
>>> libraries use a Result type with typed errors.  Moving to an async / await 
>>> model without also introducing typed errors into Swift would require giving 
>>> up something that is highly valued by many Swift developers.  Maybe Swift 5 
>>> is the right time to tackle typed errors as well.  I would be happy to help 
>>> with design and drafting a proposal but would need collaborators on the 
>>> implementation side.
>> 
>> Typed throws is something we need to settle one way or the other, and I 
>> agree it would be nice to do that in the Swift 5 cycle.
> 
> My view of this is the opposite of Matthew's—the canonical examples of things 
> for which untyped errors are the "right thing" due to unbounded failure 
> modes, such as file IO, IPC, network communication, etc. are almost all 
> things you also want to be 'async', so I don't think async makes typed 
> 'throws' any more urgent to consider. As we've discussed in person, I feel 
> like there's a strong argument to be made that 'async' should always imply 
> untyped 'throws’.

That’s interesting. Have you looked at how people are using `Result` in current third party libraries that do async stuff?

Even when failure modes are unbounded it can still be very useful to categorize 
the kinds of errors that might happen and encourage thoughtfulness about 
recovery in a way that an untyped `Error` does not.  Maybe types are not the 
best way to solve that problem but I haven’t seen any alternative that looks 
promising.

> 
> -Joe

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


Re: [swift-evolution] [Concurrency] async/await + actors

2017-08-18 Thread Matthew Johnson via swift-evolution

> On Aug 18, 2017, at 9:19 AM, Michel Fortin via swift-evolution 
>  wrote:
> 
> Great writeup. Here's a few comments about the manifesto, actors and value 
> semantics specifically.
> 
> 
> # About actors and data isolation
> 
> Can I call global functions like sin(x) in an actor? Surely you need to be 
> able to do that. But how can the compiler know which functions are safe to 
> use and which are out of bound for an actor?
> 
> Actors shouldn't access the global mutable state and thus should only call 
> functions that do not access the global mutable state. We probably need a 
> concept of a functions being pure (as in not accessing the global mutable 
> state) for that.
> 
> 
> # About the part "Does a type provide proper value semantics?"
> 
> I would argue that this is the wrong question. Most types are a hybrid form 
> of value and reference semantics. All you need is to limit what you do to 
> what is proper value semantics and forbid the parts that use reference 
> semantics. Otherwise you are pessimising the capabilities of the types.
> 
> For instance, has Array value semantics? You might be tempted to say 
> that it does not because it contains class references, but in reality that 
> depends on what you do with those UIViews. If you treat the class references 
> as opaque pointers (never dereferencing them), you preserve value semantics. 
> You can count the elements, shuffle them, all without dereferencing the 
> UIViews it contains. Value semantics only end when you dereference the class 
> references. And even then, there are some exceptions.
> 
> 
> I suggested a little while ago on this list some principles based on this 
> that would allow for the compiler to enforce value semantics with a `pure` 
> attribute and I'm currently working on a draft proposal. In essence this 
> proposal will have pure functions guaranteeing value semantics and no access 
> to the global state, and a correct implementation for copy-on-write types. I 
> think this would be useful for actors.

It’s great to hear that you’re returning to the topic of pure functions Michel! 
 Please let me know if there is anything I can do to help.

> 
> 
> 
>> Le 17 août 2017 à 18:24, Chris Lattner via swift-evolution 
>> > a écrit :
>> 
>> Hi all,
>> 
>> As Ted mentioned in his email, it is great to finally kick off discussions 
>> for what concurrency should look like in Swift.  This will surely be an epic 
>> multi-year journey, but it is more important to find the right design than 
>> to get there fast.
>> 
>> I’ve been advocating for a specific model involving async/await and actors 
>> for many years now.  Handwaving only goes so far, so some folks asked me to 
>> write them down to make the discussion more helpful and concrete.  While I 
>> hope these ideas help push the discussion on concurrency forward, this isn’t 
>> in any way meant to cut off other directions: in fact I hope it helps give 
>> proponents of other designs a model to follow: a discussion giving extensive 
>> rationale, combined with the long term story arc to show that the features 
>> fit together.
>> 
>> Anyway, here is the document, I hope it is useful, and I’d love to hear 
>> comments and suggestions for improvement:
>> https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782 
>> 
>> 
>> -Chris
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> 
> 
> -- 
> Michel Fortin
> https://michelf.ca 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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


  1   2   3   4   5   6   7   8   9   10   >