Re: [swift-evolution] typed throws

2017-08-25 Thread Dave Abrahams via swift-evolution


on Fri Aug 25 2017, John McCall  wrote: 

On Aug 25, 2017, at 12:18 PM, Dave Abrahams via swift-evolution 
 wrote: on Fri Aug 18 2017, Joe 
Groff  wrote:  
On Aug 17, 2017, at 11:27 PM, John McCall via swift-evolution 
 wrote: 


 Essentially, you give Error a tagged-pointer representation 
to allow payload-less errors on non-generic error types to be 
allocated 
 
globally, and then you can (1) tell people to not throw 
errors that require allocation if it's vital to avoid 
allocation (just like we would tell them today not to 
construct classes or indirect enum cases) and (2) allow a 
special global payload-less error to be substituted if error 
allocation fails.   Of course, we could also say that systems 
code is required to use a typed-throws feature that we add 
down the line for their purposes.  Or just tell them to not 
use payloads.  Or force them to constrain their error types 
to fit within some given size.  (Note that obsessive error 
taxonomies tend to end up with a bunch of indirect enum cases 
anyway, because they get recursive, so the allocation problem 
is very real whatever we do.) 
 Alternatively, with some LLVM work, we could have the thrower 
leave the error value on the stack when propagating an error, 
and make it the catcher's responsibility to consume the error 
value and pop the stack. We could make not only errors but 
existential returns in general more efficient and "systems 
code"-worthy with a technique like that. 
 That's how the best C++ unwiding mechanisms work already. 


Them's fighting words. :) 


The correct term, John, is “fightin'”

-Crustee

John. 

I always thought it was off the table because we were wedded to 
the idea that throwing functions are just effectively returning 
a Result normally under the covers, but if not, so much the 
better!   --  -Dave 
___ swift-evolution 
mailing list swift-evolution@swift.org 
https://lists.swift.org/mailman/listinfo/swift-evolution 


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


Re: [swift-evolution] typed throws

2017-08-25 Thread John McCall via swift-evolution
> On Aug 25, 2017, at 12:18 PM, Dave Abrahams via swift-evolution 
>  wrote:
> on Fri Aug 18 2017, Joe Groff  wrote:
> 
>>> On Aug 17, 2017, at 11:27 PM, John McCall via swift-evolution
>>>  wrote:
>>> 
>>> Essentially, you give Error a tagged-pointer representation to allow
>>> payload-less errors on non-generic error types to be allocated
>> 
>>> globally, and then you can (1) tell people to not throw errors that
>>> require allocation if it's vital to avoid allocation (just like we
>>> would tell them today not to construct classes or indirect enum
>>> cases) and (2) allow a special global payload-less error to be
>>> substituted if error allocation fails.
>>> 
>>> Of course, we could also say that systems code is required to use a
>>> typed-throws feature that we add down the line for their purposes.
>>> Or just tell them to not use payloads.  Or force them to constrain
>>> their error types to fit within some given size.  (Note that
>>> obsessive error taxonomies tend to end up with a bunch of indirect
>>> enum cases anyway, because they get recursive, so the allocation
>>> problem is very real whatever we do.)
>> 
>> Alternatively, with some LLVM work, we could have the thrower leave
>> the error value on the stack when propagating an error, and make it
>> the catcher's responsibility to consume the error value and pop the
>> stack. We could make not only errors but existential returns in
>> general more efficient and "systems code"-worthy with a technique like
>> that.
> 
> That's how the best C++ unwiding mechanisms work already.

Them's fighting words. :)

John.

> I always thought it was off the table because we were wedded to the idea that
> throwing functions are just effectively returning a Result normally
> under the covers, but if not, so much the better!
> 
> -- 
> -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] typed throws

2017-08-25 Thread Dave Abrahams via swift-evolution

on Fri Aug 18 2017, Joe Groff  wrote:

>> On Aug 17, 2017, at 11:27 PM, John McCall via swift-evolution
>>  wrote:
>> 
>> Essentially, you give Error a tagged-pointer representation to allow
>> payload-less errors on non-generic error types to be allocated
>
>> globally, and then you can (1) tell people to not throw errors that
>> require allocation if it's vital to avoid allocation (just like we
>> would tell them today not to construct classes or indirect enum
>> cases) and (2) allow a special global payload-less error to be
>> substituted if error allocation fails.
>> 
>> Of course, we could also say that systems code is required to use a
>> typed-throws feature that we add down the line for their purposes.
>> Or just tell them to not use payloads.  Or force them to constrain
>> their error types to fit within some given size.  (Note that
>> obsessive error taxonomies tend to end up with a bunch of indirect
>> enum cases anyway, because they get recursive, so the allocation
>> problem is very real whatever we do.)
>
> Alternatively, with some LLVM work, we could have the thrower leave
> the error value on the stack when propagating an error, and make it
> the catcher's responsibility to consume the error value and pop the
> stack. We could make not only errors but existential returns in
> general more efficient and "systems code"-worthy with a technique like
> that.

That's how the best C++ unwiding mechanisms work already.  I always
thought it was off the table because we were wedded to the idea that
throwing functions are just effectively returning a Result normally
under the covers, but if not, so much the better!

-- 
-Dave

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


Re: [swift-evolution] typed throws

2017-08-25 Thread Dave Abrahams via swift-evolution

on Thu Aug 17 2017, 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.
>
> Sometimes we then go on to have a conversation about wrapping errors
> in other error types, and that can be interesting, but now we're
> talking about adding a big, messy feature just to get "safety"
> guarantees for a fairly minor need.
>
> Programmers often have an instinct to obsess over error taxonomies
> that is very rarely directed at solving any real problem; it is just
> self-imposed busy-work.

+1; I couldn't have said this any better.  

The problem is not merely that by implementing this we'd be expending
effort and adding language complexity; it's also that programmers love
to classify things and those working with statically-typed languages
have a natural inclination to think “more static type information is
better,” so they *will* use this feature whether it's good for code or
not.

-- 
-Dave

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


Re: [swift-evolution] typed throws

2017-08-21 Thread Brent Royal-Gordon via swift-evolution
> On Aug 17, 2017, at 11:27 PM, John McCall via swift-evolution 
>  wrote:
> 
> 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.


Let me take this in a slightly different direction.

I largely agree with you that most code shouldn't limit the types of errors it 
can throw. But I still want still want typed throws because I want to address a 
completely different problem: generics. Other than the useful but limited 
abilities of `rethrows`, there is currently no way to sensibly abstract over 
the error behavior of a piece of code. In particular, there's no way for a 
single protocol to support both throwing and non-throwing conformances.

One very straightforward and sensible way to handle this would be to support 
typed `throws` and make `Never` a subtype of `Error`; then you could handle 
error behavior abstraction using generic parameters, associated types, `where` 
clauses, and all those nice things we've already invented and taught people how 
to use. The other alternative is to invent several generics features from whole 
cloth purely to handle `throws`.

If we want to support errors in generics, designing typed `throws` and its 
interactions with the generics system seems a lot easier than designing a novel 
mechanism. Perhaps there are complications I'm not aware of—the thought of 
figuring out how generics are implemented fills me with dread—but naïvely, I 
would guess that the typed-throws-based solution will be easier to implement, 
too. And of course typed `throws` also helps the people who think they want to, 
you know, specify the type that a function throws. And it might help with the 
systems programming challenges we've talked about in this thread. So we can 
solve several different problems with a single feature, even if we think some 
of those problems are kind of niche.

