<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br>Sent from my iPad</div><div><br>On May 9, 2016, at 3:01 AM, Andrew Trick <<a href="mailto:atrick@apple.com">atrick@apple.com</a>> wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8"><br class=""><div><blockquote type="cite" class=""><div class="">On May 7, 2016, at 11:51 PM, Dave Abrahams <<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Does Array<T> have value semantics then only if T also has value<br class="">semantics?<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">This is a great question; I had to rewrite my response four times.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">In my world, an Array<T> always has value semantics if you respect the</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">boundaries of element values as defined by ==. That means that if T is</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">a mutable reference type, you're not looking through references, because</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">== is equivalent to ===.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Therefore, for almost any interesting SomeConstraint that doesn't refine</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">ValueSemantics, then</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class=""> Array<T: SomeConstraint></span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">only has value semantics if T has value semantics, since SomeConstraint</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">presumably uses aspects of T other than reference identity. </span></div></div></blockquote></div><br class=""><div class=""><div class="">I just had a chance to digest Dave's answer. It explains a lot.</div><div class=""><br class=""></div><div class="">PureValue was defined in terms of the type's physical representation:</div><div class="">- A struct with no reference properties</div><div class="">- Recursively, a reference to immutable or uniquely referenced memory.</div><div class=""><br class=""></div><div class="">It's defined such that we can say Array<T> is a PureValue iff T is a PureValue.</div></div></div></blockquote><blockquote type="cite"><div><div class=""><div class=""><br class=""></div><div class="">There is currently no procedure for determining PureValue because we have no way to declare that references are immutable or uniquely referenced. It would be a promise by the developer.</div></div></div></blockquote><div><br></div><div>Yes. The same can be said of some semantic requirements in existing protocols, such as complexity requirements. It is fair to observe that there is a difference here - not meeting complexity requirement slows things down, but doesn't fundamentally break. Another example is the requirement to always return nil after you reach the end of <span style="background-color: rgba(255, 255, 255, 0);">IteratorType</span>.</div><div><br></div><div>If it is possible to eventually have a mechanism that can be verified by the compiler we should wait to introduce the concept until that is in place. Verifying value semantics would be the first step in that direction.</div><div><br></div><blockquote type="cite"><div><div class=""><div class=""><br class=""></div><div class="">Now attempting to look at it from Dave's direction, value semantics apply to the variable's type, not the object's physical representation:</div><div class=""><br class=""></div><div class="">let v2 = v1</div><div class="">f(v1)</div><div class="">assert(v1 == v2)</div><div class=""><br class=""></div><div class="">If everything is a value, then this always works. Great!</div><div class=""><br class=""></div><div class="">If the variable's type does not allow mutating shared state, then operations on the variable are operating on a value.</div><div class=""><br class=""></div><div class="">protocol ValueP {</div><div class=""> func compute() -> Result // nonmutating</div><div class="">}</div><div class=""><br class=""></div><div class="">func g(v1 : ValueP) {</div><div class=""> let v2 = v1</div><div class=""> v1.compute()</div><div class=""> assert(v1 == v2)</div><div class="">}</div><div class=""><br class=""></div><div class="">Nice. ‘compute' cannot change the value. Those value semantics do not tell me anything about shared state or function purity. For that, I need some additional constraint on 'compute'. Knowing that it does not mutate the 'self' value is insufficient.</div><div class=""><br class=""></div><div class="">One way of doing that, for example, is to declare that 'compute' transitively cannot access globals *and* ValueP must be a PureValue. Now I can safely write this:</div><div class=""><br class=""></div><div class="">protocol ValueP : PureValue {</div><div class=""> @strawman_noglobal func compute() -> Result</div><div class="">}</div><div class=""><br class=""></div><div class="">/// Return (v1.compute, v2.compute)</div><div class="">func g(v1 : ValueP, v2 : ValueP) -> (Result, Result) {</div><div class=""> let r1 = v1.compute()</div><div class=""> if v1 == v2 {</div><div class=""> return (r1, r1)</div><div class=""> }</div><div class=""> return (r1, v2.compute())</div><div class="">}</div><div class=""><br class=""></div><div class="">So, Dave is right that we need to decide soon whether we can make stronger assumptions about value semantics. But that is a separate question from how to express function purity. </div></div></div></blockquote><div><br></div><div>Agree. Nailing down value semantics is a big step in the right direction.</div><br><blockquote type="cite"><div><div class=""><div class="">I don't think there is any urgency in introducing things like the PureValue protocol or @strawman_noglobals attribute, now that we have clearly established shared-state-mutability-by-default. When we want to seriously have that discussion, we should consider other alternatives. </div></div></div></blockquote><div><br></div><div>No argument from me. I didn't mean to give a sense of urgency on this and am not attached to a specific mechanism. I am advocating for the importance of eventually having a way to distinguish pure values from impure values (even if the have value semantics such as Array<UIView>). If we don't get there in Swift 3 and the solution looks different than a PureValue protocol that is ok with me.</div><br><blockquote type="cite"><div><div class=""><div class="">I would prefer to wait until indirect structs and improved CoW support have had more discussion.</div></div></div></blockquote><div><br></div><div>I've been thinking a lot about Dave's desire to "mandate" that value semantic types must be value types and allowing us to use reference identity for equality of reference types. I would support that if these features were in place so I think shifting to those topics is a good next step for this discussion. </div><div><br></div><div>Along those lines, I've been thinking about a proposal to allow the indirect modifier on any property that has a value type. It may also be useful to allow the indirect modifier directly on struct and enum to allow type authors to indicate that all instances should be indirect. Do you think it would it be worthwhile to pursue this proposal now?</div><div><br></div><div>Can you elaborate on what you have in mind with regards to improved CoW support? Is there any chance of doing something here in Swift 3?</div> <div>-Matthew</div></body></html>