<div dir="ltr">I like the idea, conceptually—having more set-like semantics for enums sounds like it would open up some interesting possibilities. (And I don&#39;t think we should limit ourselves to subsets either. Supersets are also interesting.)<div><br></div><div>Things could get pretty tricky though, so there are a lot of gaps to fill in here. Off the top of my head, I&#39;d be curious about the following situations:</div><div><br></div><div>* You don&#39;t mention cases with associated values anywhere. Is it your intention to prohibit those, or would the following work?</div><div><br></div><div>enum Foo {</div><div>   case Bar</div><div>   case Baz(Int)</div><div>   case Blorp(String)</div><div>}</div><div>typealias FooSubset = Foo.(Bar|Baz)</div><div>// FooSubset is effectively: enum FooSubset { case Bar; case Baz(Int) }?</div><div><br></div><div>I can&#39;t think of any reason off the top of my head to prohibit cases with associated values, for what it&#39;s worth.</div><div><br></div><div>* How would non-case members of an enum (i.e., computed properties, methods, etc.) be effected? Other folks in the thread have mentioned methods that switch on self. In a very abstract sense, there are two kinds of these properties/methods: those that simply use &quot;self&quot; to branch, and those that use the enum in other ways. For example, I see no reason that this shouldn&#39;t work:</div><div><br></div><div>enum Color {</div><div>  case red</div><div>  case blue</div><div>  case green</div><div><br></div><div>  var uiColor: UIColor {</div><div>    switch self {</div><div>      case .red: return UIColor.red()</div><div>      case .blue: return UIColor.blue()</div><div>      case .green: return UIColor.green()</div><div>    }</div><div>  }</div><div>}</div><div>let x: Color.(blue|green) = Color.blue</div><div>let color = x.uiColor</div><div><br></div><div>But on the other hand, you could have something like this:</div><div><br></div><div><div>enum Color {</div><div>  case red</div><div>  case blue</div><div>  case green</div><div><br></div><div>  var nextColor: Color {</div><div>    switch self {</div><div>      case .red: return .blue</div><div>      case .blue: return .green</div><div>      case .green: return .red</div><div>    }</div><div>  }</div><div>}</div>let x: Color.(blue|green) = Color.blue</div><div><span style="line-height:1.5">let color = x.nextColor  // umm....</span><br></div><div><br></div><div>Things start getting really hard to predict because it&#39;s very hard to reason about what happens inside these computed properties, and I fear that the solution becomes &quot;conservatively exclude a lot of stuff&quot; and that starts taking a lot of the power away from those enums.</div><div><br></div><div><br></div><div><br class="inbox-inbox-Apple-interchange-newline"><div class="gmail_quote"><div dir="ltr">On Fri, Jun 3, 2016 at 2:35 PM T.J. Usiyan via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Since this seems to have some interest, I&#39;ve made a gist.<div><br></div><div><a href="https://gist.github.com/griotspeak/963bc87a0c244c120264b11fb022d78c" target="_blank">https://gist.github.com/griotspeak/963bc87a0c244c120264b11fb022d78c</a></div><div></div></div><div dir="ltr"><div><h2 style="color:rgb(17,17,17);font-size:27px;line-height:42px;margin-top:42px;margin-bottom:21px;font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif">Introduction</h2><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">This proposal adds/creates syntax to allow ad hoc creation of enums whose members are strict subsets of explicitly defined enums.</p><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">Swift-evolution thread: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160530/020025.html" style="color:rgb(13,110,161);text-decoration:none" target="_blank"><ins style="display:inline-block;text-decoration:none!important;border:none!important;background-image:none!important"></ins>Discussion thread topic for that proposal</a></p></div></div><div dir="ltr"><div><h2 style="color:rgb(17,17,17);font-size:27px;line-height:42px;margin-top:42px;margin-bottom:21px;font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif">Motivation</h2><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">Consider a situation where we have an enum <code style="line-height:1">Color</code> which represents the entire set of colors relevant to your application with many salient methods and operations. We have also declared an enum <code style="line-height:1">LCDColorModel</code> with only three colors, <code style="line-height:1">red, blue, green</code> .</p><pre style="margin-top:21px;margin-bottom:21px;color:rgb(17,17,17);font-size:15px;min-height:183px;background-color:rgb(248,248,248)"><code style="line-height:inherit;display:block;padding:0.5em;color:rgb(51,51,51);min-height:auto"><span><span style="font-weight:bold">enum</span> <span style="color:rgb(68,85,136);font-weight:bold">Color</span> </span>{
    </code></pre></div></div><div dir="ltr"><div><pre style="margin-top:21px;margin-bottom:21px;color:rgb(17,17,17);font-size:15px;min-height:183px;background-color:rgb(248,248,248)"><code style="line-height:inherit;display:block;padding:0.5em;color:rgb(51,51,51);min-height:auto"><span style="font-weight:bold">case</span> red, orange, yellow, green, blue, indigo, violet
    …
}