I don't think any of the individual reasons to support typed `throws` are home 
runs, but I think this thread has produced some pretty solid ground balls and a 
couple of well-timed bunts, and that might be enough to get it across home 
plate.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] typed throws

2017-08-20 Thread Karl Wagner via swift-evolution

> On 18. Aug 2017, at 08:27, John McCall via swift-evolution 
>  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.
> 
> Sometimes we then go on to have a conversation about wrapping errors in other 
> error types, and that can be interesting, but now we're talking about adding 
> a big, messy feature just to get "safety" guarantees for a fairly minor need.
> 
> Programmers often have an instinct to obsess over error taxonomies that is 
> very rarely directed at solving any real problem; it is just self-imposed 
> busy-work.
> 
>> - Some people think that while it might be useful in some narrow cases, the 
>> utility isn’t high enough to justify making the language more complex 
>> (complexity that would intrude on the APIs of result types, futures, etc)
>> 
>> I’m sure there are other points in the discussion that I’m forgetting.
>> 
>> One thing that I’m personally very concerned about is in the systems 
>> programming domain.  Systems code is sort of the classic example of code 
>> that is low-level enough and finely specified enough that there are lots of 
>> knowable things, including the failure modes.
> 
> Here we are using "systems" to mean "embedded systems and kernels".  And 
> frankly even a kernel is a large enough system that they don't want to 
> exhaustively switch over failures; they just want the static guarantees that 
> go along with a constrained error type.
> 
>> Beyond expressivity though, our current model involves boxing thrown values 
>> into an Error existential, something that forces an implicit memory 
>> allocation when the value is large. Unless this is fixed, I’m very concerned 
>> that we’ll end up with a situation where certain kinds of systems code 
>> (i.e., that which cares about real time guarantees) will not be able to use 
>> error handling at all.  
>> 
>> JohnMC has some ideas on how to change code generation for ‘throws’ to avoid 
>> this problem, but 

Re: [swift-evolution] typed throws

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


Sent from my iPad

> On Aug 19, 2017, at 2:16 PM, Xiaodi Wu  wrote:
> 
>> On Sat, Aug 19, 2017 at 2:04 PM, Matthew Johnson  
>> wrote:
>> 
>> 
>> Sent from my iPad
>> 
>>> On Aug 19, 2017, at 12:43 PM, Xiaodi Wu  wrote:
>>> 
>>> 
 On Sat, Aug 19, 2017 at 08:29 Matthew Johnson  
 wrote:
 
 
 Sent from my iPad
 
> On Aug 18, 2017, at 9:19 PM, Xiaodi Wu  wrote:
> 
> 
> 
>> On Fri, Aug 18, 2017 at 8:11 PM, Matthew Johnson 
>>  wrote:
>> 
>> 
>> Sent from my iPad
>> 
>>> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu  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.  
> 
> Sorry, how does the presence or absence of typed throws play into this?
 
 It provides a convenient way to drive an error conversion mechanism during 
 propagation, whether in a library function used to wrap the throwing 
 expression or ideally with language support.  If I call a function that 
 throws FooError and my function throws BarError and we have a way to go 
 from FooError to BarError we can invoke that conversion without needing to 
 catch and rethrow the wrapped error.  
>>> 
>>> But isn't that an argument *against* typed errors? You need this 
>>> language-level support to automatically convert FooErrors to BarErrors 
>>> *because* you've restricted yourself to throwing BarErrors and the function 
>>> you call is restricted to throwing FooErrors. Currently, without typed 
>>> errors, there is no need to convert a FooError to a BarError.
>> 
>> No, this is a misunderstanding of the point of the conversion.  In that 
>> example, the point of performing a conversion is not because the types are 
>> arbitrarily chosen. It is because the initializer of BarError includes an 
>> algorithm that categorizes errors.  It may place different values of 
>> FooError into different cases.  What I am after is language-level support 
>> for categorizing errors during propagation and making the categories easily 
>> visible to anyone who looks at the signature of a function that chooses to 
>> categorize its errors.  Using types and the 

Re: [swift-evolution] typed throws

2017-08-19 Thread Xiaodi Wu via swift-evolution
On Sat, Aug 19, 2017 at 2:04 PM, Matthew Johnson 
wrote:

>
>
> Sent from my iPad
>
> On Aug 19, 2017, at 12:43 PM, Xiaodi Wu  wrote:
>
>
> On Sat, Aug 19, 2017 at 08:29 Matthew Johnson 
> wrote:
>
>>
>>
>> Sent from my iPad
>>
>> On Aug 18, 2017, at 9:19 PM, Xiaodi Wu  wrote:
>>
>>
>>
>> On Fri, Aug 18, 2017 at 8:11 PM, Matthew Johnson 
>> wrote:
>>
>>>
>>>
>>> Sent from my iPad
>>>
>>> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu  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.
>>>
>>
>> Sorry, how does the presence or absence of typed throws play into this?
>>
>>
>> It provides a convenient way to drive an error conversion mechanism
>> during propagation, whether in a library function used to wrap the throwing
>> expression or ideally with language support.  If I call a function that
>> throws FooError and my function throws BarError and we have a way to go
>> from FooError to BarError we can invoke that conversion without needing to
>> catch and rethrow the wrapped error.
>>
>
> But isn't that an argument *against* typed errors? You need this
> language-level support to automatically convert FooErrors to BarErrors
> *because* you've restricted yourself to throwing BarErrors and the function
> you call is restricted to throwing FooErrors. Currently, without typed
> errors, there is no need to convert a FooError to a BarError.
>
>
> No, this is a misunderstanding of the point of the conversion.  In that
> example, the point of performing a conversion is not because the types are
> arbitrarily chosen. It is because the initializer of BarError includes an
> algorithm that categorizes errors.  It may place different values of
> FooError into different cases.  What I am after is language-level support
> for categorizing errors during propagation and making the categories easily
> visible to anyone who looks at the signature of a function that chooses to
> categorize its errors.  Using types and the initializer is one way (the
> most obvious way) to do this.
>
>
> As mentioned above, it's difficult even internally to design a single
> ontology of errors that works throughout a library, so compiler support for
> typed errors would be tantamount to a compiler-enforced facility that
> pervasively requires this laborious classification and re-classification of
> errrors whenever a function rethrows, much of which may be ultimately
> unnecessary.  In other words, if you are a library vendor and wrap every
> FooError from 

Re: [swift-evolution] typed throws

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


Sent from my iPad

> On Aug 19, 2017, at 12:43 PM, Xiaodi Wu  wrote:
> 
> 
>> On Sat, Aug 19, 2017 at 08:29 Matthew Johnson  wrote:
>> 
>> 
>> Sent from my iPad
>> 
>>> On Aug 18, 2017, at 9:19 PM, Xiaodi Wu  wrote:
>>> 
>>> 
>>> 
 On Fri, Aug 18, 2017 at 8:11 PM, Matthew Johnson  
 wrote:
 
 
 Sent from my iPad
 
> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu  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.  
>>> 
>>> Sorry, how does the presence or absence of typed throws play into this?
>> 
>> It provides a convenient way to drive an error conversion mechanism during 
>> propagation, whether in a library function used to wrap the throwing 
>> expression or ideally with language support.  If I call a function that 
>> throws FooError and my function throws BarError and we have a way to go from 
>> FooError to BarError we can invoke that conversion without needing to catch 
>> and rethrow the wrapped error.  
> 
> But isn't that an argument *against* typed errors? You need this 
> language-level support to automatically convert FooErrors to BarErrors 
> *because* you've restricted yourself to throwing BarErrors and the function 
> you call is restricted to throwing FooErrors. Currently, without typed 
> errors, there is no need to convert a FooError to a BarError.

No, this is a misunderstanding of the point of the conversion.  In that 
example, the point of performing a conversion is not because the types are 
arbitrarily chosen. It is because the initializer of BarError includes an 
algorithm that categorizes errors.  It may place different values of FooError 
into different cases.  What I am after is language-level support for 
categorizing errors during propagation and making the categories easily visible 
to anyone who looks at the signature of a function that chooses to categorize 
its errors.  Using types and the initializer is one way (the most obvious way) 
to do this.

> 
> As mentioned above, it's difficult even internally to design a single 
> ontology of errors that works throughout a library, so compiler support for 
> typed errors would be tantamount to a compiler-enforced facility that 
> pervasively requires this laborious classification and re-classification of 
> errrors whenever a function rethrows, much of which may be ultimately 

Re: [swift-evolution] typed throws

2017-08-19 Thread Xiaodi Wu via swift-evolution
On Sat, Aug 19, 2017 at 08:29 Matthew Johnson 
wrote:

>
>
> Sent from my iPad
>
> On Aug 18, 2017, at 9:19 PM, Xiaodi Wu  wrote:
>
>
>
> On Fri, Aug 18, 2017 at 8:11 PM, Matthew Johnson 
> wrote:
>
>>
>>
>> Sent from my iPad
>>
>> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu  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.
>>
>
> Sorry, how does the presence or absence of typed throws play into this?
>
>
> It provides a convenient way to drive an error conversion mechanism during
> propagation, whether in a library function used to wrap the throwing
> expression or ideally with language support.  If I call a function that
> throws FooError and my function throws BarError and we have a way to go
> from FooError to BarError we can invoke that conversion without needing to
> catch and rethrow the wrapped error.
>

But isn't that an argument *against* typed errors? You need this
language-level support to automatically convert FooErrors to BarErrors
*because* you've restricted yourself to throwing BarErrors and the function
you call is restricted to throwing FooErrors. Currently, without typed
errors, there is no need to convert a FooError to a BarError.

As mentioned above, it's difficult even internally to design a single
ontology of errors that works throughout a library, so compiler support for
typed errors would be tantamount to a compiler-enforced facility that
pervasively requires this laborious classification and re-classification of
errrors whenever a function rethrows, much of which may be ultimately
unnecessary. In other words, if you are a library vendor and wrap every
FooError from an upstream dependency into a BarError, your user is still
likely to have their own classification of errors and decide to handle
different groups of BarError cases differently anyway, so what was the
point of your laborious conversion of FooErrors to BarErrors?

It also provides convenient documentation of the categorization along with
> a straightforward way to match the cases (with code completion as Chris
> pointed out).  IMO, making this information immediately clear and with easy
> matching at call sites is crucial to improving how people handle errors in
> practice.
>

Again, I don't see documentation as a sufficient argument for this feature;
there is no reason why the Swift compiler could not extract comprehensive
information about what errors are thrown at compile time without typed
errors--and with more granularity than can be documented via types (since
only specific enum cases may ever be thrown in a particular function).

Error 

Re: [swift-evolution] typed throws

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


Sent from my iPad

> On Aug 18, 2017, at 9:19 PM, Xiaodi Wu  wrote:
> 
> 
> 
>> On Fri, Aug 18, 2017 at 8:11 PM, Matthew Johnson  
>> wrote:
>> 
>> 
>> Sent from my iPad
>> 
>>> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu  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.  
> 
> Sorry, how does the presence or absence of typed throws play into this?

It provides a convenient way to drive an error conversion mechanism during 
propagation, whether in a library function used to wrap the throwing expression 
or ideally with language support.  If I call a function that throws FooError 
and my function throws BarError and we have a way to go from FooError to 
BarError we can invoke that conversion without needing to catch and rethrow the 
wrapped error.  

It also provides convenient documentation of the categorization along with a 
straightforward way to match the cases (with code completion as Chris pointed 
out).  IMO, making this information immediately clear and with easy matching at 
call sites is crucial to improving how people handle errors in practice.  

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.  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, 

Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution
> On Aug 19, 2017, at 12:25 AM, John McCall via swift-evolution 
>  wrote:
>> On Aug 18, 2017, at 11:43 PM, Mark Lilback > > wrote:
>> 
>>> 
>>> On Aug 18, 2017, at 2:27 AM, John McCall via swift-evolution 
>>> > wrote:
>>> 
>>> 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.
>> 
>> We're doing it in the project I'm working on. Sure, there are some places 
>> where we just log the error. But the vast majority of the time, we're 
>> handling them. Maybe that's because we're using reactive programming and 
>> errors bubble to the top, so there's no need to write that many error 
>> handlers. And if I am just logging, either the error doesn't really matter 
>> or there is a TODO label reminding me to fix it at some point.
> 
> I'm not saying people only log errors instead of handling them in some more 
> reasonable way.  I'm saying that logging functions are the only place I've 
> ever seen someone switch over an entire error type.
> 
> I keep bringing exhaustive switches up because, as soon as you have a default 
> case, it seems to me that you haven't really lost anything vs. starting from 
> an opaque type like Error.
> 
>>> On Aug 18, 2017, at 3:11 PM, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> The primary goal for me personally is to factor out and centralize code 
>>> that categorizes an error, allowing catch sites to focus on implementing 
>>> recovery instead of figuring out what went wrong.  Here’s some concrete 
>>> sample code building on the example scenario above:
>> 
>> I'm using a similar approach. Here is some stripped down code:
>> 
>> //error object used throughout project
>> public struct Rc2Error: LocalizedError, CustomStringConvertible, 
>> CustomDebugStringConvertible {
>>  /// basic categories of errors
>>  public enum Rc2ErrorType: String, Error {
>>  /// a requested object was not found
>>  case noSuchElement
>>  /// a requested operation is already in progress
>>  case alreadyInProgress
>>  /// problem parsing json, Freddy error is nested
>>  case invalidJson
>>  /// nestedError will be the NSError 
>>  case cocoa 
>>  /// nested error is related to the file system 
>>  case file 
>>  /// a wrapped error from a websocket 
>>  case websocket 
>>  /// a generic network error 
>>  case network 
>>  /// an invalid argument was passed (or parsed from json)
>>  /// wraps an unknown error
>>  case unknown
>>  }
>> 
>>  /// the generic type of the error
>>  public let type: Rc2ErrorType
>>  /// the underlying error that caused the problem
>>  public let nestedError: Error?
>>  /// location in source code of where error happened
>>  public let location: String
>> }
> 
> Okay.  I mean, this seems essentially like Swift's Error design.  The comment 
> says you use this type ubiquitously in your project.  The type completely 
> erases any differences between functions in terms of what errors they can 
> throw.  Predictably, it includes an unknown case.  Code that processes values 
> of this type must look essentially exactly like switching over an Error, 
> except that the unknown case involves explicitly matching '.unknown' instead 
> of using 'default'.
> 
>> //a domain-specific error type that will be nested
>> public enum NetworkingError {
>>  case unauthorized
>>  case unsupportedFileType
>>  case timeout
>>  case connectionError(Error)
>>  case canceled
>>  case uploadFailed(Error)
>>  case invalidHttpStatusCode(HTTPURLResponse)
>>  case restError(code: Int, message: String)
>> }
> 
> Okay.  So you're doing semantic tagging of errors — you're communicating out 
> that an error arose during a specific operation.  And having some static 
> enforcement here makes it easier to ensure that you've tagged all the errors.
> 
>> The most common errors don't need a nested error. The call site can figure 
>> out how to recover based on this. Using Result I can specifically limit 
>> what kind of errors are possible from a function without using the wrapper 
>> error. E can always be specified as Error to ignore the typed system.
> 
> I see.  So you do have some functions that use a more specific type.
> 
>> It would be great if the native swift error system 

