<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 Feb 19, 2017, at 11:19 PM, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">This is very, very interesting. Thank you so much for the text.<div class=""><br class=""></div><div class="">If I understand your take correctly, the benefits of `pure` in Swift would be contingent on how pervasively it can be used (as it's the composability of pure functions that gives it exponential value). And, based on your discussion, very few functions in Swift would be compiler-provably pure, meaning any realistic adoption would have to mean "trust me, compiler, it's pure even though you can't prove it" as opposed to "go ahead, compiler, test my assertion that this function is pure." If Swift is to keep its promise of safety by default (granted, principally memory safety), this is going to have to prompt some soul-searching as to whether that's a very safe thing to add. It would also mean that lots of things would have to be manually annotated "trust me" after careful analysis of whether that trust is warranted, as opposed to the compiler being able to work that out for itself for free.<div class=""><div class=""><br class=""></div><div class="">Can I venture an operational definition of semantic purity? Maybe this would be a basis to talk about what "trust me, it's pure" would mean, if we wanted it:</div><div class=""><br class=""></div><div class="">Consider two variables `a` and `b`, without regard to whether they are instances of value types or reference types, and without regard to whether those types are Equatable.</div><div class=""><br class=""></div><div class="">```</div><div class="">let aa = a</div><div class="">let bb = b</div><div class="">```</div><div class=""><br class=""></div><div class="">Let's define, only for the purposes of this discussion and not as an actual syntax, a notion of pseudo-equality. We will say that `aa` is pseudo-equal to `a` and `bb` is pseudo-equal to `b`. (I deliberately choose not to conflate this notion with Equatable's `==` or with `===`.) Now, consider a function `f(_:_:)`.</div><div class=""><br class=""></div><div class="">```</div><div class="">let result1 = f(a, b)</div><div class="">// ...</div><div class="">// arbitrary code to be executed here</div><div class="">// ...</div><div class="">let result2 = f(aa, bb)</div><div class="">```</div><div class=""><br class=""></div><div class="">The function `f(_:_:)` is pure if, for any `aa` pseudo-equal to `a` and for any `bb` pseudo-equal to `b`, and for any arbitrary code in the middle, the snippet above could be replaced by the snippet below with no observable change in behavior:</div><div class=""><br class=""></div><div class="">```</div><div class="">let result1 = f(a, b)</div><div class="">// ...</div><div class="">// arbitrary code to be executed here</div><div class="">// ...</div><div class="">let result2 = result1</div><div class="">```</div><div class=""><br class=""></div><div class="">Now, this naive definition would preclude I/O and inout, but it would not preclude infinite loops, fatal errors, etc.</div></div></div></div></div></blockquote><div><br class=""></div><div>This looks like it corresponds with my intuition of pure. It is certainly a minimum requirement anything considered pure should meet (whether compiler verified or “trust me”). </div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><div class=""><div class="gmail_extra"><br class=""></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Sun, Feb 19, 2017 at 10:49 PM, Michel Fortin <span dir="ltr" class=""><<a href="mailto:michel.fortin@michelf.ca" target="_blank" class="">michel.fortin@michelf.ca</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word" class=""><div class="">The message about D was from me. I'm actually quite familiar with D so I'll try to summarize it's take on purity here.</div><div class=""><br class=""></div><div class=""># Pure in D</div><div class=""><br class=""></div><div class="">D has the keyword `pure`, and the compiler enforces purity constraints. There is basically two types of pure functions: strongly pure ones and weakly pure one, but in general when writing code you can ignore the distinction: they all use the same `pure` attribute. The strongly pure one is the kind that can be optimized because it has no side effect and its result can be reused. The weakly pure one is the kind that takes pointers to non-immutable memory and for which you either cannot guaranty a stable result across calls or cannot guaranty it won't mutate the memory behind those pointers. (Keep in mind that object references are a kind of pointer too.) The compiler examine the type of the parameters of a pure function to determine if they contain pointers (including pointers hidden in structs) and classify it as weakly or strongly pure.</div><div class=""><br class=""></div><div class="">Pure functions are allowed to throw, to exit the program, to run infinite loops, and to allocate memory. They can't access global variables unless they are immutable (constant), or they are passed as an argument using a pointer. </div><div class=""><br class=""></div><div class="">All pure functions can only call other pure functions. This is the part where weakly pure is useful: a strongly pure function can call a weakly pure function since the weakly pure one will only be able to mutate the local state of the enclosing strongly pure function, always in a deterministic way.</div><div class=""><br class=""></div><div class="">In D, `const` and `immutable` are transitive attributes, meaning that any memory accessed through such pointer is also `const` or `immutable`. So if you pass a `const` or `immutable` value to a function in D, it won't be able to mutate anything. This makes many functions strongly pure even in the presence of pointers.</div><div class=""><br class=""></div><div class="">`pure` in D can also be used to create guarantied uniquely referenced objects and object hierarchies, which then can then become transitively immutable once they are returned by the pure function.</div><div class=""><br class=""></div><div class="">`pure` works so well in D that most functions are actually pure. There is some pressure in libraries to mark functions as pure because their functions then become usable inside other pure functions, which means that as time passes more and more functions get the pure attribute. To ease the burden of adding these attributes everywhere, pure is inferred for template functions (and only template functions, because non templates are allowed to be opaque).</div><div class=""><br class=""></div><div class="">Official reference: <a href="https://dlang.org/spec/function.html#pure-functions" target="_blank" class="">https://dlang.org/spec/<wbr class="">function.html#pure-functions</a></div><div class=""><br class=""></div><div class=""># Pure in Swift?</div><div class=""><br class=""></div><div class="">Because Swift does not have that concept of transitive immutability, I'm under the impression that very few functions would be "strongly pure" in Swift, making optimizations impossible except for the trivial value types. Or, maybe, when a "trust me" attribute vouch that the implementation of a value type is pure-compatible.</div><div class=""><br class=""></div><div class="">But I'd be wary about relying much on a "trust me" attribute, as it greatly diminish the value of having `pure` in the first place. Add a "trust me" at the wrong place and the compiler will not complain when it should. Forget a "trust me" somewhere and the compiler will complain where it should not. The ratio of "trust me"/`pure` has to be very small for the whole purity system to be valuable.</div><div class=""><br class=""></div><div class="">The way I see it, `pure` is likely to make things more complicated for everyone, not just for those who want to use pure. Those who want to use pure will be asking for everything they want to use to be labeled correctly (either with `pure` or "trust me", whichever works).</div><div class=""><br class=""></div><div class=""># What about constexpr?</div><div class=""><br class=""></div><div class="">That's the name of a C++ feature where the compiler evaluates a function at compile time to set the value of a constant. This obviously only works for functions with no side effects. `constexpr` is the keyword attached to those functions.</div><div class=""><a href="http://en.cppreference.com/w/cpp/language/constexpr" target="_blank" class="">http://en.cppreference.com/w/<wbr class="">cpp/language/constexpr</a></div><div class=""><br class=""></div><div class="">The difference from `pure` is that this happens only at compile time. Which means you can implement it like D has done instead: treat all functions as evaluatable and only stop and emit an error upon reaching an instruction that cannot be evaluated. No special attribute needed. Only works for functions where the source code is available.</div><div class=""><a href="https://dlang.org/spec/function.html#interpretation" target="_blank" class="">https://dlang.org/spec/<wbr class="">function.html#interpretation</a></div><div class=""><br class=""></div><div class="">The D approach won't work for Swift across module boundaries, except perhaps for functions that can be inlined. For resilience you might want an attribute to make it a contract that the inline version is compile-time evaluable.</div><div class=""><div class="gmail-h5"><div class=""><br class=""></div><div class=""><br class=""></div>Le 19 févr. 2017 à 20:58, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> a écrit :<br class=""><div class=""><blockquote type="cite" class=""><br class="gmail-m_3725187869282566811Apple-interchange-newline"><div class="">I don't know very much about this topic, so I won't pretend that I have strong feelings about Michel's questions, but they are undeniably important and undoubtedly only one of many.<br class=""><br class="">Before we get to any syntactic bikeshedding, can the proponents of this feature write up a comparative summary to educate us about the current state of the art? How have other languages have defined purity? I recall an earlier message about D, and some rough comparisons or non-comparisons to C++ constexpr. Roughly, it would be very helpful to get some sense of the following:<br class=""><br class="">What other C-family languages have a concept of purity?<br class=""><br class="">How is purity defined in those languages?<br class=""><br class="">What use cases are enabled by those definitions of purity, and just as important, what use cases are notably excluded by them?<br class=""><br class="">If there is evidence in the public record to this effect: if the designers of those languages could do it again, have they expressed any thoughts about how they would do it differently with respect to purity?<br class=""><br class="">It has been said that Haskell and other functional languages prioritize purity over ergonomics of impure functions like I/O. With that in mind, what design choices surrounding purity made by those languages are off-limits for Swift?<br class=""><br class="">What use cases or even compiler optimizations are possible in Haskell and other non-C family languages with a more expansive or stricter concept of pure functions that we don't find in C-family languages?<br class=""><br class="">If Swift were to adopt some of these beyond-C rules, how would that impact the user experience with common impure functions (I/O, etc.)?<br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Sun, Feb 19, 2017 at 14:45 T.J. Usiyan via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr" class="gmail-m_3725187869282566811gmail_msg">I'm going to update the draft with points addressed here and the twitter conversation. There have been quite a few implications to consider pointed out. <div class="gmail-m_3725187869282566811gmail_msg"><br class="gmail-m_3725187869282566811gmail_msg"></div><div class="gmail-m_3725187869282566811gmail_msg">This feature is not 'for' the compiler as much as it is for humans writing code, but I will address that in the update.</div></div><div class="gmail_extra gmail-m_3725187869282566811gmail_msg"><br class="gmail-m_3725187869282566811gmail_msg"><div class="gmail_quote gmail-m_3725187869282566811gmail_msg">On Sun, Feb 19, 2017 at 3:34 PM, David Sweeris <span dir="ltr" class="gmail-m_3725187869282566811gmail_msg"><<a href="mailto:davesweeris@mac.com" class="gmail-m_3725187869282566811gmail_msg" target="_blank">davesweeris@mac.com</a>></span> wrote:<br class="gmail-m_3725187869282566811gmail_msg"><blockquote class="gmail_quote gmail-m_3725187869282566811gmail_msg" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto" class="gmail-m_3725187869282566811gmail_msg"><div class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"></span></div><div class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"></span><br class="gmail-m_3725187869282566811gmail_msg"><blockquote type="cite" class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg">On Feb 19, 2017, at 11:47, Michel Fortin via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="gmail-m_3725187869282566811gmail_msg" target="_blank">swift-evolution@swift.org</a>> wrote:</span><br class="gmail-m_3725187869282566811gmail_msg"></blockquote><blockquote type="cite" class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"></span><br class="gmail-m_3725187869282566811gmail_msg"></blockquote><blockquote type="cite" class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg">7. Is it desirable that the optimizer sometime take the pure attribute to heart to combine multiple apparently redundant calls into a single one? Or is pure not intended to be usable for compiler optimizations? The ability to optimize will likely be affected by the answer to these question and the loopholes you are willing to allow.</span><br class="gmail-m_3725187869282566811gmail_msg"></blockquote><span class="gmail-m_3725187869282566811gmail_msg"></span><br class="gmail-m_3725187869282566811gmail_msg"></span><span class="gmail-m_3725187869282566811gmail_msg">AFAIK, "compiler optimizations" are main point of having a keyword for pure functions. (Well, that and whatever role it might play in supporting constant expressions, but that seems like more of a compiler implementation detail than an actual "feature" of pure functions.)</span><br class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"></span><br class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg">Calling fatalError() is fine IMHO because, at that point, any side-effects become a moot point.</span><br class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"></span><br class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg">I'm inclined to say that passing in reference values is ok, as long as we can prove the function doesn't modify anything. Don't know how we'd do that, though, since classes don't need that `mutating` keyword for functions that mutate `self`.</span></div><div class="gmail-m_3725187869282566811gmail_msg"><span class="gmail-m_3725187869282566811gmail_msg"><br class="gmail-m_3725187869282566811gmail_msg"></span></div><div class="gmail-m_3725187869282566811gmail_msg">If someone is determined to use pointers to pointers to get global state or something to trick the compiler into accepting <i class="gmail-m_3725187869282566811gmail_msg">semantically</i> impure code as <i class="gmail-m_3725187869282566811gmail_msg">syntactically</i> pure, I'm not sure there's a way we can really stop them. Not and still have @pure be useful. (Or maybe we can... I'm merely thinking of the saying, "every time someone builds a fool-proof system, the world makes a bigger fool".)<br class="gmail-m_3725187869282566811gmail_msg"><br class="gmail-m_3725187869282566811gmail_msg">I would think that allocating memory is ok, as long as it's either deallocated by the time the function exits or it's part of the return value, but I don't know a lot about low-level implementation details, so maybe there's something I'm missing. If that is a problem, though, I think the answer to your "what subset..." question would, more or less, be whatever subset doesn't rely on the runtime (the usefulness of that subset should expand if/when we extend the syntax around tuples or support fixed-length arrays in some other way).</div><div class="gmail-m_3725187869282566811gmail_msg"><br class="gmail-m_3725187869282566811gmail_msg"></div><div class="gmail-m_3725187869282566811gmail_msg">In any case, yeah, IMHO you're correct that we should nail down the semantics before worrying so much about the syntax.</div><div class="gmail-m_3725187869282566811gmail_msg"><br class="gmail-m_3725187869282566811gmail_msg"></div><div class="gmail-m_3725187869282566811gmail_msg">- Dave Sweeris</div></div></blockquote></div><br class="gmail-m_3725187869282566811gmail_msg"></div>
______________________________<wbr class="">_________________<br class="gmail-m_3725187869282566811gmail_msg">
swift-evolution mailing list<br class="gmail-m_3725187869282566811gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="gmail-m_3725187869282566811gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="gmail-m_3725187869282566811gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="gmail-m_3725187869282566811gmail_msg" target="_blank">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="gmail-m_3725187869282566811gmail_msg">
</blockquote></div>
______________________________<wbr class="">_________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class=""></div></blockquote></div><br class=""></div></div><span class="gmail-"><div class="">
<div style="letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; word-wrap: break-word;" class=""><div style="letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; word-wrap: break-word;" class=""><div style="letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; word-wrap: break-word;" class=""><div style="font-family: helvetica; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; word-wrap: break-word;" class=""><span class="gmail-m_3725187869282566811Apple-style-span" style="border-collapse: separate; font-family: helvetica; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><div style="word-wrap:break-word" class=""><span class="gmail-m_3725187869282566811Apple-style-span" style="border-collapse: separate; font-family: helvetica; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><div style="word-wrap:break-word" class=""><span class="gmail-m_3725187869282566811Apple-style-span" style="border-collapse: separate; font-family: helvetica; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-east-asian: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><div style="word-wrap:break-word" class="">-- <br class="">Michel Fortin</div><div style="word-wrap:break-word" class=""><span style="text-align:-webkit-auto" class=""><a href="https://michelf.ca/" target="_blank" class="">https://michelf.ca</a></span></div></span></div></span></div></span></div></div></div></div>
</div>
<br class=""></span></div></blockquote></div><br class=""></div></div></div></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>