Pitch: Fix rethrows checking and add rethrows(unsafe)

No, I don't believe so, but you're welcome to take a look at the three examples I linked in the pitch.

This is a non-starter. It would be massively source breaking, and would mean that any function that uses Sequence.map(), just to take one example, would be throws (and your code would be littered with try).

3 Likes

Oh, thanks, I must have misread it before.

This (rethrows(unsafe) or some alternative escape hatch) is great!

I have recently bumped into issues of not being able to use rethrows when implementing our Task related APIs a few times. I forget the exact situation, but usually it takes the form of something like this:

func make(f: @concurrent @escaping () throws -> X) async rethrows -> X { 
 // for whatever reason, need to detach this `f`
  let h = Task.runDetached(f)

  return try await h.get() // I "know" that this will only throw, 
                           // if and only if `f` throws...
                           // but the compiler won't believe me :-)
}

As I understand this proposal, either of those two would allow me to actually keep this make as a rethrows function.

I like either shape proposed to solve this: just "going unchecked" with rethrows(unsafe) or rethrows(unchecked) or the withForwardedThrows also looks fine. Perhaps the special builtin wrapper function is nicer since it's about how the function is implemented, and less about stuffing this info into the type signature...?

The rethrow looks cute, but I wonder if that isn't hiding that this is possible to "hold it wrong".

1 Like

I commented over in your PR:

This would make sense to me—that, or some scoped bridging mechanism to allow an engineer to say "I'm going to call an intermediate function that can't throw an error itself (e.g. because it's @convention(c) ), but which may need to catch an error thrown by the passed closure. Trust me." Which is of course what the new attribute does, but having a with -like function might be better from a readability standpoint (and would allow us to limit the scope of such behaviour to a specific subsection of the rethrowing function's body rather than the whole body.)

If nothing else, we could reserve the @_rethrowsUnchecked attribute for this with -like function only and tell everyone else to call it and not use the attribute directly.

So, in terms of the proposal, I guess I'm suggesting that rather than change rethrows, we have a dedicated stdlib function encapsulating this new behaviour. Possible name: withUnsafeUncheckedThrowingBehavior, withUnsafeRethrowingBehavior, withUncheckedRethrowingBehavior, etc.—something that uses "unsafe" or "unchecked" in its name to strongly imply the operation is unsafe (as rethrows(unsafe) would), but acting as a scope rather than as a keyword so that adopters can explicitly and visibly limit the impact.

(Hopefully the above isn't too jumbled!)

Edit: And I just saw Slava already mentioned a function-based alternative. :)

1 Like

I see this topic has been stale for a long time, but I was wondering what happened to this pitch? I am running into similar issues when wrapping an AsyncSequence and using Task.

1 Like