Re: [swift-evolution] typed throws

2017-08-18 Thread David Waite via swift-evolution
> 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.
> - Some people think that while it might be useful in some narrow cases, the 
> utility isn’t high enough to justify making the language more complex 
> (complexity that would intrude on the APIs of result types, futures, etc)

I actually can’t think of anything other than details to add to this synopsis. 

I personally think even for internal usage, errors remain very hard to neatly 
categorize into an ontology, and it is very difficult to have a single ontology 
for all usage. For internal usage, you at least have the ability to evolve your 
usage when you discover the problems, but the weight of typed throws as part of 
function/method types doesn’t seem worth a compiler-enforced exhaustive catch 
to me.

Attempting to categorize errors using a concrete error type can’t help but push 
the complexity of errors down via nested errors (e.g. “The JSON failed to parse 
- but was it due to data corruption, or transient network failure?”). Java’s 
multi-page nested exception traces are a side effect of attempting to corral 
exceptional cases using the type system - I think Swift has benefit of 
retroactive protocol conformance which would keep it from getting Java-level 
bad (see jgroff’s example), but I still don’t think people who want clear 
documentation or exhaustive catches want to have to dive through a hierarchy of 
nested errors to try to determine the root cause.

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


Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution

> On Aug 18, 2017, at 11:43 PM, Mark Lilback  wrote:
> 
>> 
>> On Aug 18, 2017, at 2:27 AM, John McCall via swift-evolution 
>>  wrote:
>> 
>> 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.
> 
> We're doing it in the project I'm working on. Sure, there are some places 
> where we just log the error. But the vast majority of the time, we're 
> handling them. Maybe that's because we're using reactive programming and 
> errors bubble to the top, so there's no need to write that many error 
> handlers. And if I am just logging, either the error doesn't really matter or 
> there is a TODO label reminding me to fix it at some point.

I'm not saying people only log errors instead of handling them in some more 
reasonable way.  I'm saying that logging functions are the only place I've ever 
seen someone switch over an entire error type.

I keep bringing exhaustive switches up because, as soon as you have a default 
case, it seems to me that you haven't really lost anything vs. starting from an 
opaque type like Error.

>> On Aug 18, 2017, at 3:11 PM, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> The primary goal for me personally is to factor out and centralize code that 
>> categorizes an error, allowing catch sites to focus on implementing recovery 
>> instead of figuring out what went wrong.  Here’s some concrete sample code 
>> building on the example scenario above:
> 
> I'm using a similar approach. Here is some stripped down code:
> 
> //error object used throughout project
> public struct Rc2Error: LocalizedError, CustomStringConvertible, 
> CustomDebugStringConvertible {
>   /// basic categories of errors
>   public enum Rc2ErrorType: String, Error {
>   /// a requested object was not found
>   case noSuchElement
>   /// a requested operation is already in progress
>   case alreadyInProgress
>   /// problem parsing json, Freddy error is nested
>   case invalidJson
>   /// nestedError will be the NSError 
>   case cocoa 
>   /// nested error is related to the file system 
>   case file 
>   /// a wrapped error from a websocket 
>   case websocket 
>   /// a generic network error 
>   case network 
>   /// an invalid argument was passed (or parsed from json)
>   /// wraps an unknown error
>   case unknown
>   }
> 
>   /// the generic type of the error
>   public let type: Rc2ErrorType
>   /// the underlying error that caused the problem
>   public let nestedError: Error?
>   /// location in source code of where error happened
>   public let location: String
> }

Okay.  I mean, this seems essentially like Swift's Error design.  The comment 
says you use this type ubiquitously in your project.  The type completely 
erases any differences between functions in terms of what errors they can 
throw.  Predictably, it includes an unknown case.  Code that processes values 
of this type must look essentially exactly like switching over an Error, except 
that the unknown case involves explicitly matching '.unknown' instead of using 
'default'.

> //a domain-specific error type that will be nested
> public enum NetworkingError {
>   case unauthorized
>   case unsupportedFileType
>   case timeout
>   case connectionError(Error)
>   case canceled
>   case uploadFailed(Error)
>   case invalidHttpStatusCode(HTTPURLResponse)
>   case restError(code: Int, message: String)
> }

Okay.  So you're doing semantic tagging of errors — you're communicating out 
that an error arose during a specific operation.  And having some static 
enforcement here makes it easier to ensure that you've tagged all the errors.

> The most common errors don't need a nested error. The call site can figure 
> out how to recover based on this. Using Result I can specifically limit 
> what kind of errors are possible from a function without using the wrapper 
> error. E can always be specified as Error to ignore the typed system.

I see.  So you do have some functions that use a more specific type.

> It would be great if the native swift error system let you optionally put 
> compiler-enforced constraints on what kind of error can be thrown. Then I can 
> setup handlers for my specific type of error, but the compiler will give an 
> error/warning if I'm not handling a possible Error. A generic catch-all 

Re: [swift-evolution] typed throws

2017-08-18 Thread Chris Lattner via swift-evolution
On Aug 17, 2017, at 11:27 PM, John McCall  wrote:
> 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 won’t make any claims about what people say to you, but there are other 
benefits of course.  Even if you don’t *exhaustively* catch your errors, it is 
still useful to get code completion for the error cases that you do intend to 
handle (covering the rest with a "catch {“).

Throwing a resilient enum is actually a rather defensible way to handle this, 
since clients will be expected to have a default, and the implementation is 
allowed to add new cases.

> Programmers often have an instinct to obsess over error taxonomies that is 
> very rarely directed at solving any real problem; it is just self-imposed 
> busy-work.

Indeed, no denying that.

>> One thing that I’m personally very concerned about is in the systems 
>> programming domain.  Systems code is sort of the classic example of code 
>> that is low-level enough and finely specified enough that there are lots of 
>> knowable things, including the failure modes.
> 
> Here we are using "systems" to mean "embedded systems and kernels".  And 
> frankly even a kernel is a large enough system that they don't want to 
> exhaustively switch over failures; they just want the static guarantees that 
> go along with a constrained error type.

I think you’re over focusing on exhaustively handling cases.  If you use errno 
as one poor proxy for what kernels care about, it is totally reasonable to 
handle a few of the errors produced by a call (EAGAIN, EINTR are two common 
examples), but not all of them.  It is useful to get code completion on enum 
members, and it is also useful to get an indication from a compiler that 
something can/will never be thrown.  You give up both with full type erasure.

>> 
>> JohnMC has some ideas on how to change code generation for ‘throws’ to avoid 
>> this problem, but I don’t understand his ideas enough to know if they are 
>> practical and likely to happen or not.
> 
> Essentially, you give Error a tagged-pointer representation to allow 
> payload-less errors on non-generic error types to be allocated globally, and 
> then you can (1) tell people to not throw errors that require allocation if 
> it's vital to avoid allocation (just like we would tell them today not to 
> construct classes or indirect enum cases) and (2) allow a special global 
> payload-less error to be substituted if error allocation fails.
> 
> Of course, we could also say that systems code is required to use a 
> typed-throws feature that we add down the line for their purposes.  Or just 
> tell them to not use payloads.  Or force them to constrain their error types 
> to fit within some given size.  (Note that obsessive error taxonomies tend to 
> end up with a bunch of indirect enum cases anyway, because they get 
> recursive, so the allocation problem is very real whatever we do.)

