<div dir="ltr"><div>> <span style="font-size:12.800000190734863px">As Andy says, the major problem is that public API (which you can't see the implementation of in general) would all need to be marked up properly.</span></div><div><br></div>The use-case I'm most interested in is reducing programmer error, I'm personally not too concerned about optimisations achieved by "pure" at this stage.<div><br></div><div>This means I'd be happy in the short-term to ignore a verified strong purity requirement, and allow "pure" to be achieved in multiple stages/releases. A gradual adoption would also make it easier to enforce the concept strictly in future.</div><div><br></div><div>Purity could initial be defined in two levels, weak and strong.</div><div><ul><li><b>strong purity</b>: everything in the function has strong purity, what we've been discussing</li><li><b>weak purity</b>: everything in the function is strong-pure, weak-pure, or says "trust me"</li></ul><div><br></div><div>The following code suggest how this might work, it introduces a few things:</div><div><ul><li><span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px"><b>pure</b></span> keyword, indicates that a function is has either weak or strong purity<br></li><li><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"><b>pretendPure</b></span> (ignore the name) pretends whatever happens inside it is pure, it has weak purity</li></ul></div></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="color:rgb(4,51,255)">func</span> strongPurityFunction(<span style="color:rgb(4,51,255)">_</span> lhs: <span style="color:rgb(52,149,175)">Int</span>, rhs: <span style="color:rgb(52,149,175)">Int</span>) <span style="color:rgb(4,51,255)">pure</span> -> <span style="color:rgb(52,149,175)">Int</span> {</p></div></div></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"> <span style="color:rgb(4,51,255)">return</span> lhs + rhs</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)">}</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Helvetica;min-height:14px"><br></p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="color:rgb(4,51,255)">func</span> weakPurityFunction(value: <span style="color:rgb(52,149,175)">Int</span>) <span style="color:rgb(4,51,255)">pure</span> -> <span style="color:rgb(52,149,175)">Int</span> {</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"> <span style="color:rgb(4,51,255)">return</span> pretendPure {</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"> functionFromAnotherLibrary(<wbr>value)</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"> }</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)">}</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Helvetica;min-height:14px"><br></p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="color:rgb(4,51,255)">func</span> anotherWeakPurityFunction(<wbr>value: <span style="color:rgb(52,149,175)">Int</span>) <span style="color:rgb(4,51,255)">pure</span> -> <span style="color:rgb(52,149,175)">Int</span> {</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"> <span style="color:rgb(4,51,255)">return</span> <span style="color:rgb(52,149,175)">weakPurityFunction</span>(value: value)</p></div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)">}</p></div></blockquote><font color="#000000" face="Menlo"><span style="font-size:12px"><br></span></font><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><br></p></div></blockquote>When this gets compiled to SIL the pure annotations would specialised as:<font color="#000000" face="Menlo"><span style="font-size:12px"><br></span></font><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"></p><div style="color:rgb(34,34,34);font-family:arial,sans-serif"></div><p></p><span style="font-family:Menlo;font-size:12px;color:rgb(4,51,255)">func</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"> strongPurityFunction(</span><span style="font-family:Menlo;font-size:12px;color:rgb(4,51,255)">_</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"> <wbr>lhs: </span><span style="font-family:Menlo;font-size:12px;color:rgb(52,149,175)">Int</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px">, rhs: </span><span style="font-family:Menlo;font-size:12px;color:rgb(52,149,175)">Int</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px">) </span><span style="font-family:Menlo;font-size:12px;color:rgb(4,51,255)">_strong_pure</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"> -> </span><span style="font-family:Menlo;font-size:12px;color:rgb(52,149,175)">Int</span><br><span style="font-family:Menlo;font-size:12px;color:rgb(4,51,255)">func</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"> weakPurityFunction(value:<wbr> </span><span style="font-family:Menlo;font-size:12px;color:rgb(52,149,175)">Int</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px">) </span><span style="font-family:Menlo;font-size:12px;color:rgb(4,51,255)">_weak_pure</span><span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"> -> </span><span style="font-family:Menlo;font-size:12px;color:rgb(52,149,175)">Int</span><br><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="color:rgb(4,51,255)">func</span> <wbr>anotherWeakPurityFunction(<wbr>value: <span style="color:rgb(52,149,175)">Int</span>) <span style="color:rgb(4,51,255)">_weak_pure</span> -> <span style="color:rgb(52,149,175)">Int</span></p></div></blockquote><font color="#000000" face="Menlo"><span style="font-size:12px"><div><font color="#000000" face="Menlo"><span style="font-size:12px"><br></span></font></div></span></font><div><br></div>Marking a function as pure, but using an unannotated function could start as a warning, then become an error.<div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"><span style="color:rgb(4,51,255)">func</span> failingFunction(value: <span style="color:rgb(52,149,175)">In<wbr>t</span>) <span style="color:rgb(4,51,255)">pure</span> -> <span style="color:rgb(52,149,175)">Int</span> {</p></div></div><div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)"> <span style="color:rgb(4,51,255)">return</span> <span style="color:rgb(52,149,175)">nonPureFunction</span>(<wbr>value: value)</p></div></div><div><div><p style="margin:0px;font-stretch:normal;font-size:12px;line-height:normal;font-family:Menlo;color:rgb(0,0,0)">}</p></div></div></blockquote><div><br></div>The staged rollout could go something like this:<div><ul><li><span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px">_weak_pure</span> only with <b style="color:rgb(0,0,0);font-family:Menlo;font-size:12px">pretendPure</b> or equivalent</li><li><span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px">_strong_pure</span>, <span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px">_weak_pure</span>, and <span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"><b>pretendPure</b></span></li><li><span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px">_strong_pure</span>, deprecate <span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px">_weak_pure</span>, and <span style="color:rgb(0,0,0);font-family:Menlo;font-size:12px"><b>pretendPure</b></span></li><li><span style="color:rgb(4,51,255);font-family:Menlo;font-size:12px">_strong_pure</span> only</li></ul><div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Sep 10, 2017 at 3:01 PM, David Sweeris via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
> On Sep 9, 2017, at 10:48 AM, Dave Abrahams via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
><br>
> on Wed Aug 23 2017, Joe Groff <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
>>>> On Aug 18, 2017, at 12:10 PM, Chris Lattner via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote: Splitting this out from the concurrency thread:<br>
>>>><br>
>>>>> On Aug 18, 2017, at 6:12 AM, Matthew Johnson <<a href="mailto:matthew@anandabits.com">matthew@anandabits.com</a>> wrote:<br>
>>>>>> On Aug 17, 2017, at 11:53 PM, Chris Lattner <<a href="mailto:clattner@nondot.org">clattner@nondot.org</a>> wrote:<br>
>>>>>> In the manifesto you talk about restrictions on passing functions across an actor message. You didn’t discuss pure functions, presumably because Swift doesn’t have them yet. I imagine that if (hopefully when) Swift has compiler support for verifying pure functions these would also be safe to pass across an actor message. Is that correct?<br>
>>>>> Correct. The proposal is specifically/intentionally designed to be light on type system additions, but there are many that could make it better in various ways. The logic for this approach is that I expect *a lot* of people will be writing mostly straight-forward concurrent code, and that goal is harmed by presenting significant type system hurdles for them to jump over, because that implies a higher learning curve. This is why the proposal doesn’t focus on a provably memory safe system: If someone slaps “ValueSemantical” on a type that doesn’t obey, they will break the invariants of the system. There are lots of ways to solve that problem (e.g. the capabilities system in Pony) but it introduces a steep learning curve. I haven’t thought a lot about practically getting pure functions into Swift, because it wasn’t clear what problems it would solve (which couldn’t be solved another way). You’re right though that this could be an interesting motivator.<br>
>>>> I can provide a concrete example of why this is definitely and important motivator. My current project uses pure functions, value semantics and declarative effects at the application level and moves as much of the imperative code as possible (including effect handling) into library level code. This is working out really well and I plan to continue with this approach. The library level code needs the ability to schedule user code in the appropriate context. There will likely be some declarative ability for application level code to influence the context, priority, etc, but it is the library that will be moving the functions to the final context. They are obviously not closure literals from the perspective of the library. Pure functions are obviously important to the semantics of this approach. We can get by without compiler verification, using documentation just as we do for protocol requirements that can't be verified. That said, it would be pretty disappointing to have to avoid using actors in the implementation simply because we can't move pure functions from one actor to another as necessary. To be clear, I am talking in the context of "the fullness of time". It would be perfectly acceptable to ship actors before pure functions. That said, I do think it's crucial that we eventually have the ability to verify pure functions and move them around at will.<br>
>>> Right. Pure functions are also nice when you care about thread safety, and there is a lot of work on this. C has __attribute__((const)) and ((pure)) for example, c++ has constexpr, and many research languages have built full blown effects systems. My principle concern is that things like this quickly become infectious: LOTS of things are pure functions, and requiring them all to be marked as such becomes a lot of boilerplate and conceptual overhead. This is happening in the C++ community with constexpr for example. The secondary concern is that you need to build out the model enough that you don’t prevent abstractions. A pure function should be able to create an instance of a struct, mutate it (i.e. calling non-pure functions) etc. This requires a non-trivial design, and as the design complexity creeps, you run the risk of it getting out of control.<br>
>> Now that inout parameters are guaranteed exclusive, a mutating method on a struct or a function that takes inout parameters is isomorphic to one that consumes the initial value as a pure argument and returns the modified value back. This provides a value-semantics-friendly notion of purity, where a function can still be considered pure if the only thing it mutates is its unescaped local state and its inout parameters and it doesn't read or write any shared mutable state such as mutable globals, instance properties, or escaped variables. That gives you the ability to declare local variables and composably apply "pure" mutating operations to them inside a pure function. We've already brought Swift somewhat into the effects-system design space with "throws" (and "async", if it gets taken as we've currently proposed it), and we already have some abstraction debt to pay off with "throws"; if we wanted to, we could conceivably fold "impure" into that system as well. While it's true that there would be a lot of effort in propagating pure annotations to the right places, that's going to be true of any attempt to move the current everything-goes world into a more robust and constrained framework. I don't think we should write off the notion completely.<br>
><br>
> I agree with Joe here... in principle. We keep finding features we want to add that have effects-system-like semantics, and I expect that we will continue to do so. The best language design would probably result from addressing this category of feature in some holistic way. My main concern is that in practice, it seems unlikely to be doable before ABI lockdown makes it too late.<br>
<br>
</span>Is there anything in particular that would make it more likely to be doable before ABI lockdown? (Other that pushing it back again, I mean)<br>
<br>
I'd guess that if it were as simple as adding a few "reserved for future use" bits in the on-disk representation, you wouldn't have raised the issue.<br>
<br>
- Dave Sweeris<br>
<div class="HOEnZb"><div class="h5">______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
</div></div></blockquote></div><br></div>