<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Thanks for continuing the discussion David.</div><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 21, 2015, at 1:30 PM, David Owens II &lt;<a href="mailto:david@owensd.io" class="">david@owensd.io</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I’m just going to interject a few thoughts in here.</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2015, at 6:36 AM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Hi David,</div><div class=""><br class=""></div></div></div></blockquote><blockquote type="cite" class="">(my paraphrase: <i class="">pattern matching is great and solves more of my concerns than I originally realized.</i>)&nbsp;</blockquote><div class=""><br class=""></div><div class="">Awesome!</div><div class=""><br class=""></div><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I would also like to comment that there are some interesting related ideas for enhancing enums in the "<font face="Helvetica Neue" class="">[Pitch] Use enums as enum underlying types” thread. &nbsp;They don’t directly impact the proposal but could make such use cases even more convenient if they are pursued independently.</font></div></div></blockquote><div class=""><br class=""></div><div class="">I’m not sure I really like any of those proposals, but feedback for those is better on that thread, and I’ve only taken a cursory look at them.</div></div></div></div></blockquote><div><br class=""></div><div>Sure, just wanted to mention them. &nbsp;I’m not sure whether I like any of them either - even the ones I have posted. &nbsp;I do think they are interesting to think about but I am not sure whether they are good ideas or not.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">The other concern I have is still valid, but I think a relatively straightforward solution is possible.</div><div class=""><br class=""></div><div class="">(my paraphrase: <i class="">Converting from an inner-error to a publicly exposed error is tedious, boilerplate code.)</i></div></div></blockquote><div class=""><br class=""></div><div class="">Maybe. I think that depends on the assumption that you do nothing other than convert the inner error to a published error. Also, it assumes that all “recoverable” inner errors stay “recoverable” outer errors.</div><div class=""><br class=""></div><div class="">I tend to use a lot of telemetry markers and assertions within my code, so it’s not a one-liner conversion.</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">do {</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; try some.implementation.detail.throwing.api()</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">catch {</font></div><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; // what happens here?</span></div><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">I actually think there are various options of what to do at this place:</div><div class=""><br class=""></div><div class=""><ol class="MailOutline"><li class="">Simply propagate the error out (basically untyped errors)</li><li class="">Wrap the error (still exposes the internal implementation details)</li><li class="">Convert the error to a published error type</li><li class="">Promote the error to a non-recoverable error (e.g. fatalError())</li></ol><div class=""><br class=""></div><div class="">All of these can have additional code in place, such as telemetry/logging or debug assertions. While it <i class="">might</i>&nbsp;be the case that people simply want to wrap an error, can we say that is the <i class="">safe</i>&nbsp;way to deal with the errors? I’m not sure I’m willing to make that statement.</div></div></div></div></div></blockquote><div><br class=""></div><div>I agree. &nbsp;I am proposing a solution to reduce boilerplate where either option 2 or 3 is the right thing to do. &nbsp;Obviously if you need to do something more complex you do need to handle the error, in which case it is not boilerplate. &nbsp;The suggestion of implicit conversion would not prevent you from doing this.</div><div><br class=""></div><div>Please note: sometimes option 2 exposes implementation details but not necessarily. &nbsp;The example I discussed was describing a scenario where a library has a family of possible errors it publishes as part of its API contract and two (or more) different ones may be generated by the same function.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><div class=""><br class=""></div><div class="">I, obviously, recommend against doing options #1 and #2 above. I’ll talk about conversion below. And I believe promotion would look something like this:</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">guard&nbsp;((try?&nbsp;</font><span style="font-family: Menlo;" class="">some.implementation.detail.throwing.api()</span><font face="Menlo" class="">) !=&nbsp;nil)&nbsp;else&nbsp;{ fatalError(</font><span style="font-family: Menlo;" class="">"</span><font face="Menlo" class="">bad mojo!")&nbsp;}</font></div></div></div></blockquote><div class=""><div class=""><div class=""><br class=""></div><div class="">Or if I want the error:</div><div class=""><br class=""></div><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">do {</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; try some.implementation.detail.throwing.api()</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">catch {</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; Telemetry.LogFatalIssue(error)</font></div><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp;&nbsp;</span><font face="Menlo" class="">fatalError(</font><span style="font-family: Menlo;" class="">"</span><font face="Menlo" class="">bad mojo!")</font></div><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""></div></div><div class=""><br class=""></div><div class="">In an ideal world, I would also like to be able to do something like this:</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">guard try some.implementation.detail.throwing.api() else {</font></div></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; Telemetry.LogFatalIssue(error)</font></div><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp;&nbsp;</span><font face="Menlo" class="">fatalError(</font><span style="font-family: Menlo;" class="">"</span><font face="Menlo" class="">bad mojo!")</font><span style="font-family: Menlo;" class="">&nbsp; &nbsp;&nbsp;</span></div></div></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></div></blockquote><div class=""><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div><div class="">But that’s a syntax that’s out-of-scope for this proposal as well.</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">This is the problem that `From` addresses in Rust. &nbsp;Swift is not Rust and our solution will look different. &nbsp;The point is that this <b class="">is</b>&nbsp;a problem and it can and has been solved.</div><div class=""><br class=""></div><div class="">My suggestion is that we should allow implicit conversion during error propagation. &nbsp;If the published error type has one and only one non-failable, non-throwing initializer that takes a single argument of the type that is thrown (including enum case initializers with a single associated value of the thrown type) that initializer is used to implicitly convert to the published error type. &nbsp;This conversion could be accomplished by synthesizing the necessary boilerplate or by some other means.</div><div class=""><br class=""></div><div class="">Now we have:</div><div class=""><br class=""></div><div class="">func functionThatCallsUnderlingyingThrows(_ whichError: Bool) throws MyPublishedError {<br class="">&nbsp; &nbsp; &nbsp; &nbsp; try funcThatThrowsAnErrorThatMustBeTranslatedIntoMyPublishedError()<br class="">}</div><div class=""><br class=""></div><div class="">This looks as it should. &nbsp;We don’t pay a price of boilerplate for carefully designing the errors we expose in our API contract. &nbsp;This also handles automatic wrapping of errors where that is appropriate.</div></div></blockquote><div class=""><br class=""></div><div class="">I would argue against implicit conversion. Again, this is about consistency with the language. Also, Rust is using it’s macro system to generate the code; it’s not actually doing implicit conversions either.</div></div></div></div></blockquote><div><br class=""></div><div>I understand that Rust is not doing implicit conversions, but the effect for the user is pretty much the same. &nbsp;The try macro is converting the underlying error to the type that can be propagated. &nbsp;As I stated, Swift is not Rust and deserves a different solution. &nbsp;</div><div><br class=""></div><div>Nevertheless, that does not minimize the need to solve the problem. &nbsp;I maintain that the <b class="">problem </b>solved by the try macro is a significant one that is not addressed by the current proposal. &nbsp;I would really like to see it addressed one way or another.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><div class="">You could make it “nicer” by doing something like this:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">try&nbsp;MyError.convertFrom(try&nbsp;funcThatThrowsAnErrorThatMustBeTranslatedItoMyPublishedError())</font></div></div></blockquote></div></div></blockquote><div><br class=""></div><div>Can you elaborate on how you think this would work? &nbsp;If&nbsp;funcThatThrowsAnErrorThatMustBeTranslatedItoMyPublishedError actually throws it will be propagated to the next enclosing catch clause. &nbsp;MyError.convertFrom will not have a chance to do anything with it.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><div class="">All of the “boiler-plate” code (which you need to write the conversion code regardless) can be put where it needs to be and kept out of all of the call sites. You could then propose a “conversion” feature to Swift that would allow <i class="">explicit</i> conversions:</div><div class=""><br class=""></div><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">try&nbsp;funcThatThrowsAnErrorThatMustBeTranslatedItoMyPublishedError() as MyError</font></div></div></blockquote></div></div></div></div></blockquote><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><div class=""></div></div><div class=""><br class=""></div><div class="">This could call the conversion initializers.</div><div class=""></div></div><br class=""></div></div></blockquote><br class=""></div><div><div>This would be casting the return value, not the error value. &nbsp;Again, the error would be propagated to the next enclosing catch block.</div><div><br class=""></div><div>I would probably be ok with the need to *explicitly* declare a conversion like this at the call site if that were possible (although I would want to consider concrete examples). &nbsp;It just isn’t possible in the language today so 1) it’s hard to know exactly what it would look like and 2) it shouldn’t be part of the discussion unless we are considering adding something specific to the proposal.</div><div><br class=""></div><div>Are you willing to explore adding *explicit* syntax to convert thrown errors to your proposal? &nbsp;That seems like it might be a reasonable compromise between implicit conversions and manual boilerplate. &nbsp;</div><div><br class=""></div><div>I still prefer implicit conversions in this case and believe the value they bring to the table far outweighs their cost. &nbsp;We are not talking about implicit conversion of arbitrary expressions here. &nbsp;We are talking about implicit conversion specifically at the time of error propagation *from* the explicitly stated error type in throwing functions that are called *to* the explicitly stated error type in the calling function *if* an eligible initializer exists. &nbsp;</div><div><br class=""></div><div>This is a pretty narrow case with pretty obvious results IMO. &nbsp;And it only kicks in if the underlying error is propagated out of the function so you still have the ability to catch it and log it, suppress it, convert to fatalError(), etc if you need to do that.</div><div class=""><br class=""></div><div class="">Matthew</div></div><br class=""></body></html>