The issue isn’t allocation that can fail, it is the fact that allocation runs 
in nondeterministic time even when it succeeds.  This is highly problematic for 
realtime systems.

Your answer basically says to me that you’re ok with offering a vastly limited 
programming model to people who care about realtime guarantees, and that gives 
up performance needlessly even in use-cases that probably care about low level 
perf.  I agree that it would not be the end of the world (that would be for 
systems programmers to have to keep using C :-), but it certainly falls short 
of the best possible system that we could build.

-Chris

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


Re: [swift-evolution] typed throws

2017-08-18 Thread Mark Lilback via swift-evolution
> 
> On Aug 18, 2017, at 2:27 AM, John McCall via swift-evolution 
>  wrote:
> 
> 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.

We're doing it in the project I'm working on. Sure, there are some places where 
we just log the error. But the vast majority of the time, we're handling them. 
Maybe that's because we're using reactive programming and errors bubble to the 
top, so there's no need to write that many error handlers. And if I am just 
logging, either the error doesn't really matter or there is a TODO label 
reminding me to fix it at some point.

> On Aug 18, 2017, at 3:11 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> The primary goal for me personally is to factor out and centralize code that 
> categorizes an error, allowing catch sites to focus on implementing recovery 
> instead of figuring out what went wrong.  Here’s some concrete sample code 
> building on the example scenario above:

I'm using a similar approach. Here is some stripped down code:

//error object used throughout project
public struct Rc2Error: LocalizedError, CustomStringConvertible, 
CustomDebugStringConvertible {
/// basic categories of errors
public enum Rc2ErrorType: String, Error {
/// a requested object was not found
case noSuchElement
/// a requested operation is already in progress
case alreadyInProgress
/// problem parsing json, Freddy error is nested
case invalidJson
/// nestedError will be the NSError 
case cocoa 
/// nested error is related to the file system 
case file 
/// a wrapped error from a websocket 
case websocket 
/// a generic network error 
case network 
/// an invalid argument was passed (or parsed from json)
/// wraps an unknown error
case unknown
}

/// the generic type of the error
public let type: Rc2ErrorType
/// the underlying error that caused the problem
public let nestedError: Error?
/// location in source code of where error happened
public let location: String
}

//a domain-specific error type that will be nested
public enum NetworkingError {
case unauthorized
case unsupportedFileType
case timeout
case connectionError(Error)
case canceled
case uploadFailed(Error)
case invalidHttpStatusCode(HTTPURLResponse)
case restError(code: Int, message: String)
}

The most common errors don't need a nested error. The call site can figure out 
how to recover based on this. Using Result I can specifically limit what 
kind of errors are possible from a function without using the wrapper error. E 
can always be specified as Error to ignore the typed system.

It would be great if the native swift error system let you optionally put 
compiler-enforced constraints on what kind of error can be thrown. Then I can 
setup handlers for my specific type of error, but the compiler will give an 
error/warning if I'm not handling a possible Error. A generic catch-all is not 
proper error handling. And if I'm calling something that doesn't throw 
type-constrained errors, I can use a generic handler and wrap it up in my own 
error. But the call site is getting details necessary to recover (if possible) 
without having to use the runtime to figure out what kind of error it is.

I've got a very efficient system set up right now with great error handling. I 
don't see why the same capability can't exist in the language, especially when 
you can choose to completely ignore it. Hopefully more people would use it and 
we'd stop seeing so many "unknown error" dialogs.

- Mark




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


Re: [swift-evolution] typed throws

2017-08-18 Thread Xiaodi Wu via swift-evolution
On Fri, Aug 18, 2017 at 8:11 PM, Matthew Johnson 
wrote:

>
>
> Sent from my iPad
>
> On Aug 18, 2017, at 6:56 PM, Xiaodi Wu  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.
>

Sorry, how does the presence or absence of typed throws play into this?


> 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 
> wrote:
>
>>
>> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu  wrote:
>>
>> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson 
>>  wrote:
>>
>>>
>>> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu  wrote:
>>>
>>> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution <
>>> 

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  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  
>> wrote:
>> 
>>> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu  wrote:
>>> 
 On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson  
 wrote:
 
> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu  wrote:
> 
>> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
>>  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 
>> >>> 

Re: [swift-evolution] typed throws

2017-08-18 Thread Xiaodi Wu via swift-evolution
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)
}


On Fri, Aug 18, 2017 at 6:46 PM, Matthew Johnson 
wrote:

>
> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu  wrote:
>
> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson 
> wrote:
>
>>
>> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu  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  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 
>>> 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 

Re: [swift-evolution] typed throws

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

> On Aug 18, 2017, at 6:29 PM, Xiaodi Wu  wrote:
> 
> On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson  > wrote:
> 
>> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu > > wrote:
>> 
>> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
>> > 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 

Re: [swift-evolution] typed throws

2017-08-18 Thread Xiaodi Wu via swift-evolution
On Fri, Aug 18, 2017 at 6:19 PM, Matthew Johnson 
wrote:

>
> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu  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  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 
>> 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 hopes 

Re: [swift-evolution] typed throws

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

> On Aug 18, 2017, at 6:15 PM, Xiaodi Wu  wrote:
> 
> On Fri, Aug 18, 2017 at 09:20 Matthew Johnson via swift-evolution 
> > 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 

Re: [swift-evolution] typed throws

2017-08-18 Thread Xiaodi Wu via swift-evolution
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  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 
> 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 hopes that the
> problem was somewhere else and this parse will succeed.
>
> All of this can obviously be accomplished with untyped errors.  That said,
> using types to categorize errors would significantly improve the clarity of
> such code.  More 

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 Joe Groff via swift-evolution

> On Aug 18, 2017, at 11:09 AM, John McCall via swift-evolution 
>  wrote:
> 
>> I think you're right that wrapping errors is tightly related to an effective 
>> use of typed errors.  You can do a reasonable job without language support 
>> (as has been discussed on the list in the past).  On the other hand, if 
>> we're going to introduce typed errors we should do it in a way that 
>> *encourages* effective use of them. My opinion is that encouraging effect 
>> use means categorizing (wrapping) errors without requiring any additional 
>> syntax beyond the simple `try` used by untyped errors.  In practice, this 
>> means we should not need to catch and rethrow an error if all we want to do 
>> is categorize it.  Rust provides good prior art in this area.
> 
> Yes, the ability to translate errors between domains is definitely something 
> we could work on, whether we have typed errors or not.

