I’m pretty sure this is only one line:
func foo() throws { try foo(bar: default()) }
I’m pretty sure this is only one line:
func foo() throws { try foo(bar: default()) }
In that case, then, I think it'll be incumbent upon you to provide the concrete data necessary to convince your readers that this will be of widespread benefit. I, for one, am unconvinced at the moment.
Your example, for instance, shows the error being propagated from a sign-in routine through each database operation, and from there it is surfaced to the user from UI code. Based on that design, the same sign-in error would have to be handled independently by each routine in UI code. This doesn't sound like a very common design pattern, and I'd like to see evidence of its widespread use.
In that case, then, I think it’ll be incumbent upon you to provide the concrete data necessary to convince your readers that this will be of widespread benefit. I, for one, am unconvinced at the moment.
In the case that this becomes a proposal in the Swift 5 window, it will be incumbent on the proposal author(s) to demonstrate that. But I’m unconvinced we’re in that case, given that we lack a proposal or an author and the thread is a few days old. Who knows?
Your example, for instance, shows the error being propagated from a sign-in routine through each database operation, and from there it is surfaced to the user from UI code.
The problem in fact arises because of recursively composing functions that take a similar argument, having an obvious default value that may go wrong at runtime. How wide that intersection is, is a reasonable debate. But I would suggestion function composition, similar arguments, default values, and things that go wrong at runtime are individually “widely used”, so on a prima facie basis I think we’ve cleared the bar to do some design work.
Reviving an old thread. I spoke to some compiler engineers over beer about this and the problem with overloads (and the reason default arguments aren't implemented with them) is combinatorial explosion. Basically, an overload is a distinct function (e.g. with a distinct implementation) and so if we were to generate an overload for each set of arguments we would be producing a large binary. Meanwhile, there is a lot of pressure to keep binary sizes small on iOS, e.g. see recent work on -Os
.
Default arguments, on the other hand, are done in the caller. (I think; there may be a thunk or something on -O0
builds but on -O
it gets inlined into the caller.) The result is that we have a single function body regardless of the argument combinations, and although callers pay some cost to call, it's only paid for combinations that are actually used, which is generally fewer than the semantics support. This is also the underlying reason why assigning a function to a closure variable "collapses" it into the version without default arguments, that version is the only one and the default arguments are a sugar on top (that is not currently supported for closures but arguably ought to be). Anyway.
Due to the combinatorial explosion, solutions along the line of defining implicit overloads for throws / nonthrows will not be viable. The "right" implementation is along the lines of what I originally proposed, e.g. to extend the default arguments model, which is to inline the arguments calculation (and therefore a try
) into callers.
I personally think this is reasonable. There's no syntactic change to the language, just a semantic one that says default argument expressions can throw if the function already throws. (I'd be careful around rethrows
when writing up a formal proposal, though.)