</code></pre></div></div><div dir="ltr"><div><pre style="margin-top:21px;margin-bottom:21px;color:rgb(17,17,17);font-size:15px;min-height:183px;background-color:rgb(248,248,248)"><code style="line-height:inherit;display:block;padding:0.5em;color:rgb(51,51,51);min-height:auto"><span><span style="font-weight:bold">enum</span> <span style="color:rgb(68,85,136);font-weight:bold">LCDColor</span> </span>{
    <span style="font-weight:bold">case</span> red, green, blue
}</code></pre><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">The cases in <code style="line-height:1">LCDColor</code> in our scenario do not require different behavior from their similarly named cases in <code style="line-height:1">Color</code>. We would like, simply stated, to explicitly restrict the cases allowed within a specific portion of our software. There are, currently, a few approaches<br>1. Duplicate functionality in <code style="line-height:1">LCDColor</code></p></div></div><div dir="ltr"><div><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em"><br>- Completely manually<br>- Protocols with ‘minimal’ manual duplication<br></p></div></div><div dir="ltr"><div><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">2. Avoid duplication by allowing conversion to <code style="line-height:1">Color</code>. </p><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">Neither of these solutions make the subset relationship between <code style="line-height:1">Color</code> and <code style="line-height:1">LCDColor</code> clear or strict.</p></div></div><div dir="ltr"><div><h2 style="color:rgb(17,17,17);font-size:27px;line-height:42px;margin-top:42px;margin-bottom:21px;font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif">Proposed solution</h2><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">Add syntax to describe a restricted set of cases from an enum. </p></div></div><div dir="ltr"><div><pre style="margin-top:21px;margin-bottom:21px;color:rgb(17,17,17);font-size:15px;min-height:36px;background-color:rgb(248,248,248)"><code style="line-height:inherit;display:block;padding:0.5em;color:rgb(51,51,51);min-height:auto"><span style="font-weight:bold">typealias</span> <span>LCDColor</span> = <span>Color</span>.(red|green|blue)</code></pre><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em"><code style="line-height:1">LCDColor</code> has all of the type and instance methods of <code style="line-height:1">Color</code>.</p><ul style="margin-top:21px;margin-bottom:21px;padding-left:1.5em;color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;font-size:15px"><li style="font-size:17px">Barring any technical reason, the ‘actual’ name of the type, in this example, is <code style="line-height:1">Color.(red|green|blue)</code> This makes the relationship to <code style="line-height:1">Color</code>syntactically clear. If a typealias is not desired, <code style="line-height:1">Color.(red|green|blue)</code> should refer to the same type as <code style="line-height:1">LCDColor</code></li><li style="font-size:17px">Switching over <code style="line-height:1">Color.(red|green|blue)</code> should only need to be exhaustive for the three cases <code style="line-height:1">.red</code>, <code style="line-height:1">.green</code>, and <code style="line-height:1">.blue</code>.</li><li style="font-size:17px">Two initializers should be implicitly created<ul style="margin-top:0px;margin-bottom:0.4em;padding-left:1.5em"><li><code style="line-height:1">Color</code> to <code style="line-height:1">LCDColor?</code><ul style="margin-top:0px;margin-bottom:0.4em;padding-left:1.5em"><li>returns nil for all cases not in <code style="line-height:1">LCDColor</code></li></ul></li><li><code style="line-height:1">LCDColor</code> to <code style="line-height:1">Color</code><ul style="margin-top:0px;margin-bottom:0.4em;padding-left:1.5em"><li>Obvious and trivial implementation mapping cases from <code style="line-height:1">LCDColor</code> to <code style="line-height:1">Color</code></li></ul></li></ul></li><li style="font-size:17px">Casting should be allowed<ul style="margin-top:0px;margin-bottom:0.4em;padding-left:1.5em"><li>from superset to subset only using <code style="line-height:1">as?</code> or <code style="line-height:1">as!</code> syntax.</li><li>from subset to superset using <code style="line-height:1">as</code></li></ul></li><li style="font-size:17px">Creating subsets of subsets is not allowed but reasonable conversions among subsets should be allowed if technically feasible such that:<ul style="margin-top:0px;margin-bottom:0.4em;padding-left:1.5em"><li>Given subsets of <code style="line-height:1">C</code> <code style="line-height:1">A</code> and <code style="line-height:1">B</code>, where A is a superset of B, the casting relationship between <code style="line-height:1">A</code> and <code style="line-height:1">B</code> should be similar to that between <code style="line-height:1">C</code> and either of the other two named subsets.</li></ul></li></ul><h2 style="color:rgb(17,17,17);font-size:27px;line-height:42px;margin-top:42px;margin-bottom:21px;font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif">Detailed design</h2><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em"></p></div></div><div dir="ltr"><div><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">While I am unsure of the entirety of the design, I propose that name mangling be used which, along with the declaration order restriction should mean that all possible subsets have a stable and predictable name which contains all of the information necessary to infer cases.<br></p></div></div><div dir="ltr"><div><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">If a mangled name approach is taken, the ordering of cases should be sorted to ensure stability.</p><h2 style="color:rgb(17,17,17);font-size:27px;line-height:42px;margin-top:42px;margin-bottom:21px;font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif">Alternatives considered</h2><ul style="margin-top:21px;margin-bottom:21px;padding-left:1.5em;color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;font-size:15px"><li style="font-size:17px">Do nothing. This feature is not strictly necessary but does allow for expressivity not currently available in the language.</li><li style="font-size:17px">implicitly create properties which convert to superset type.</li></ul></div></div><div dir="ltr"><div><h2 style="color:rgb(17,17,17);font-size:27px;line-height:42px;margin-top:42px;margin-bottom:21px;font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif">Impact on existing code</h2><p style="color:rgb(17,17,17);font-family:&#39;Helvetica Neue&#39;,Helvetica,Arial,Verdana,sans-serif;word-wrap:break-word;margin:1.3125em 0px;font-size:1.1429em;line-height:1.3125em">This is an additive change which should have no breaking change to existing code.</p></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jun 3, 2016 at 4:57 PM, Austin Zheng <span dir="ltr">&lt;<a href="mailto:austinzheng@gmail.com" target="_blank">austinzheng@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">I really like the idea behind this proposal.<div><br></div><div>Some questions:</div><div><br></div><div>- Would the enum &#39;slice&#39; be a distinct type relative to the base enum?</div><div>- On a related note, would shared cases between the sliced enum and the base enum be implicitly convertible?</div><div>- If they aren&#39;t implicitly convertible between each other, would there be an affordance to perform conversions (e.g. a &quot;parentEnumType&quot; property and an &quot;init?(parentEnumType:)&quot; initializer)/</div><div>- Would you be able to further slice a sliced enum? If so, would they share the same parent, or would the &#39;parent&#39; of the sliced sliced enum be the sliced enum?</div><div>- If the parent enum has members that switch on &#39;self&#39;, would those members be available to the child automatically?</div><div>- What happens if you have two (or more) slices with disjoint members? (e.g. &#39;LCDColors&#39; and &#39;TrafficLightColors&#39;) Would they be considered completely separate &#39;sub-types&#39;?</div><div><br></div><div>Best,</div><div>Austin</div><div><br></div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote"><div><div>On Fri, Jun 3, 2016 at 6:22 AM, T.J. Usiyan via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div><div dir="ltr"><div>This is loosely related to but not meant to &#39;compete&#39; with the ad hoc enum proposal.</div><div><br></div><div>## Introduction</div><div><br></div><div>This proposal adds/creates syntax to allow ad hoc creation of enums whose members are strict subsets of explicitly defined enums.</div><div><br></div><div>Swift-evolution thread: [Discussion thread topic for that proposal](<a href="http://news.gmane.org/gmane.comp.lang.swift.evolution" target="_blank">http://news.gmane.org/gmane.comp.lang.swift.evolution</a>)</div><div><br></div><div>## Motivation</div><div>Consider a situation where we have an enum `Colors` which represents the entire set of colors relevant to your application with many salient methods and operations. We have also declared an enum `LCDColorModel` with only three colors, `red, blue, green` .</div><div><br></div><div>``` swift</div><div>enum Colors {</div><div><span style="white-space:pre-wrap">        </span>case red, orange, yellow, green, blue, indigo, violet</div><div><span style="white-space:pre-wrap">        </span>…</div><div>}</div><div><br></div><div>enum LCDColors {</div><div><span style="white-space:pre-wrap">        </span>case red, green, blue</div><div>}</div><div>```</div><div><br></div><div>The cases in `LCDColors` in our scenario do not require different behavior from their similarly named cases in `Colors`. We would like, simply stated, to explicitly restrict the cases allowed within a specific portion of our software. There are, currently, a few approaches </div><div><span style="white-space:pre-wrap">        </span>1. Duplicate functionality in `LCDColors` </div><div><span style="white-space:pre-wrap">                </span>- Completely manually</div><div><span style="white-space:pre-wrap">                </span>- Protocols with &#39;minimal&#39; manual duplication</div><div><span style="white-space:pre-wrap">        </span>2. Avoid duplication by allowing conversion to `Colors`. </div><div><br></div><div>Neither of these solutions make the subset relationship between `Colors` and `LCDColors`  clear or strict.</div><div><br></div><div>## Proposed solution</div><div><br></div><div>Add syntax to describe a restricted set of cases from an enum. </div><div><br></div><div>```swift</div><div>typealias LCDColors = Colors.(red|green|blue)</div><div>```</div><div><br></div><div>`LCDColors ` has all of the type and instance methods of `Colors`. Cases must appear in the same order as their original declaration. </div><div><br></div><div><br></div><div>## Detailed design</div><div><br></div><div>While I am unsure of the entirety of the design, I propose that name mangling be used which, along with the declaration order restriction should mean that all possible subsets have a stable and predictable name which contains all of the information necessary to infer cases. </div><div><br></div><div>## Impact on existing code</div><div><br></div><div>This is an additive change which should have no breaking change to existing code.</div><div><br></div><div><br></div></div>
<br></div></div><span>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br></span></blockquote></div><br></div>
</blockquote></div><br></div>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div></div>