The Rust approach of automatically wrapping errors when you "cross domains", so 
to speak, has the disadvantage you've observed before that the layers of 
wrapping can obscure the structure of the underlying error when you're trying 
to ferret out and handle a particular form of failure mode. 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 thi
 s:

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)
}

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


Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution
> On Aug 18, 2017, at 4:40 AM, Gwendal Roué  wrote:
> Hello all,
> 
> I'm also on the "side" of untyped errors, but I can imagine how other 
> developers may like a stricter error hierarchy. It surely fits some 
> situations.
> 
> Enter Result and Result:
> 
> Since Swift "native" errors don't fit well with asynchronous APIs, various 
> ways to encapsulate them have emerged, most of them eventually relying on 
> some kind of variant of those `Result` type:
> 
>   // Untyped errors
>   enum Result {
>   case success(T)
>   case failure(Error)
>   }
>   
>   // Typed errors
>   enum Result {
>   case success(T)
>   case failure(E)
>   }
> 
> The first Result fits well people who like untyped errors. And Result E> fits people who prefer typed errors. Result is objectively closer to 
> the "spirit" of Swift 2-4. Yet Result has the right to live as well.
> 
> When Swift 5 brings sugar syntax around async/await/etc, most needs for 
> Result will naturally vanish.
> 
> However, the need for Result will remain. The debate about "typed 
> throws", for me, sums up to this question: will the typed folks be able to 
> take profit from the syntax sugar brought by async/await/etc of Swift 5? Or 
> will they have to keep on carrying Result with them?

If I understand correctly, the people really attached to Result often use 
it as a normal result type rather than using the built-in error machinery at 
all.  That is, of course, their right.  If they're doing that, then they can 
have an async function that does that just as well as they can have a non-async 
function.  However, "async" implying "throws" would undermine them to a 
significant extent.

John.

> 
> Gwendal Roué
> 
> 
> 
>> Le 18 août 2017 à 10:23, John McCall via swift-evolution 
>> > a écrit :
>> 
>>> On Aug 18, 2017, at 3:28 AM, Charlie Monroe >> > wrote:
 On Aug 18, 2017, at 8:27 AM, John McCall via swift-evolution 
 > 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 

Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution

> 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 hopes that the problem was 
> somewhere else and this parse will succeed.
> 
> All of this can obviously be accomplished with untyped errors.  That said, 
> using types 

Re: [swift-evolution] typed throws

2017-08-18 Thread Christopher Kornher via swift-evolution

> On Aug 18, 2017, at 7:38 AM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> I would like to reiterate the point I made in the question that spawned this 
> thread: there are *many* Swift libraries for writing async code of various 
> sorts which are *already* using typed errors via `Result Error>`.  We don't have to speculate about how this feature might be used and 
> what kind of benefits might be realized.  We can have a discussion about what 
> people are already doing and determine whether this model should be supported 
> in the async / await world or not.  What do you think of putting a call out 
> to the broader Swift community to bring us concrete examples of how they are 
> benefiting from using typed errors in async code.

I have found this “feature" has been painful to use. I have been forced to wrap 
hetrogenous errors in a custom error type just to satisfy these ill-conceived 
APIs. i have never found any benefit to ```ErrorType: Error``` generic 
parameter. … Any. Ever.

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


Re: [swift-evolution] typed throws

2017-08-18 Thread Michael Ilseman via swift-evolution
Wouldn’t switching from `async` to `async throws` be both a source and ABI 
break for libraries? If so, there is a library evolution argument to `async` 
also encompassing throws as a reasonable default. It's likely that the 
non-throwing-ness of many `async` operations is an artifact of the initial 
implementation rather than deliberate design. Using the more verbose 
`async(non-throwing)` (or even some other keyword `generator|yielding|…`) makes 
it a deliberate API decision rather than an accidental omission.



> On Aug 18, 2017, at 10:05 AM, Joe Groff via swift-evolution 
>  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'.
> 
> -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] 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] typed throws

2017-08-18 Thread Joe Groff via swift-evolution

> 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'.

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


Re: [swift-evolution] typed throws

2017-08-18 Thread Joe Groff via swift-evolution

> On Aug 17, 2017, at 11:27 PM, John McCall via swift-evolution 
>  wrote:
> 
> Essentially, you give Error a tagged-pointer representation to allow 
> payload-less errors on non-generic error types to be allocated globally, and 
> then you can (1) tell people to not throw errors that require allocation if 
> it's vital to avoid allocation (just like we would tell them today not to 
> construct classes or indirect enum cases) and (2) allow a special global 
> payload-less error to be substituted if error allocation fails.
> 
> Of course, we could also say that systems code is required to use a 
> typed-throws feature that we add down the line for their purposes.  Or just 
> tell them to not use payloads.  Or force them to constrain their error types 
> to fit within some given size.  (Note that obsessive error taxonomies tend to 
> end up with a bunch of indirect enum cases anyway, because they get 
> recursive, so the allocation problem is very real whatever we do.)

Alternatively, with some LLVM work, we could have the thrower leave the error 
value on the stack when propagating an error, and make it the catcher's 
responsibility to consume the error value and pop the stack. We could make not 
only errors but existential returns in general more efficient and "systems 
code"-worthy with a technique like that.

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


Re: [swift-evolution] typed throws

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


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 hopes that the problem was 
somewhere else and this parse will succeed.

All of this can obviously be accomplished with untyped errors.  That said, 
using types to categorize errors would significantly improve the clarity of 
such code.  More importantly, I believe that by categorizing errors in ways 
that are most relevant to a specific domain a library (perhaps internal 

Re: [swift-evolution] typed throws

2017-08-18 Thread Johannes Weiß via swift-evolution
Hi John,

tl;dr I think throws should be optionally typed. Ie. `func someSyscall(...) 
throws(POSIXError) -> Int` should be just as legal as `func 
doSomeFancyCocoaOperation() throws -> Void`.

> [...]
>> 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 just grep'ed through some code and what I always see is this:

} catch let e {
fatalError("unexcepted error caught: \(e)")
}

most of the code is fairly low-level and the only error thrown in there is a 
POSIXError which basically holds the errno value and a string describing the 
failed syscall. I find this a very common pattern. Also the IMHO quite 
widespread use of Result types shows that there are valid uses of a typed 
error mechanism. On the other hand requiring a high-level Cocoa method to 
declare all errors doesn't seem right either. So why not optionally typing the 
throws?



> [...]

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


Re: [swift-evolution] typed throws

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


Sent from my iPad

> On Aug 17, 2017, at 11:58 PM, Chris Lattner  wrote:
> 
> Splitting this off into its own thread:

Thanks.  I considered starting a thread but decided to ask about it first in 
case it was considered out of scope for Swift 5. 

> 
>> 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.
> - Some people think that while it might be useful in some narrow cases, the 
> utility isn’t high enough to justify making the language more complex 
> (complexity that would intrude on the APIs of result types, futures, etc)
> 
> I’m sure there are other points in the discussion that I’m forgetting.

