<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 &lt;<a href="mailto:atrick@apple.com">atrick@apple.com</a>&gt; 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 &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; 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&lt;T&gt; 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&lt;T&gt; 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 ==. &nbsp;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="">&nbsp;Array&lt;T: SomeConstraint&gt;</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. &nbsp;</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&lt;T&gt; 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. &nbsp;The same can be said of some semantic requirements in existing protocols, such as complexity requirements. &nbsp;It is fair to observe that there is a difference here - not meeting complexity requirement slows things down, but doesn't fundamentally break. &nbsp;Another example is the requirement to always return nil after you reach the end of&nbsp;<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. &nbsp;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="">&nbsp; func compute() -&gt; Result // nonmutating</div><div class="">}</div><div class=""><br class=""></div><div class="">func g(v1 : ValueP) {</div><div class="">&nbsp; let v2 = v1</div><div class="">&nbsp; v1.compute()</div><div class="">&nbsp; 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="">&nbsp; @strawman_noglobal func compute() -&gt; 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) -&gt; (Result, Result) {</div><div class="">&nbsp; let r1 = v1.compute()</div><div class="">&nbsp; if v1 == v2 {</div><div class="">&nbsp; &nbsp; return (r1, r1)</div><div class="">&nbsp; }</div><div class="">&nbsp; 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. &nbsp;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. &nbsp;I didn't mean to give a sense of urgency on this and am not attached to a specific mechanism. &nbsp;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&lt;UIView&gt;). &nbsp;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. &nbsp;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. &nbsp;</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. &nbsp;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. &nbsp;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? &nbsp;Is there any chance of doing something here in Swift 3?</div>&nbsp;<div>-Matthew</div></body></html>