There is another interesting performance consideration for unboxed Result types—they're not ideal for code size when propagated through many frames. Because unboxed Result<T, U>
has a different size and layout for every T
and U
, propagating an error may require reconstructing a new Result
into a different-sized indirect return buffer, or moving back and forth between register and in-memory returns. This is a problem in Rust, where Result is the idiomatic error propagation type; even simple error-propagating code spends a number of instructions moving pieces of Result
s from one buffer to the next:
Swift's throws
avoids these issues by using a uniform boxed representation for Error
, and a special calling convention that makes testing and propagating error results cheap; a Swift function can propagate an error by returning while leaving the existing error value in the error register (r12
on x86-64):
If we anticipate that people will want to use Result
as a propagation mechanism, we many also want to consider whether it should be an indirect enum
, which would give it a uniform representation that can be propagated more inexpensively. This would also give it a fixed layout so that it can be worked with uniformly in unspecialized generic code. The downside would be that constructing a Result would require boxing and allocating.