<div dir="ltr">So this is how this feature could be achieved right now with minimal changes to the language.<div><br></div><div>- We expose some kind of protocol that allows you to Box up types, we could call this `Box` or something else like `Unit`. (I have a working implementation in the current language with a bit of boilerplate). This protocol handles the default implementation of converting from literals and to floats etc.</div><div>- For each type-safe unit for a calculation - you define a protocol extending this `Box` type which defines the associated type of the value that unit holds. For example for Degree and Radian I declared a `AngleType` which set the associated type to be a double. </div><div>- For each unit type, you declare a struct that inherits from that protocol you defined. So I have two structs `Degree` and `Radian` which implement the `AngleType` protocol.</div><div>- You implement the functions for figuring out if your units are equal and all other operators they may need i.e `Degree(360) - 30`.</div><div><br></div><div>Future improvements with language updates:</div><div><br></div><div>- `AngleType` protocol may not be needed if swift introduces generic protocols.</div><div>- Boilerplate in your type safe unit types may be reduced if swift introduces memberwise initialization.</div><div>- The current implementation of this system in Swift will be greatly simplified once the refactoring of Swift&#39;s Number types has been completed. We currently use a bunch of work arounds with the compiler.</div><div>- We could introduce custom user literals to create these types if swift supports this in the future (As Felix states).</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jan 7, 2016 at 7:06 AM, Félix Cloutier <span dir="ltr">&lt;<a href="mailto:felixcca@yahoo.ca" target="_blank">felixcca@yahoo.ca</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">I&#39;d like to hijack this thread to talk about what the TI Voyage 200 could do as far as &quot;type-safe calculations&quot; go.<div><br></div><div>The calculator supports symbolic equations (for instance, `a * 1000 / 2` results in `500a` when a isn&#39;t known). The interesting part is that you could append units to numbers. For instance, you can write `500_m`, and this means 500 meters. Numbers with a type can only be added/subtracted with numbers of the same type, but they can be multiplied or divided by pretty much anything. For instance, `500_m - 2_s` (500 meters minus 2 seconds) is an error, but `500_m / 2_s` is `250 (_m/_s)` (or _m * _s^-1).</div><div><br></div><div>I found this *extremely* useful for engineering calculations. For instance, when you multiply quantities that should end up in Teslas, you know that you&#39;ve done something wrong if the unit displayed after the number doesn&#39;t look like `V * s * m^-2`. It was also a lifesaver that you could do something like `6_ft` and end up with 1.8288_m (because _ft is defined as 0.3048_m).</div><div><br></div><div>I have no idea how you&#39;d implement that with Swift though. I&#39;m not a very powerful template wizard, but I have no idea how you&#39;d do it with C++ either.</div><div><br></div><div>Of course, it might be a few years before you&#39;re allowed to use the Swift compiler during your physics exams, and I don&#39;t think that real-world programs often need that much unit safety with numbers. But when I read &quot;epic typesafe calculations&quot;, that&#39;s what I think about.</div><div><div>
<br><span style="color:rgb(0,0,0);font-family:&#39;Lucida Grande&#39;;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;display:inline!important;float:none">Félix</span>
</div>

