<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 19. Jun 2017, at 20:03, Karl Wagner <<a href="mailto:razielim@gmail.com" class="">razielim@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 19. Jun 2017, at 04:30, Nevin Brackett-Rozinsky via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Is there a way to restrict the associated values of an enum? For example, suppose I have this type:<div class=""><br class=""></div><div class=""><div class=""><font face="monospace, monospace" class="">enum Angle {</font></div><div class=""><font face="monospace, monospace" class=""> case radians(Double)</font></div><div class=""><font face="monospace, monospace" class=""> case degrees(Double)</font></div><div class=""><font face="monospace, monospace" class="">}</font></div></div><div class=""><br class=""></div><div class="">I want to ensure that the radians values is always in [0, 2π) and the degrees values is always in [0, 360). Ideally I would like to write an initializer which is called when the user writes eg. “let x: Angle = .degrees(-45)” and contains the logic to wrap the provided value into the allowed range (in this case by adding a multiple of 360).</div><div class=""><br class=""></div><div class="">I don’t see a way to do it. Is this possible?<br class=""></div><div class=""><br class=""></div><div class="">The closest I’ve found is to create auxiliary types such as</div><div class=""><br class=""></div><div class=""><font face="monospace, monospace" class="">struct Degree { … }</font></div><div class=""><font face="monospace, monospace" class="">struct Radian { … }</font><br class=""></div><div class=""><br class=""></div><div class="">and give them appropriate initializers, then use them for the associated values. However that is undesirable because it adds an extra level of depth to get at the actual numeric values.</div><div class=""><br class=""></div><div class="">Is there a better way?</div><div class=""><br class=""></div><div class="">Nevin</div></div>
_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-users" class="">https://lists.swift.org/mailman/listinfo/swift-users</a><br class=""></div></blockquote><br class=""></div><div class="">I suggested a type like this when Xiaodi announced his maths library, but a more efficient implementation would look like this:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">struct</span><span style="font-variant-ligatures: no-common-ligatures" class=""> Angle<T: </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">FloatingPoint</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=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> radians: </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">T</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=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">var</span><span style="font-variant-ligatures: no-common-ligatures" class=""> degrees: </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">T</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=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> (</span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">radians</span><span style="font-variant-ligatures: no-common-ligatures" class=""> / .</span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">pi</span><span style="font-variant-ligatures: no-common-ligatures" class="">) * </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">180</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=""> }</span></div><p 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="webkit-block-placeholder"></p><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">static</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> radians(</span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> rads: </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">T</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">Angle</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=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">Angle</span><span style="font-variant-ligatures: no-common-ligatures" class="">(radians: rads)</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=""> }</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=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">public</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">static</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> degrees(</span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> degs: </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">T</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">Angle</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=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">Angle</span><span style="font-variant-ligatures: no-common-ligatures" class="">(radians: (degs / </span><span style="font-variant-ligatures: no-common-ligatures; color: #323e7d" class="">180</span><span style="font-variant-ligatures: no-common-ligatures" class="">) * .</span><span style="font-variant-ligatures: no-common-ligatures; color: #587ea8" class="">pi</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=""> }</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="">}</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=""><br class=""></span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">Floating-points don’t have extra inhabitants, so the enum representation would occupy { float size + 1 byte } of storage, with the extra byte marking which enum case you have.</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""><br class=""></span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">A better approach is to store a single, normalised value (in this case, the ‘radians' value), and to provide initialisers which validate and normalise those input values. In your case, you wrap them to an allowed range. </span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class=""><br class=""></span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">I think the best-practice advice in this situation would be to consider switching: will anybody need to switch over the cases of your enum? In this case, no - Angle<T> is just a wrapper which statically verifies that the angle is in the expected “notation”; You want to put an angle of either notation in, and grab the same angle out in another notation. The underlying stored notation is an implementation detail, so a struct is better.</span></div><div class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div></div>- Karl</div></div></blockquote></div><br class=""><div class="">Oh, and one thing to note is that by making static initialiser functions, you can still pass angles in to functions by calling ".degrees(90)” or “.radians(.pi/4)”, so you kind-of emulate the convenience of using enums. IIRC, RawOptionSet does a similar trick.</div><div class=""><br class=""></div><div class="">The above struct is source-compatible with an equivalent enum representation; it all comes down to implementation details, and for this, the struct is more efficient.</div><div class=""><br class=""></div><div class="">- Karl</div></body></html>