<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="">I agree that there's something about the inheritance that's inside out, since the enum restricts the domain of the underlying type instead of expanding it. However, it is consistent with the current enum semantics when they're based off raw values.</div><div class=""><br class=""></div><div class="">It seems to me that the relationships otherwise make sense: looking at the declaration syntax `enum FileSystemError: MyLibError`, there's no surprise that any FileSystemError can be converted to a MyLibError.</div><div class=""><br class=""></div><div class="">The fact that enums are value types and that value types can't usually use inheritance does mean that there will be no vtable involved, however, and that could go against the principle of least surprise. This is less of an issue with composition since fields would be expected to have their own methods.</div><div class=""><br class=""></div><div class="">I like the prospect of automatically synthesizing a sub-enum for cases that are actually thrown as this would make catching much shorter. In that regard, sub-enums stand out compared to inclusive enums when you have two functions that can throw overlapping subsets of errors:</div><div class=""><br class=""></div><div class=""><div class=""></div><blockquote type="cite" class=""><div class="">enum ChangePictureError {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>case NoInternet, Security</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>case PictureTooBig</div><div class="">}</div><div class=""><br class=""></div><div class="">func doThis() throws {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>guard checkInternet() else {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>throw ChangePictureError.NoInternet</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>guard checkAllowed() else {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>throw ChangePictureError.Security</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class="">}</div><div class=""><br class=""></div><div class="">func doThat() throws {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>guard checkInternet() else {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>throw ChangePictureError.NoInternet</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>guard checkPictureSize() else {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>throw ChangePictureError.PictureTooBig</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class="">}</div></blockquote></div><font color="#5856d6" class=""><br class=""></font><div class="">With composed enums, you'd have NetworkError, and ChangePictureError that includes NetworkError and provides an additional PictureTooBig. However, with both functions, there's at least one case that can't be thrown. Even with annotated throws, this means you still need irrelevant case(s) to prove exhaustiveness if you can't synthesize sub-enums and don't want to complicate function metadata to include every possibly thrown case. If the compiler is allowed to create sub-enums, you won't need a catch-all to prove exhaustiveness.</div><div class=""><br class=""></div><div class="">Inclusive enums and sub-enums aren't necessarily mutually exclusive, either.</div><br class=""><div class="">
<span class="Apple-style-span" style="border-collapse: separate; line-height: normal; border-spacing: 0px;">Félix</span>
</div>
<br class=""><div><blockquote type="cite" class=""><div class="">Le 20 déc. 2015 à 20:13:14, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> a écrit :</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" style="font-family: LucidaGrande; 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;"><div class=""><br class="Apple-interchange-newline">On Dec 19, 2015, at 3:36 PM, Félix Cloutier <<a href="mailto:felixcca@yahoo.ca" class="">felixcca@yahoo.ca</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">I'm biased as the pitcher, but I find that an "inheritance" model would be more straightforward than an inclusive model.<div class=""><br class=""></div><div class="">If I understand you correctly, with this model:</div><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class="">enum NetworkException {<br class=""> case NoInternetError, SecurityError<br class="">}</div><div class=""><br class=""></div><div class=""><span class="" style="font-family: LucidaGrande;">enum ChangePictureError {</span><br class="" style="font-family: LucidaGrande;"><span class="" style="font-family: LucidaGrande;"> case NetworkException(NetworkException)</span><br class="" style="font-family: LucidaGrande;"><span class="" style="font-family: LucidaGrande;"> case ParseException(ParseException)</span><br class="" style="font-family: LucidaGrande;"><span class="" style="font-family: LucidaGrande;"> case PictureTooLarge</span><br class="" style="font-family: LucidaGrande;"><span class="" style="font-family: LucidaGrande;">}</span><br class=""></div></blockquote><div class=""><br class=""></div>you're saying that we should be able to write:<div class=""><br class=""></div><div class=""><blockquote type="cite" class="">let x: ChangePictureError = NetworkException.NoInternetError<br class=""></blockquote><div class=""><div class=""><br class=""></div><div class="">The implicit conversion from NetworkException to ChangePictureError reminds me of C++ implicit constructors, which are generally frowned upon, so I'm not sure that this is the best way forward.</div><div class=""><br class=""></div><div class="">On the other hand, going back to my original example:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class="">enum MyLibError: ErrorType {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case FileNotFound<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case UnexpectedEOF<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case PermissionDenied<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// ... 300 cases later<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case FluxCapacitorFailure<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case SplineReticulationError<br class="">}<br class=""><br class="">enum FileSystemError: MyLibError {<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case FileNotFound = .FileNotFound<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case UnexpectedEOF = .UnexpectedEOF<br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case PermissionDenied = .PermissionDenied<br class="">}</blockquote></div><div class=""><br class=""></div><div class="">I can easily rationalize that FileSystemError is implicitly convertible to MyLibError because of the "inheritance" relationship.</div><div class=""><br class=""></div></div></div></div></div></blockquote><div style="font-family: LucidaGrande; 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=""></div><div style="font-family: LucidaGrande; 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="">As I said, I was mostly thinking out loud about possibilities here. </div><div style="font-family: LucidaGrande; 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=""></div><div style="font-family: LucidaGrande; 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="">The supertype / subtype relationship makes sense to me but an inheritance relationship does not. It doesn’t make sense because enums are value types and also because it gets the supertype / subtype relationship backwards. Just because you have a FileSystemError you do not necessarily have a MyLibError. However, if you have a MyLibError you *do* have something that can be a FileSystemError (whether by include or by composition or whatever mechanism we might use).</div><div style="font-family: LucidaGrande; 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=""></div><div style="font-family: LucidaGrande; 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="">I agree that implicit conversions are generally a bad thing and I am not necessarily convinced that the idea I outlined is a good one. However, it does follow the pattern of allowing implicit conversion for subtype / supertype relationships *if* we consider the nested enum case to effectively make ChangePictureError a supertype of NetworkExceptionError. In other words, all NetworkExceptions *can be* a ChangePictureError. </div><div style="font-family: LucidaGrande; 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=""></div><div style="font-family: LucidaGrande; 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="">Swift already includes a number of implicit conversions for subtype / supertype relationships: reference type inheritance, protocol conformance, values to optional values, etc. Chris has talked about possibly extending this further. This is the line of thinking that lead to my writeup. Whether it makes sense to extend it in the way I outlined or not I am not sure. But that makes more sense than the other ideas I have seen in this thread so far.</div><div style="font-family: LucidaGrande; 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=""></div><div style="font-family: LucidaGrande; 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="">The problem I see with the include idea is that it doesn’t consider the type holistically, it only considers the cases. What about other initializers and methods? The initializers are probably ok because they would only reference cases that were included, but the methods would not be ok as they would not match the additional cases in the containing enum. </div><div style="font-family: LucidaGrande; 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=""></div><div style="font-family: LucidaGrande; 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="">Including the cases but losing access to the methods seems like a worse solution than what we have today with nested enums. I don’t think there is necessarily a good solution that isn’t a nested enum. That is why I started thinking about ways to make them more convenient by taking advantage of the subtype / supertype relationship that is already effectively latent in nested enums. I’m not sure it is a good idea, but I don’t see any better path to improve on current state.</div><div style="font-family: LucidaGrande; 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=""></div></div></blockquote></div><br class=""></body></html>