<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 20 Feb 2017, at 06:40, Niels Andriesse via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">I'd like to discuss the possibility of treating the cases of a given enum as if they are subtypes of that enum. This seems like a natural thing to do because enum cases (especially when they have associated values) effectively define a closed set of subtypes.</div><div class=""><br class=""></div><div class="">Doing so would allow for constructions such as the following:</div><div class=""><br class=""></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">enum Foo {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""><span style="white-space:pre" class=""> </span>case a(name: String)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""><br class=""></font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">func isA(foo: Foo) -> Bool {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> // The old way:</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> if case .a = foo { return true }</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> return false</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> // The new way:</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> return foo is .a</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">}</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""><br class=""></font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">func printNameIfFooIsA(foo: Foo) -> Bool {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> // The old way:</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> if case let .a(name) = foo {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> print(name)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> }</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> // The new way (1):</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> if let a = foo as? .a {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> print(<a href="http://a.name/" class="">a.name</a>)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> }</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> // The new way (2):</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> if let name = (foo as? .a)?.name {</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> print(name)</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class=""> }</font></span></div><div class=""><span style="background-color:rgb(255,255,255)" class=""><font face="monospace, monospace" class="">}</font></span></div><div class=""><br class=""></div><div class="">Treating an enum's cases as its subtypes would make enums easier to work with because handling them would be syntactically the same as handling other types.</div><div class=""><br class=""></div><div class="">The pattern matching capabilities of enums wouldn't be affected by this proposal.</div><div class=""><br class=""></div><div class="">Multiple other proposals have already attempted to simplify enum handling (they have particularly focused on getting rid of "if case" and adding the ability to treat enum case tests as expressions), but none of the solutions presented in those proposals have worked out so far.</div><div class=""><br class=""></div><div class="">I believe that this could be the right solution to multiple enum-related problems that have been brought up repeatedly.</div></div></div></blockquote></div><br class=""><div class="">I really like the simplification of is/as here, since the leading dot should be clear enough and is consistent with other usages of enums.</div><div class=""><br class=""></div><div class="">Presumably this would apply even further though? For example, could I do:</div><div class=""><br class=""></div><div class=""><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func myMethod(_ something:Foo.a) -> Foo.a { … }</font></div><div class=""><br class=""></div><div class="">i.e- take and return only instances of Foo.a?</div><div class=""><br class=""></div><div class="">It should then also be possible for me to do:</div><div class=""><br class=""></div><div class=""><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let a:Foo = myMethod(Foo.a("test"))</font></div><div class=""><br class=""></div><div class="">In other words, Foo.a is a valid instance of Foo (but not vice versa without casting first)?</div></body></html>