> 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