On Feb 20, 2017, at 11:12 PM, John McCall <[email protected]> wrote:
>> 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.

Yeah, I agree that it will be appealing to people who don’t know better, but 
here’s the thing: the (almost certain) Swift design will prevent the bad thing 
from happening in practice.

Consider the barriers Swift already puts in place to prevent the bad thing 
(declaring an inappropriately narrow explicitly-specified throw signature) from 
happening:

1) First of all, you need to declare a public API.  If it isn’t public, then 
there is no concern at all, you can evolve the implementation and clients 
together.

2) The Second problem depends on the number of errors it can throw.  If there 
is exactly one type of error, the most common way to handle it is by returning 
optional.  If you have one obvious failure mode with a value, then you throw 
that value.  The most common case is where you can throw more than one sort of 
error, and therefore have an enum to describe it.

3) Third, your enum needs to be declared fragile in order to allow clients to 
enumerate their cases specifically.

The third step (having to mark your enum fragile, however it is spelled) is the 
biggest sign that you’re opting into a commitment that you should think really 
hard about.  If folks don’t know that this is a big API commitment, then we 
have bigger problems.


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

Agreed.

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

Proposed solution:  ABI is that the callee takes in a register which is either 
a buffer address to fill in or null.  On error, the callee returns the error 
pointer in a specific register.  If there was a buffer passed in, it uses it, 
otherwise it allocates.

In practice, this allows the compiler to only pre-allocate the buffer when it 
knows the fixed size, otherwise the caller allocates on the heap on demand.

AFAICT, the cost of this API is only a “li rN, 0” in the normal path.

-Chris

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to