<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=""><blockquote type="cite" class="">On Jun 29, 2016, at 5:30 PM, Paul Cantrell via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""></blockquote><div><blockquote type="cite" class=""><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="" style="font-family: HelveticaNeue;"><blockquote type="cite" class="" style="font-family: HelveticaNeue; font-size: 12px; font-style: normal; font-variant-caps: 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;"><div class="">On Jun 27, 2016, at 1:17 PM, Douglas Gregor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""><p class="" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">The <code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">LocalizedError</code> protocol describes an error that provides localized messages for display to the end user, all of which provide default implementations. The conforming type can provide implementations for any subset of these requirements:</p><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><pre class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; 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; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">protocol</span> LocalizedError <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">:</span> Error {
<span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">/// A localized message describing what error occurred.</span>
<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">var</span> errorDescription: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span>? { <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">get</span> }
…
}
</pre></div></div></div></div></blockquote></div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">Given that LocalizedError would now be its own protocol that not all errors would conform to, could errorDescription be non-optional?</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;"><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><pre class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; 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; word-break: normal;"> <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">var</span> errorDescription: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span> { <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">get</span> }</pre></div></div></div></blockquote></div><div class="" style="font-family: HelveticaNeue;">It would be nice if conformance to LocalizedError guaranteed the presence of a user-readable message. Such a guarantee is useful when building a UI.</div><div class="" style="font-family: HelveticaNeue;"><br class=""></div><div class="" style="font-family: HelveticaNeue;">I realize the bridging to NSError may make this impossible, but in principle it seems like the right design.</div></div></div></div></blockquote><br class=""></div><div>The trouble is that NSError allows NSLocalizedDescriptionKey to be nil, and leaving it nil is how you get Cocoa's default behavior in a lot of situations. In fact, this is usually what you want—leaving NSLocalizedDescriptionKey nil and populating NSLocalizedFailureReasonErrorKey instead is often the better way to go. For example, in NSDocument’s error reporting, if you throw an error that sets a failure reason, like this:</div><div><br class=""></div><div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">override</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> read(from data: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Data</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, ofType typeName: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">String</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">throws</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> {</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(112, 61, 170);"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">let</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);"> userInfo = [</span><span class="" style="font-variant-ligatures: no-common-ligatures;">NSLocalizedFailureReasonErrorKey</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);">: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"Something went wrong."</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);">]</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">throw</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">NSError</span><span class="" style="font-variant-ligatures: no-common-ligatures;">(domain: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"Foo"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, code: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(39, 42, 216);">1</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, userInfo: userInfo)</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">}</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;">The error is presented to the user as “The operation could not be completed. Something went wrong.”</div><div class="" style="margin: 0px; line-height: normal;"><br class=""></div><div class="" style="margin: 0px; line-height: normal;">However, if you provide the description instead:</div><div class="" style="margin: 0px; line-height: normal;"><br class=""></div><div class="" style="margin: 0px; line-height: normal;"><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">override</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">func</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> read(from data: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">Data</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, ofType typeName: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">String</span><span class="" style="font-variant-ligatures: no-common-ligatures;">) </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">throws</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> {</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(112, 61, 170);"><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">let</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);"> userInfo = [</span><span class="" style="font-variant-ligatures: no-common-ligatures;">NSLocalizedDescriptionKey</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);">: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"Something went wrong."</span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(0, 0, 0);">]</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);">throw</span><span class="" style="font-variant-ligatures: no-common-ligatures;"> </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);">NSError</span><span class="" style="font-variant-ligatures: no-common-ligatures;">(domain: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(209, 47, 27);">"Foo"</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, code: </span><span class="" style="font-variant-ligatures: no-common-ligatures; color: rgb(39, 42, 216);">1</span><span class="" style="font-variant-ligatures: no-common-ligatures;">, userInfo: userInfo)</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;">}</span></div><div class="" style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;">You just get “The operation could not be completed.” with no further information.</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;">Providing the failure reason while leaving the description nil also changes the presentation when you’re reporting errors directly, as below:</div><div class="" style="margin: 0px; line-height: normal;"><br class=""></div><div class="" style="margin: 0px; line-height: normal;"><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> userInfo = [NSLocalizedFailureReasonErrorKey: </span><span style="font-variant-ligatures: no-common-ligatures; color: #d12f1b" class="">"Something went wrong."</span><span style="font-variant-ligatures: no-common-ligatures" class="">]</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">NSApp.presentError(NSError(domain: </span><span style="font-variant-ligatures: no-common-ligatures; color: #d12f1b" class="">"Foo"</span><span style="font-variant-ligatures: no-common-ligatures" class="">, code: </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">1</span><span style="font-variant-ligatures: no-common-ligatures" class="">, userInfo: userInfo))</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-family: Helvetica; font-size: 12px;" class=""><br class=""></span></div><div style="margin: 0px; line-height: normal; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""></span>This gives you “The operation could not be completed. Something went wrong.” By comparison:</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> userInfo = [NSLocalizedDescriptionKey: </span><span style="font-variant-ligatures: no-common-ligatures; color: #d12f1b" class="">"Something went wrong."</span><span style="font-variant-ligatures: no-common-ligatures" class="">]</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">NSApp.presentError(NSError(domain: </span><span style="font-variant-ligatures: no-common-ligatures; color: #d12f1b" class="">"Foo"</span><span style="font-variant-ligatures: no-common-ligatures" class="">, code: </span><span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">1</span><span style="font-variant-ligatures: no-common-ligatures" class="">, userInfo: userInfo))</span></div></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;">This just gives you “Something went wrong.” without the polite “The operation could not be completed.” prefix, which causes the error description to come across as rather blunt. A default implementation for the property could be provided, of course, but since the primary purpose of the methods in this protocol are for the implementer of the error type to provide information to the frameworks to assist in creating the NSError, I can’t think of any way to have it simultaneously return a meaningful value to a client and still communicate to the frameworks that this value should be nil.</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;">Perhaps we should add an additional property for a user-facing string generated from the rest of the strings?</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;">Charles</span></div><div class="" style="margin: 0px; line-height: normal;"><span class="" style="font-variant-ligatures: no-common-ligatures;"><br class=""></span></div></div></div></body></html>