[swift-users] Rethrows issue

Jacob Bandes-Storch jtbandes at gmail.com
Sun Dec 31 18:05:35 CST 2017


On Sat, Dec 30, 2017 at 11:35 PM, Nevin Brackett-Rozinsky via swift-users <
swift-users at swift.org> wrote:

> So, I know this doesn’t actually address your issue, but I think it is
> important to clarify that “rethrows” does not guarantee anything about the
> *type* of error thrown by a function. What “rethrows” implies is that the
> function *will not throw* unless at least one of its arguments throws.
>
> In particular, if the argument throws, the outer function can throw *any
> error or none at all*. For example,
>
> enum CatError: Error { case hairball }
> enum DogError: Error { case chasedSkunk }
>
> func foo(_ f: () throws -> Void) rethrows -> Void {
>     do    { try f() }
>     catch { throw CatError.hairball }
> }
>
> do {
>     try foo{ throw DogError.chasedSkunk }
> } catch {
>     print(error)    // hairball
> }
>
> Inside foo’s catch block, it is legal to throw any error, or not throw an
> error at all. But *outside* that catch block foo cannot throw, which is
> causing you consternation.
>
> • • •
>
> I don’t have a good solution for you, but in attempting to find one I
> *did* uncover something which compiles that probably shouldn’t. It seems
> that a “rethrows” function is currently allowed to throw if a *local*
> function throws:
>
> func rethrowing(_ f: () throws -> Void) rethrows -> Void {
>     func localThrowing() throws -> Void { throw CatError.hairball }
>     return try localThrowing()
> }
>

Yikes, that looks bad; worth filing a bug at bugs.swift.org if there isn't
one already.


>
> do {
>     try rethrowing{ throw DogError.chasedSkunk }
> } catch {
>     print(error)    // hairball
> }
>
> I wouldn’t count on this functionality as it is most likely a bug. Indeed,
> if we pass in a non-throwing argument then we get a runtime error:
>
> rethrowing{ return }  // EXC_BAD_ACCESS (code=1, address=0x0)
>
> Although, if we change “localThrowing” to use do/catch on a call to “f”
> and throw only in the catch block, or even use your “var caught: Error?”
> trick, then it appears to work as intended with no problems at runtime.
>
> • • •
>
> In the unlikely scenario that the above local-function behavior is valid
> and intended, the following function will, technically speaking, let you
> work around the issue you’re having:
>
> func withPredicateErrors <Element, Return>
>     (_ predicate: (Element) throws -> Bool,
>      do body: @escaping ((Element) -> Bool) -> Return
>     ) rethrows -> Return
> {
>     func bodyWrapper(_ f: (Element) throws -> Bool) throws -> Return {
>         var caught: Error?
>         let value = body{ elem in
>             do {
>                 return try f(elem)
>             } catch {
>                 caught = error
>                 return true
>             }
>         }
>         if let caught = caught { throw caught }
>         return value
>     }
>
>     return try bodyWrapper(predicate)
> }
>
> It is not pretty, and it probably relies on a compiler bug, but at the
> present time, against all odds, it look like this operates as you intend.
>
> Nevin
>
>
>
> On Sat, Dec 30, 2017 at 11:15 PM, Brent Royal-Gordon via swift-users <
> swift-users at swift.org> wrote:
>
>> I need to do something like this:
>>
>>         func withPredicateErrors<Element, Return>(_ predicate: (Element)
>> throws -> Bool, do body: ((Element) -> Bool) -> Return) rethrows -> Return {
>>           var caught: Error?
>>           let value = body { elem in
>>             do {
>>               return try predicate(elem)
>>             }
>>             catch {
>>               caught = error
>>               return true     // Terminate search
>>             }
>>           }
>>
>>           if let caught = caught {
>>             throw caught
>>           }
>>           else {
>>             return value
>>           }
>>         }
>>
>> The problem is, the Swift compiler doesn't allow the explicit `throw`
>> statement; even though it can only throw errors originally thrown by
>> `predicate`, the compiler is not smart enough to prove that to itself. I
>> cannot make `body` a `throws` function.
>>
>> Is there any way to do this? Either to override the compiler's safety
>> check, or to rewrite this function to avoid it?
>>
>> --
>> Brent Royal-Gordon
>> Architechies
>>
>> _______________________________________________
>> swift-users mailing list
>> swift-users at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20171231/6f4f93da/attachment.html>


More information about the swift-users mailing list