<div dir="ltr">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.<div><br></div><div>In particular, if the argument throws, the outer function can throw *any error or none at all*. For example,</div><div><br></div><div><div><font face="monospace, monospace">enum CatError: Error { case hairball }</font></div><div><font face="monospace, monospace">enum DogError: Error { case chasedSkunk }</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">func foo(_ f: () throws -> Void) rethrows -> Void {</font></div><div><font face="monospace, monospace"> do { try f() }</font></div><div><font face="monospace, monospace"> catch { throw CatError.hairball }</font></div><div><font face="monospace, monospace">}</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">do {</font></div><div><font face="monospace, monospace"> try foo{ throw DogError.chasedSkunk }</font></div><div><font face="monospace, monospace">} catch {</font></div><div><font face="monospace, monospace"> print(error) // hairball</font></div><div><font face="monospace, monospace">}</font></div></div><div><br></div><div>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.</div><div><br></div><div>• • •</div><div><br></div><div>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:</div><div><br></div><div><div><span style="font-family:monospace,monospace">func rethrowing(_ f: () throws -> Void) rethrows -> Void {</span><br></div><div><font face="monospace, monospace"> func localThrowing() throws -> Void { throw CatError.hairball }</font></div><div><font face="monospace, monospace"> return try localThrowing()</font></div><div><font face="monospace, monospace">}</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">do {</font></div><div><font face="monospace, monospace"> try rethrowing</font><span style="font-family:monospace,monospace">{ throw DogError.chasedSkunk }</span></div><div><font face="monospace, monospace">} catch {</font></div><div><font face="monospace, monospace"> print(error) // hairball</font></div><div><font face="monospace, monospace">}</font></div></div><div><br></div><div>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:</div><div><br></div><div><font face="monospace, monospace">rethrowing{ return } // EXC_BAD_ACCESS (code=1, address=0x0)</font><br></div><div><br></div><div>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.<br></div><div><br></div><div>• • •</div><div><br></div><div>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:</div><div><br></div><div><div><font face="monospace, monospace">func withPredicateErrors <Element, Return></font></div><div><font face="monospace, monospace"> (_ predicate: (Element) throws -> Bool,</font></div><div><font face="monospace, monospace"> do body: @escaping ((Element) -> Bool) -> Return</font></div><div><font face="monospace, monospace"> ) rethrows -> Return</font></div><div><font face="monospace, monospace">{</font></div><div><font face="monospace, monospace"> func bodyWrapper(_ f: (Element) throws -> Bool) throws -> Return {</font></div><div><font face="monospace, monospace"> var caught: Error?</font></div><div><font face="monospace, monospace"> let value = body{ elem in</font></div><div><font face="monospace, monospace"> do {</font></div><div><font face="monospace, monospace"> return try f(elem)</font></div><div><font face="monospace, monospace"> } catch {</font></div><div><font face="monospace, monospace"> caught = error</font></div><div><font face="monospace, monospace"> return true</font></div><div><font face="monospace, monospace"> }</font></div><div><font face="monospace, monospace"> }</font></div><div><font face="monospace, monospace"> if let caught = caught { throw caught }</font></div><div><font face="monospace, monospace"> return value</font></div><div><font face="monospace, monospace"> }</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace"> return try bodyWrapper(predicate)</font></div><div><font face="monospace, monospace">}</font></div></div><div><br></div><div>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.</div><div><br></div><div>Nevin<br></div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Dec 30, 2017 at 11:15 PM, Brent Royal-Gordon via swift-users <span dir="ltr"><<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I need to do something like this:<br>
<br>
func withPredicateErrors<Element, Return>(_ predicate: (Element) throws -> Bool, do body: ((Element) -> Bool) -> Return) rethrows -> Return {<br>
var caught: Error?<br>
let value = body { elem in<br>
do {<br>
return try predicate(elem)<br>
}<br>
catch {<br>
caught = error<br>
return true // Terminate search<br>
}<br>
}<br>
<br>
if let caught = caught {<br>
throw caught<br>
}<br>
else {<br>
return value<br>
}<br>
}<br>
<br>
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.<br>
<br>
Is there any way to do this? Either to override the compiler's safety check, or to rewrite this function to avoid it?<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Brent Royal-Gordon<br>
Architechies<br>
<br>
______________________________<wbr>_________________<br>
swift-users mailing list<br>
<a href="mailto:swift-users@swift.org">swift-users@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-users</a><br>
</font></span></blockquote></div><br></div>