> On Feb 20, 2017, at 4:15 PM, Joe Groff <jgr...@apple.com> wrote:
>> On Feb 20, 2017, at 9:57 AM, John McCall via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> On Feb 19, 2017, at 3:04 PM, Anton Zhilin via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> It’s expected that if you need resilience, then you will throw an “open” 
>>> enum. Essentially, we pass resilience of typed throws on to those who will 
>>> hopefully establish resilience of enums.
>>> 
>>> If you prefer separate error types, then declare a base protocol for all 
>>> your error types and throw a protocol existential. You won’t even need 
>>> default case in switches, if closed protocols make it into the language.
>>> 
>>> I don’t like any solution that is based on comments. I think that compiler 
>>> should always ignore comments.
>>> 
>> I agree.  And in general, this sort of thing is exactly my core concern 
>> about adding typed throws to the language: I am completely certain that many 
>> programmers will add typed throws annotations because they're programmers 
>> and thus, well, probably a little obsessive/compulsive, and they're trying 
>> to precisely document the behavior of their function without necessarily 
>> thinking about the usefulness of that information for their clients and (if 
>> they're writing a library; and really you should almost always be writing 
>> code as if you're writing a library) whether they're actually willing to 
>> commit to that behavior in their interface.  For those programmers, typed 
>> throws is just going to box them in and force them into anti-patterns in the 
>> long run.
>> 
>> In the vast majority of use-cases, clients are not going to exhaustively 
>> handle all errors — they will always have some generic fall-back.  That is 
>> not pessimism, it's actually the natural result of the complicated world we 
>> live in, where code can fail for a huge host of reasons and most callers 
>> won't have meaningful special-case behavior for all of them.  (On most 
>> operating systems, opening a file or a network connection can fail because 
>> you ran out of file descriptors.  You're seriously telling me that you're 
>> going to add a special case to your error logic for that?)  Go look at the 
>> actual error types that people use in most typed-throws situations and try 
>> to tell me I'm wrong — they probably have like twenty alternatives, and 
>> solidly a quarter or more of them will just be embedding some other 
>> arbitrarily-complex or stringly-typed error value.
> 
> I agree that overly specific API specs are a concern. There's still some 
> documentational benefit to a typed error enum, even if it ultimately ends up 
> containing a catch-all case, since it gives you the ability to also enumerate 
> some number of discrete, realistically handleable cases. Sure, your network 
> request running in an XPC service has infinitely many failure cases due to 
> resource constraints or IPC failure or network chaos, but there's usually 
> some number of domain-specific error cases  too.

I definitely agree with the documentational benefits of declaring interesting 
error cases, and I agree that most libraries will add new domain-specific 
errors, too.  I just don't see the actual benefit to either API authors or 
clients of saying "I will only throw errors that look like *this*" and then 
*this* turns out to be an enum with ten interesting cases, most of which don't 
apply to the specific operation, and a bunch of generic wrapping cases that 
communicate very little; especially not compared to saying "in this interesting 
case I'll throw a FooError.bar" in the documentation.  Especially since it's 
not obvious that *cases* are the right granularity for describing a specific 
kind of domain error, since a case can't be retroactively split into more- and 
less-informative sub-cases without adding language features that only I seem to 
be interested in. :)

> And if we compare the proposed "you get to specify one error enum type" model 
> to, say, Java or C++98's "you get to specify any number of error classes" 
> model, I think that helps steer people away from the most grievous API 
> mistakes in Java land, since instead of listing a closed set of concrete 
> error classes directly in your API signature, you'll list those error cases 
> in your enum definition, and in a resilient world, the enum will be "open" by 
> default to external users, preventing it from being a permanent liability 
> unless the user explicitly opted into closedness.

To be exact, resilience prevents it from being a permanent liability as long as 
you've thought ahead enough to use your own error type.

> In the discussions around Rust's error handling conventions, they recognized 
> this pattern of APIs either raising some number of layer-appropriate errors 
> or carrying forward the failure modes of the layers below them, and they 
> developed a convention for errors wrapping other errors. It would be 
> reasonable to say we should do the same thing as part of the typed errors 
> design. If we were to generalize enum subtyping beyond Optional, that might 
> be one way to go about it, letting an enum wrap its underlying layers' 
> failure cases as subtypes.

I agree that, if we added typed throws, there would be an immediate demand for 
enum subtyping as a way to make remapping less painful.  We'd also want some 
way of allowing users to specify an *explicit* remapping function (presumably a 
case constructor in most cases); this could probably be a library function, 
though.

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

Reply via email to