To be clear, I don't think anyone is arguing that we should remove the ability 
to simply mark a function `throws` with an implicit error type of `Error`! :) 
This is obviously crucial and would continue to be used in many cases.  One 
important variation of this use case is that with typed errors it is also 
possible to refine `Error` and throw a slightly more specific existential.  
Obviously Apple will continue to use untyped errors in most or all APIs 
regardless of what we do and unannotated `throws` will continue to be the 
shortest syntax.

The topic of Java errors has already been beat to death on the list in the 
past.  I find it unfortunate that the counter-examples (notably Rust) are not 
usually mentioned.  I haven't worked in Java, but my study of this topic in the 
past has convinced me the Java design has some serious flaws that are 
completely avoidable.

I would like to reiterate the point I made in the question that spawned this 
thread: there are *many* Swift libraries for writing async code of various 
sorts which are *already* using typed errors via `Result`.  We don't have to speculate about how this feature might be used and 
what kind of benefits might be realized.  We can have a discussion about what 
people are already doing and determine whether this model should be supported 
in the async / await world or not.  What do you think of putting a call out to 
the broader Swift community to bring us concrete examples of how they are 
benefiting from using typed errors in async code.

If we decide it should be, typed errors for synchronous code naturally follows. 
 If we decide it shouldn't we have to be prepared for some noise about the 
