<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 18, 2015, at 9:41 AM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; wrote:</div><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><br class=""></div><div class="">I’m not asking for you to speak for them. &nbsp;But I do think we need to learn from communities that are having success with typed error handling. &nbsp;Your proposal would be stronger if it went into detail about how it would avoid the problems that have been encountered in other languages. &nbsp;The experience of Rust could help to make that case as it is concrete and not hypothetical.</div></div></div></blockquote><div><br class=""></div><div>Sure, it could. It’s also anecdotal. It’s not necessarily true that something that works well in one context works well in another. It’s good to note that typed errors are wholly considered bad, but I’m not sure how much further we need to go then that. If you have specifics, then I could probably add them as an addendum to the proposal.</div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">My understanding is that Rust uses static multi-dispatch to do this. &nbsp;I don’t believe it has anything to do with structural sum types. &nbsp;Rust error handling uses a Result type with a single error case:&nbsp;<a href="http://doc.rust-lang.org/book/error-handling.html" class="">http://doc.rust-lang.org/book/error-handling.html</a>.</div></blockquote><div><br class=""></div><div>That example takes you through many of the options available. In the end, you end up at the sum-type for the error:</div><div><pre class="rust-example-rendered rust" style="box-sizing: border-box; font-family: 'Source Code Pro', Menlo, Monaco, Consolas, 'DejaVu Sans Mono', monospace; word-wrap: break-word; border: 0px; white-space: pre-wrap; padding: 11px; margin-top: 20px; margin-bottom: 20px; font-size: 14px; word-break: break-all; overflow: auto; line-height: 1.45; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; position: relative;"><span style="color: rgb(51, 51, 51);" class=""><span class="kw" style="box-sizing: border-box; color: rgb(137, 89, 168);">fn</span> <span class="ident" style="box-sizing: border-box;">search</span><span class="op" style="box-sizing: border-box;">&lt;</span><span class="ident" style="box-sizing: border-box;">P</span>: <span class="ident" style="box-sizing: border-box;">AsRef</span><span class="op" style="box-sizing: border-box;">&lt;</span><span class="ident" style="box-sizing: border-box;">Path</span><span class="op" style="box-sizing: border-box;">&gt;&gt;</span>
         (<span class="ident" style="box-sizing: border-box;">file_path</span>: <span class="kw-2" style="box-sizing: border-box; color: rgb(66, 113, 174);">&amp;</span><span class="prelude-ty" style="box-sizing: border-box; color: rgb(66, 113, 174);">Option</span><span class="op" style="box-sizing: border-box;">&lt;</span><span class="ident" style="box-sizing: border-box;">P</span><span class="op" style="box-sizing: border-box;">&gt;</span>, <span class="ident" style="box-sizing: border-box;">city</span>: <span class="kw-2" style="box-sizing: border-box; color: rgb(66, 113, 174);">&amp;</span><span class="ident" style="box-sizing: border-box;">str</span>)
         <span class="op" style="box-sizing: border-box;">-&gt;</span> <span class="prelude-ty" style="box-sizing: border-box; color: rgb(66, 113, 174);">Result</span><span class="op" style="box-sizing: border-box;">&lt;</span><span class="ident" style="box-sizing: border-box;">Vec</span><span class="op" style="box-sizing: border-box;">&lt;</span><span class="ident" style="box-sizing: border-box;">PopulationCount</span><span class="op" style="box-sizing: border-box;">&gt;</span>, <span class="ident" style="box-sizing: border-box;">CliError</span><span class="op" style="box-sizing: border-box;">&gt;</span> {
    </span><font color="#8959a8" class="">...</font><font color="#333333" class="">
}</font></pre><div class="">It’s the CliError which is defined as:</div><div class=""><pre class="rust-example-rendered rust" style="box-sizing: border-box; font-family: 'Source Code Pro', Menlo, Monaco, Consolas, 'DejaVu Sans Mono', monospace; word-wrap: break-word; border: 0px; white-space: pre-wrap; padding: 11px; margin-top: 20px; margin-bottom: 20px; font-size: 14px; word-break: break-all; overflow: auto; line-height: 1.45; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; position: relative; color: rgb(51, 51, 51);"><span class="kw" style="box-sizing: border-box; color: rgb(137, 89, 168);">enum</span> <span class="ident" style="box-sizing: border-box;">CliError</span> {
    <span class="ident" style="box-sizing: border-box;">Io</span>(<span class="ident" style="box-sizing: border-box;">io</span>::<span class="ident" style="box-sizing: border-box;">Error</span>),
    <span class="ident" style="box-sizing: border-box;">Csv</span>(<span class="ident" style="box-sizing: border-box;">csv</span>::<span class="ident" style="box-sizing: border-box;">Error</span>),
    <span class="ident" style="box-sizing: border-box;">NotFound</span>,
}</pre></div><div class="">The From() function essentially allows the <b class="">try!</b>&nbsp;macro to expand these in a nicer way.</div><div class=""><br class=""></div><div class="">So back to the proposal, one of the key things is to promote the `error` constant throughout the catch-clauses. This means that we can already leverage Swift’s pattern matching to solve this problem:</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><div class=""><font face="Menlo" class="">enum&nbsp;Combined {</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;case&nbsp;IO(String)</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;case&nbsp;Number(Int)</font></div></div></div><div><div><div class=""><font face="Menlo" class="">}</font></div></div></div><div><div><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div><div><div><div class=""><font face="Menlo" class="">func&nbsp;simulate(err:&nbsp;Combined) {</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;switch&nbsp;err {</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;case&nbsp;let&nbsp;Combined.IO(string)&nbsp;where&nbsp;string ==&nbsp;"hi":&nbsp;print("only hi!")</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;case&nbsp;let&nbsp;Combined.IO(string):&nbsp;print(string)</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;case&nbsp;let&nbsp;Combined.Number(value):&nbsp;print(value)</font></div></div></div><div><div><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;}</font></div></div></div><div><div><div class=""><font face="Menlo" class="">}</font></div></div></div><div><div><div class=""><font face="Menlo" class=""><br class=""></font></div></div></div><div><div><div class=""><font face="Menlo" class="">simulate(Combined.IO("hi"))</font></div></div></div><div><div><div class=""><font face="Menlo" class="">simulate(Combined.IO("io"))</font></div></div></div><div><div><div class=""><font face="Menlo" class="">simulate(Combined.Number(9))</font></div></div></div></blockquote><div><div><div class=""><br class=""></div><div class="">It’s not hard to use Swift’s pattern matching to extract out the inner information on an associated value enum and white the case/catch clauses. So unless I’m missing something, I think Swift already provides a good mechanism to do what you’re asking for, with the caveat that the `error` constant is promoted to be usable in the catch-clauses similar to how the switch-statements work.</div><div class=""><br class=""></div><div class="">Maybe adding this to the proposal would clarify usage?</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">How does this create a fragile API surface area? &nbsp;Adding a new error type to the signature would be a breaking change to the API contract. &nbsp;This is really no different than changing the type of error that can be thrown under your proposal.</div></div></blockquote><div><br class=""></div><div>It’s the same fragility that enums create; this was covered in the criticisms section. The likelihood of adding additional error cases is much greater than a change that would completely change the type of the error.</div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class="">I see this functionality as a general limitation in the language. For example, errors are not the only context where you may want to return a type of A, B, or C. There have been other proposals on how we might do that in Swift. If and when it was solved in the general case for type parameters, I can’t foresee a compelling reason why it wouldn’t work in this context as well.<br class=""></div></blockquote><div class=""><br class=""></div><div class="">That makes sense in some ways, but I don’t think it’s unreasonable to ask for some analysis of whether a better design for typed errors would be possible if we had them. &nbsp;IMO it’s pretty important to get the design of typed errors right if / when we add them. &nbsp;If we don’t it will be considered a major mistake and will lead to a lot of less than desirable outcomes down the road.</div><div class=""><br class=""></div><div class="">I also think typed errors may be one of the more important use cases for structural sum types of some kind. &nbsp;If we are able to show that design problems that<span class="Apple-converted-space">&nbsp;</span><b class="">cannot</b><span class="Apple-converted-space">&nbsp;</span>be solved without them<span class="Apple-converted-space">&nbsp;</span><b class="">can</b><span class="Apple-converted-space">&nbsp;</span>be solved with them that might influence whether they are added or not. &nbsp;It might also influence<span class="Apple-converted-space">&nbsp;</span><b class="">when</b>&nbsp;it makes sense to add support for typed errors to the language.</div></div></blockquote><div><br class=""></div><div>The problem can be solved without implicitly generated sum types though. The design of typed errors, as proposed, is to be consistent with the Swift type system today. Regardless, I’ve added a response in the “cirticisms” section that hopefully addresses this in some manner - basically, yes it would be helpful, but out of scope for this proposal.</div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">That approach would make catch clauses rather clunky by nesting errors inside of associated values. &nbsp;If you’re advocating for this approach do you have any ideas on how to streamline syntax for catching them?</div></blockquote><br class=""></div><div>See above example. Does that address this concern?</div><div><br class=""></div><div>-David</div><br class=""></body></html>