[swift-evolution] [Pitch] Typed throws

John McCall rjmccall at apple.com
Tue Feb 21 01:12:27 CST 2017

> On Feb 20, 2017, at 6:04 PM, Chris Lattner <clattner at nondot.org> wrote:
>> On Feb 20, 2017, at 9:57 AM, John McCall via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> On Feb 19, 2017, at 3:04 PM, Anton Zhilin via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at 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.
> As you know, I still think that adding typed throws is the right thing to do.  I understand your concern about “the feature could be misused” but the same thing is true about many other language features.

That's fair, but I do think there's an important difference here.  The way I see it, typed-throws is really something of an expert feature, not because it's at all difficult to use, but the reverse: because it's easy to use without really thinking about the consequences.  (And the benefits are pretty subtle, too.)  I'm not saying that we should design it to be hard to use, but I think maybe it shouldn't immediately suggest itself, and it especially shouldn't come across as just a more specific version of throws.

> One thing you didn’t mention is that boxing thrown values in an existential requires allocation in the general case.  This may be unacceptable for some classes of Swift application (in the embedded / deep systems space) or simply undesirable because of the performance implication.

So, the performance implication cuts both ways.  We can design the ABI for typed-throws so that, say, the callee initializes some buffer that's passed into it.  That's an ABI that will kill some potential allocations in deep systems code, no question about it.  But in non-deep-systems code, we generally expect that error types will be resilient, which means that there are non-zero dynamic costs for allocating space on the stack for the error.  (You can trade code size for performance, but the slow path is a function call to trigger the runtime layout of the type plus a couple of loads.) That space has to be allocated eagerly before the call, so it's paid even in the non-throwing path.  And I can't think of anything we could do to shift that cost to the throw-site without either using a fixed-size buffer, requiring a second stack for the thread, or inventing some crazy CC where stack depth can change dynamically across a call.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170221/27f0efe6/attachment.html>

More information about the swift-evolution mailing list