unfortunate tradeoff developers will face between using async / await or 
continuing (pun not intended) to use explicit continuations and typed errors.  
I suspect most people would move to async / await and live with untyped errors 
(we don't see a lot of synchronous 

Re: [swift-evolution] typed throws

2017-08-18 Thread Tino Heth via swift-evolution
> There's no reason we couldn't do some tooling work to expose emergent 
> information about what kinds of errors are thrown by the current 
> implementation of a function, and maybe even check that against the current 
> documentation.  Certainly, it should be possible to document particularly 
> interesting errors that a function might throw.
I'd prefer moving some complicated and controversial questions out of the 
language level, and probably, this might be such a case — but I think the 
preferred syntax would not be "throws(NetworkError, MyError) func mayFail() 
throws", but rather something that looks much more integrated ("func mayFail() 
throws(NetworkError, MyError)")

> I'm just challenging the idea that this should be reflected and enforced in 
> the type system.
Yes, I think this might be a can of worms — just imagine rethrows, where some 
errors will always be caught, so that ultimately, we would steer towards some 
kind of type algebra just for errors...

>> Typed throws could also help to lessen the tight coupling to Objective-C:
>> Being forced to declare conformance to a protocol without requirements or 
>> even public methods feels very awkward to me.
> 
> Error is not about Objective-C interop; we could make the feature work 
> without a protocol, and in fact the protocol alone isn't sufficient for what 
> we try to do with it.  The protocol's value is mostly communicative, a way of 
> making it obvious that a type is meant to be thrown
I guess nearly all uses look like "XYError: Error", so I really don't see much 
value in the protocol; but to me, it always feels a little bit dirty when 
language features are entwined with certain types, so it might be just a 
personal oddity.

>> If people want to build huge lists of possible errors… why not? As long as 
>> I'm still able to write my own throwing functions as today, I'm fine with 
>> that.
> 
> Language features have to meet a higher bar than "why not?".
That was more geared towards something I'd consider as derailed use — but it 
seems we agree that typed throws don't have to be something to bother the 
compiler with.

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


Re: [swift-evolution] typed throws

2017-08-18 Thread Charlie Monroe via swift-evolution

> On Aug 18, 2017, at 10:22 AM, John McCall  wrote:
> 
>> On Aug 18, 2017, at 3:28 AM, Charlie Monroe > > wrote:
>>> On Aug 18, 2017, at 8:27 AM, John McCall via swift-evolution 
>>> > 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.
>> 
>> The issue I see here with non-typed errors is that relying on documentation 
>> is very error-prone. I'll give an example where I've used exhaustive error 
>> catching (but then again, I was generally the only one using exhaustive enum 
>> switches when we discussed those). I've made a simple library for reporting 
>> purchases to a server. The report needs to be signed using a certificate and 
>> there are some validations to be made.
>> 
>> This generally divides the errors into three logical areas - initialization 
>> (e.g. errors when loading the certificate, etc.), validation (when the 
>> document doesn't pass validation) and sending (network error, error response 
>> from the server, etc.).
>> 
>> Instead of using a large error enum, I've split this into three enums. At 
>> this point, especially for a newcommer to the code, he may not realize which 
>> method can throw which of these error enums.
>> 
>> I've found that the app can take advantage of knowing what's wrong. For 
>> example, if some required information is missing e.g. 
>> Validation.subjectNameMissing is thrown. In such case the application can 
>> inform the user that name is missing and it can offer to open UI to enter 
>> this information (in the case of my app, the UI for sending is in the 
>> document view, while the mentioned "subject name" information is in 
>> Preferences).
>> 
>> 

Re: [swift-evolution] typed throws

2017-08-18 Thread Gwendal Roué via swift-evolution
Hello all,

I'm also on the "side" of untyped errors, but I can imagine how other 
developers may like a stricter error hierarchy. It surely fits some situations.

Enter Result and Result:

Since Swift "native" errors don't fit well with asynchronous APIs, various ways 
to encapsulate them have emerged, most of them eventually relying on some kind 
of variant of those `Result` type:

// Untyped errors
enum Result {
case success(T)
case failure(Error)
}

// Typed errors
enum Result {
case success(T)
case failure(E)
}

The first Result fits well people who like untyped errors. And Result 
fits people who prefer typed errors. Result is objectively closer to the 
"spirit" of Swift 2-4. Yet Result has the right to live as well.

When Swift 5 brings sugar syntax around async/await/etc, most needs for 
Result will naturally vanish.

However, the need for Result will remain. The debate about "typed 
throws", for me, sums up to this question: will the typed folks be able to take 
profit from the syntax sugar brought by async/await/etc of Swift 5? Or will 
they have to keep on carrying Result with them?

Gwendal Roué



> Le 18 août 2017 à 10:23, John McCall via swift-evolution 
>  a écrit :
> 
>> On Aug 18, 2017, at 3:28 AM, Charlie Monroe > > wrote:
>>> On Aug 18, 2017, at 8:27 AM, John McCall via swift-evolution 
>>> > 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.
>> 
>> The issue I see here with non-typed errors is that relying on 

Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution
> On Aug 18, 2017, at 3:28 AM, Charlie Monroe  wrote:
>> On Aug 18, 2017, at 8:27 AM, John McCall via swift-evolution 
>>  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.
> 
> The issue I see here with non-typed errors is that relying on documentation 
> is very error-prone. I'll give an example where I've used exhaustive error 
> catching (but then again, I was generally the only one using exhaustive enum 
> switches when we discussed those). I've made a simple library for reporting 
> purchases to a server. The report needs to be signed using a certificate and 
> there are some validations to be made.
> 
> This generally divides the errors into three logical areas - initialization 
> (e.g. errors when loading the certificate, etc.), validation (when the 
> document doesn't pass validation) and sending (network error, error response 
> from the server, etc.).
> 
> Instead of using a large error enum, I've split this into three enums. At 
> this point, especially for a newcommer to the code, he may not realize which 
> method can throw which of these error enums.
> 
> I've found that the app can take advantage of knowing what's wrong. For 
> example, if some required information is missing e.g. 
> Validation.subjectNameMissing is thrown. In such case the application can 
> inform the user that name is missing and it can offer to open UI to enter 
> this information (in the case of my app, the UI for sending is in the 
> document view, while the mentioned "subject name" information is in 
> Preferences).
> 
> This way I exhaustively switch over the error enums, suggesting to the user 
> solution of the particular problem without dumbing down to a message "Oops, 
> something went wrong, but I have no idea what because this kind of error is 
> not handled.".

Surely you must have a message like that.  You're 

Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution

> On Aug 18, 2017, at 3:24 AM, Tino Heth <2...@gmx.de> wrote:
> 
> 
>> 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 think the aspect of documentation shouldn't be underestimated:
> People want to know what might go wrong — even if they have only a single 
> reaction to all cases at their disposal.

There's no reason we couldn't do some tooling work to expose emergent 
information about what kinds of errors are thrown by the current implementation 
of a function, and maybe even check that against the current documentation.  
Certainly, it should be possible to document particularly interesting errors 
that a function might throw.  I'm just challenging the idea that this should be 
reflected and enforced in the type system.

> Typed throws could also help to lessen the tight coupling to Objective-C:
> Being forced to declare conformance to a protocol without requirements or 
> even public methods feels very awkward to me.

Error is not about Objective-C interop; we could make the feature work without 
a protocol, and in fact the protocol alone isn't sufficient for what we try to 
do with it.  The protocol's value is mostly communicative, a way of making it 
obvious that a type is meant to be thrown, as well as to verify that you aren't 
accidentally throwing something nonsensical.

It also gives us a hook to add defaulted requirements in a later release.

> In some way, throws are typed already, but there's just one type allowed, and 
> it can't be changed.
> 
> Imho the big problem of the whole topic is the bad experience people had with 
> typed throws in Java; I don't see a problem in adding typed throws and 
> keeping Error as default type to be thrown if nothing else is specified.

The problems people have with typed throws in Java aren't ultimately because of 
some specific failure of Java (although there are certainly ways in which 
Java's design could be better in my opinion).  They pretty much all arise 
directly from conceptual problems with the idea of "restricted" sets of errors.

> If people want to build huge lists of possible errors… why not? As long as 
> I'm still able to write my own throwing functions as today, I'm fine with 
> that.

Language features have to meet a higher bar than "why not?".

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


Re: [swift-evolution] typed throws

2017-08-18 Thread Charlie Monroe via swift-evolution

> On Aug 18, 2017, at 8:27 AM, John McCall via swift-evolution 
>  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.

The issue I see here with non-typed errors is that relying on documentation is 
very error-prone. I'll give an example where I've used exhaustive error 
catching (but then again, I was generally the only one using exhaustive enum 
switches when we discussed those). I've made a simple library for reporting 
purchases to a server. The report needs to be signed using a certificate and 
there are some validations to be made.

This generally divides the errors into three logical areas - initialization 
(e.g. errors when loading the certificate, etc.), validation (when the document 
doesn't pass validation) and sending (network error, error response from the 
server, etc.).

Instead of using a large error enum, I've split this into three enums. At this 
point, especially for a newcommer to the code, he may not realize which method 
can throw which of these error enums.

I've found that the app can take advantage of knowing what's wrong. For 
example, if some required information is missing e.g. 
Validation.subjectNameMissing is thrown. In such case the application can 
inform the user that name is missing and it can offer to open UI to enter this 
information (in the case of my app, the UI for sending is in the document view, 
while the mentioned "subject name" information is in Preferences).

This way I exhaustively switch over the error enums, suggesting to the user 
solution of the particular problem without dumbing down to a message "Oops, 
something went wrong, but I have no idea what because this kind of error is not 
handled.".

Alternatives I've considered:

- wrapping all the errors into an "Error" enum which would switch over type of 
the error, which is not a great solution as in some cases you only throw one 
type of error
- I could throw some error that only contains 

Re: [swift-evolution] typed throws

2017-08-18 Thread Tino Heth via swift-evolution

> 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 think the aspect of documentation shouldn't be underestimated:
People want to know what might go wrong — even if they have only a single 
reaction to all cases at their disposal.

Typed throws could also help to lessen the tight coupling to Objective-C:
Being forced to declare conformance to a protocol without requirements or even 
public methods feels very awkward to me.
In some way, throws are typed already, but there's just one type allowed, and 
it can't be changed.

Imho the big problem of the whole topic is the bad experience people had with 
typed throws in Java; I don't see a problem in adding typed throws and keeping 
Error as default type to be thrown if nothing else is specified.

If people want to build huge lists of possible errors… why not? As long as I'm 
still able to write my own throwing functions as today, I'm fine with that.

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


Re: [swift-evolution] typed throws

2017-08-18 Thread John McCall via swift-evolution
> 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.

Sometimes we then go on to have a conversation about wrapping errors in other 
error types, and that can be interesting, but now we're talking about adding a 
big, messy feature just to get "safety" guarantees for a fairly minor need.

Programmers often have an instinct to obsess over error taxonomies that is very 
rarely directed at solving any real problem; it is just self-imposed busy-work.

> - Some people think that while it might be useful in some narrow cases, the 
> utility isn’t high enough to justify making the language more complex 
> (complexity that would intrude on the APIs of result types, futures, etc)
> 
> I’m sure there are other points in the discussion that I’m forgetting.
> 
> One thing that I’m personally very concerned about is in the systems 
> programming domain.  Systems code is sort of the classic example of code that 
> is low-level enough and finely specified enough that there are lots of 
> knowable things, including the failure modes.

Here we are using "systems" to mean "embedded systems and kernels".  And 
frankly even a kernel is a large enough system that they don't want to 
exhaustively switch over failures; they just want the static guarantees that go 
along with a constrained error type.

> Beyond expressivity though, our current model involves boxing thrown values 
> into an Error existential, something that forces an implicit memory 
> allocation when the value is large.  Unless this is fixed, I’m very concerned 
> that we’ll end up with a situation where certain kinds of systems code (i.e., 
> that which cares about real time guarantees) will not be able to use error 
> handling at all.  
> 
> JohnMC has some ideas on how to change code generation for ‘throws’ to avoid 
> this problem, but I don’t understand his ideas enough to know if they are 
> practical and likely to happen or not.

Essentially, you give Error a tagged-pointer representation to allow 
payload-less errors on non-generic error types 

Re: [swift-evolution] typed throws

2017-08-17 Thread Chris Lattner via swift-evolution
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.
- Some people think that while it might be useful in some narrow cases, the 
utility isn’t high enough to justify making the language more complex 
(complexity that would intrude on the APIs of result types, futures, etc)

I’m sure there are other points in the discussion that I’m forgetting.

One thing that I’m personally very concerned about is in the systems 
programming domain.  Systems code is sort of the classic example of code that 
is low-level enough and finely specified enough that there are lots of knowable 
things, including the failure modes.  Beyond expressivity though, our current 
model involves boxing thrown values into an Error existential, something that 
forces an implicit memory allocation when the value is large.  Unless this is 
fixed, I’m very concerned that we’ll end up with a situation where certain 
kinds of systems code (i.e., that which cares about real time guarantees) will 
not be able to use error handling at all.  

JohnMC has some ideas on how to change code generation for ‘throws’ to avoid 
this problem, but I don’t understand his ideas enough to know if they are 
practical and likely to happen or not.

-Chris


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