<br><div><blockquote type="cite"><div><div class="h5"><div>Le 7 janv. 2016 à 01:42:07, Thorsten Seitz via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; a écrit :</div><br></div></div><div><div><div><div class="h5"><div>I think the name should be changed to NumberBox or something similar. A box is something very generic and should not have number related associated types.<br></div><div><br></div><div>-Thorsten<br></div><div><br>Am 06. Januar 2016 um 18:15 schrieb James Campbell &lt;<a href="mailto:james@supmenow.com" target="_blank">james@supmenow.com</a>&gt;:<br><br><div><blockquote type="cite"><div><div dir="ltr">I&#39;ve managed to implement this already in the language with a few ugly corners due to the lack of generic protocols.<div><br></div><div>I created a protocol based on Box (<a href="https://github.com/robrix/Box/" target="_blank">https://github.com/robrix/Box/</a>) which works really well. I have extended this to handle certain special protocols like Equatable so you can do SpecialType == SpecialType, and even literalConversion.</div><div><br></div><div>There is however a lot of boilerplate:</div><div><br></div><div>- You have to declare all of your Convertible protocols for converting from one type to another</div><div>- You have to define an empty init so the protocol extensions have something to chain to.</div><div>- You need to write the value property with type.</div><div><br></div><div>Due to the lack of protocol generics, you also need to have a protocol for every type you wish to box which sets the associated type. Of course I could have done this with classes but I wanted to keep this as a value type :).</div><div><br></div><div>With member-wise initializations and generic protocols this could be achievable just by adding a Box protocol to the standard library.</div><div><br></div><div>Here is my implementation of Box as a protocol:</div><div><br></div><div><p><b><span>protocol</span><span> Box: </span><span>CustomStringConvertible</span><span>, </span><span>CustomDebugStringConvertible</span><span> {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>typealias</span><span> FloatLiteralType = Double</span></b></p><p><b><span>    </span><span>typealias</span><span> IntegerLiteralType = Int</span></b></p><p><b><span>    </span><span>typealias</span><span> BoxType = Any</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>var</span><span> value: </span><span>BoxType</span><span> { </span><span>get</span><span> </span><span>set</span><span> }</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>()</span></b></p><p><b><span>    </span><span>init</span><span>(</span><span>_</span><span> value: </span><span>BoxType</span><span>)</span></b></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><b><span>extension</span><span> </span><span>Box</span><span> </span><span>where</span><span> BoxType: CustomStringConvertible {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>var</span><span> description: </span><span>String</span><span> {</span></b></p><p><b><span>        </span><span>return</span><span> </span><span>self</span><span>.</span><span>value</span><span>.</span><span>description</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>var</span><span> debugDescription: </span><span>String</span><span> {</span></b></p><p><b><span>        </span><span>return</span><span> </span><span>&quot;</span><span>\</span><span>(</span><span>self</span><span>.</span><span>value</span><span>.</span><span>description</span><span>)</span><span>㎭</span><span>&quot;</span></b></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><span><b>//MARK: FloatingPointBox</b></span></p><p><b><span></span><br></b></p><p><b><span>protocol</span><span> FloatingPointBox: </span><span>Box</span><span>, </span><span>FloatLiteralConvertible</span><span>, </span><span>IntegerLiteralConvertible</span><span> {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>typealias</span><span> BoxType = Double</span></b></p><p><b><span>    </span><span>typealias</span><span> FloatLiteralConvertible = Double</span></b></p><p><b><span>    </span><span>typealias</span><span> IntegerLiteralConvertible = Int</span></b></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><b><span>extension</span><span> </span><span>Box</span><span> </span><span>where</span><span> </span><span>Self</span><span>.BoxType == Double {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(</span><span>_</span><span> value: </span><span>Double</span><span>) {</span></b></p><p><span><b>        </b></span></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>()</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>value</span><span> = value</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(</span><span>_</span><span> value: </span><span>Int</span><span>) {</span></b></p><p><span><b>        </b></span></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>()</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>value</span><span> = </span><span>Double</span><span>(value)</span></b></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><b><span>extension</span><span> </span><span>FloatLiteralType</span><span> {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>&lt;T: </span><span>Box</span><span> </span><span>where</span><span> </span><span>T</span><span>.</span><span>BoxType</span><span> == </span><span>Double</span><span> &gt;(</span><span>_</span><span> box: </span><span>T</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(box.</span><span>value</span><span>)</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>&lt;T: </span><span>Box</span><span> </span><span>where</span><span> </span><span>T</span><span>.</span><span>BoxType</span><span> == </span><span>Int</span><span> &gt;(</span><span>_</span><span> box: </span><span>T</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(box.</span><span>value</span><span>)</span></b></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><b><span>extension</span><span> </span><span>CGFloat</span><span> {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>&lt;T: </span><span>Box</span><span> </span><span>where</span><span> </span><span>T</span><span>.</span><span>BoxType</span><span> == </span><span>Double</span><span> &gt;(</span><span>_</span><span> box: </span><span>T</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(box.</span><span>value</span><span>)</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>&lt;T: </span><span>Box</span><span> </span><span>where</span><span> </span><span>T</span><span>.</span><span>BoxType</span><span> == </span><span>Int</span><span> &gt;(</span><span>_</span><span> box: </span><span>T</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(box.</span><span>value</span><span>)</span></b></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><span><b>//Adding FloatLiteralConvertible, IntegerLiteralConvertible</b></span></p><p><b><span></span><br></b></p><p><b><span>extension</span><span> </span><span>FloatingPointBox</span><span> </span><span>where</span><span> </span><span>Self</span><span>.BoxType == Double, </span><span>Self</span><span>.FloatLiteralConvertible == Double {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(floatLiteral value: </span><span>Double</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(value)</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(integerLiteral value: </span><span>Int</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(value)</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>&lt;T: </span><span>IntegerType</span><span>&gt;(</span><span>_</span><span> value: </span><span>T</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(value)</span></b></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p></div><div><br></div><div>Here is my example of using the Box protocol:</div><div><p><b><span>struct</span><span> Degree: </span><span>FloatingPointBox</span><span> {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>var</span><span> value: </span><span>Double</span><span> = </span><span>0</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>()</span></b></p><p><span><b>    {</b></span></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><b><span>protocol</span><span> DegreeConvertiable {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(degreeLiteral value: </span><span>Degree</span><span>)</span></b></p><p><span><b>}</b></span></p><p><b><span></span><br></b></p><p><b><span>extension</span><span> </span><span>Degree</span><span>: </span><span>RadianConvertiable</span><span> {</span></b></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(radianLiteral value: </span><span>Radian</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>value</span><span> = </span><span>Double</span><span>(value) * </span><span>180.0</span><span> / </span><span>M_PI</span></b></p><p><span><b>    }</b></span></p><p><span><b>    </b></span></p><p><b><span>    </span><span>init</span><span>(</span><span>_</span><span> value: </span><span>Radian</span><span>) {</span></b></p><p><b><span>        </span><span>self</span><span>.</span><span>init</span><span>(radianLiteral: value)</span></b></p><p><span><b>    }</b></span></p><p><span><b>}</b></span></p></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 5, 2016 at 5:24 PM, Matthew Johnson 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><blockquote class="gmail_quote" style="margin:0 0 0 0.8ex;border-left:1px #ccc solid;padding-left:1ex"><span><br> &gt; On Jan 5, 2016, at 11:16 AM, Thorsten Seitz via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br> &gt;<br> &gt;<br> &gt;&gt; Am 05.01.2016 um 17:11 schrieb Grzegorz Adam Hankiewicz via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;:<br> &gt;&gt;<br> &gt;&gt; The ideal would be for the compiler to pretend Euros or RefTablePk are different types, yet use their parent type at the binary level. This needs a specific syntax to teach the compiler which existing methods/operations are allowed on the new fake types and which aren’t. These new distinct types would *borrow* previous implementations.<br> &gt;<br> &gt; What about citing the relevant protocols in the newtype definition? This should include the ability to use my own protocols to which I have made the underlying type conform to by an extension.<br> <br> </span>This is how my forwarding proposal works.  The newtype syntax I suggested as a possible extension looks like this:<br> <br> newtype Euro = Double forwarding Addable, Subtractable<br> <br> The keyword could be different, but I think `forwarding` is not bad.  When I complete the second draft I think it will make even more sense.  The forwarding facility has features to handle non-trivial cases (Self and associated type requirements, etc).<br><div><div><br> &gt;<br> &gt; Throwing some syntax into the discussion:<br> &gt;<br> &gt; newtype Euro = Double : Addable, Subtractable<br> &gt;<br> &gt; where I have defined the protocols Addable and Subtractable somewhere and made Double conform to them if all this is not provided by the standard library.<br> &gt; The implementation of Euro then borrows the implementation of Double for these protocols.<br> &gt;<br> &gt; -Thorsten<br> &gt; _______________________________________________<br> &gt; swift-evolution mailing list<br> &gt; <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br> &gt; <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> _______________________________________________<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></div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div><span style="font-size:16px;line-height:19.2px"></span><span style="font-size:12.8px"> Wizard</span><br></div><div><a href="mailto:james@supmenow.com" target="_blank">james@supmenow.com</a><br></div><div><a href="tel:%2B44%207523%20279%20698" value="+447523279698" target="_blank">+44 7523 279 698</a></div></div></div></div></div></div></div></div></blockquote></div></div>
</div></div><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=iRI3beHTe3UxYAHTlV3lA38zIPfHMhyuRzgTmGKV6k6HNcWkb74NUSDxUueppvCu9gpojaO9hZVqMXWA70bVvWq4J1cDLLsnYCBRPcUGX7vfztZpLXDs1P5H2vE26cBhlOl4jucx-2BKWb7f86owE-2FdQfvirepNc1UTNMZyHIL34yiksqtvFmL-2FGRj3aQHa6jALWWzQiX5Kmj-2B-2FAvgvnj-2FMA-3D-3D" alt="" width="1" height="1" border="0" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important">
</div><span class="">
_______________________________________________<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" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></span></div></blockquote></div><br></div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div><span style="font-size:16px;line-height:19.2px"></span><span style="font-size:12.8px"> Wizard</span><br></div><div><a href="mailto:james@supmenow.com" target="_blank">james@supmenow.com</a></div><div>+44 7523 279 698</div></div></div></div></div></div>
</div>