<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 3 Nov 2016, at 22:56, Nevin Brackett-Rozinsky <<a href="mailto:nevin.brackettrozinsky@gmail.com" class="">nevin.brackettrozinsky@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="">Okay, I think I found an actual shortcoming that type narrowing might address, namely mutating a property in place if it is a subtype. Here is a small example setup:</div><div class=""><br class=""></div><div class=""><div class=""><font face="monospace, monospace" class="">protocol A { var x: Int {get} }</font></div><div class=""><font face="monospace, monospace" class="">struct B: A { var x: Int }</font></div><div class=""><font face="monospace, monospace" class="">struct C { var a: A }</font></div><div class=""><font face="monospace, monospace" class="">var c = C(a: B(x: 4))</font></div><div class=""><br class=""></div><div class="">Note that “A” does not promise the “x” property will be mutable, while B does. I use “x: Int” as a minimal example, but any solution should also work for more complex scenarios.</div><div class=""><br class=""></div><div class="">Now suppose we wish to test whether “c.a” is of type B, and if so change its “x” value. We could, of course, make a local copy, mutate it, and reassign to “c.a”. But if those operations are expensive we would rather avoid doing so. And if B uses copy-on-write, we would want to remove the value from “c” entirely so that we hopefully have a unique reference. This is hard to get right.</div><div class=""><br class=""></div><div class="">We would prefer to write something like the following:</div><div class=""><br class=""></div><div class=""><font face="monospace, monospace" class="">(c.a as? B)?.x = 12</font></div></div><div class=""><br class=""></div><div class="">But that does not currently work, resulting in the error “Cannot assign to immutable expression of type 'Int'”.</div><div class=""><br class=""></div><div class="">Will the proposed type-narrowing feature provide a simple way to mutate “c.a” in place, contingent upon its being of type B?</div></div></div></blockquote><blockquote type="cite" class="">How does it compare to an alternative such as inout return values, which could preserve mutability in the above?</blockquote><div><br class=""></div><div>That's a good example, and yes it should be possible for type-narrowing to simplify stuff like this, I'll add a section on that I should probably go into more detail on how I intend working with narrowed mutable values to work, as for the advantage vs inout it's really just a matter of simplicity I think; using type narrowing should allow it to just work without having to pass to methods or design the API specifically for that kind of thing.</div><div><br class=""></div><div><br class=""></div><div><br class=""></div><blockquote type="cite" class=""><div dir="ltr" class=""><div class="">If we are going to have any sort of type narrowing, I would strongly prefer that it be explicit. For example we could use a keyword such as “rebind” to narrow the type of an existing symbol in a scope:</div></div></blockquote><blockquote type="cite" class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class=""><font face="monospace, monospace" class="">if rebind c.a as B {</font></div><div class=""><font face="monospace, monospace" class=""> c.a.x = 12</font></div><div class=""><font face="monospace, monospace" class="">}</font></div></div></blockquote><div><br class=""></div><div>I don't see what's really gained by making it explicit vs implicit; if the condition was c.a is B then I'm not sure how that's any less clear?</div><div><br class=""></div><blockquote type="cite" class=""><div dir="ltr" class=""><div class="">Furthermore, I think the proposal to treat enum cases as types is a major change to Swift’s type system, and probably introduces many unforeseen headaches. It also smells somewhat of a backdoor way for union types to sneak into the language.</div></div></blockquote><div><br class=""></div><div>I'd say that in a sense enums are types, after all they can have unique associated value types of their own. Really though my intent is primarily to support optionals, but I figure it makes sense to try and do it from the perspective of general purpose enums since that's all optionals really are anyway.</div><div><br class=""></div><div><br class=""></div><div>Also, I've been thinking about thread safety and it occurs to me that type narrowing could actually be of significant benefit to it, rather than a detriment.</div><div><br class=""></div><div>Consider:</div><div><br class=""></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>struct Foo { var value:Int }</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>struct Bar { var foo?:Foo }</font></div><div><font face="Monaco" class=""><br class=""></font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>var a = Foo(value: 5)</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>var b = Bar(foo: a)</font></div><div><font face="Monaco" class=""><br class=""></font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>b.foo.value = 10</font></div><div><br class=""></div><div>Now, in this case we're only dealing with structs, and we know that b.foo has a value, thus b.foo.value is nice and safe; in fact no force unwrapping needs to occur behind the scenes, it can optimise away completely.</div><div><br class=""></div><div>Instead, let's assume Bar is a class we're handling in a potentially shared way:</div><div><br class=""></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>class Bar { var foo?:Foo }</font></div><div><font face="Monaco" class=""><br class=""></font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func myMethod(bar:Bar) {</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>b.foo = new Foo(5) // We now know that b.foo shouldn't be nil</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>b.foo!.value = 10</font></div><div><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</font></div><div><br class=""></div><div>In this case, since Bar is a class we don't have total control over, we can't be certain that b.foo is non-nil when we try to modify it a second time; as a result, type-narrowing won't occur (because it's a class from another scope), however, because the type-checker knows that bar.foo <b class="">should</b> have a value, we can actually issue a more informative error message if force unwrapping fails, e.g- concurrent modification error.</div><div><br class=""></div><div>In other words, we can potentially use it to help detect concurrency issues. It's another thing that's going to require a section on the proposal though, I have a feeling it's going to get pretty big!</div></div></body></html>