[swift-evolution] pure functions
davesweeris at mac.com
Fri Aug 18 16:45:02 CDT 2017
> On Aug 18, 2017, at 12:11, Chris Lattner via swift-evolution <swift-evolution at swift.org> wrote:
> Splitting this out from the concurrency thread:
>>> On Aug 18, 2017, at 6:12 AM, Matthew Johnson <matthew at anandabits.com> wrote:
>>>> On Aug 17, 2017, at 11:53 PM, Chris Lattner <clattner at nondot.org> wrote:
>>>> 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?
>>> 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.
>> 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.
> 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.
At a rough guess, how many of the stdlib's functions could realistically have their purity inferred?
If we define our semantics carefully enough, could we realistically make it so that "@pure" or "@impure" (or whatever) would simply be a note to the compiler, letting it skip that bit of analysis for the function in question?
> 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.
Did we ever get around to figuring which definition(s) of "pure" that we wanted to support, or did the discussion always get out of scope before we got that far? I know the issue's been brought up, but I don't recall if it was discussed enough to reach any conclusions.
- Dave Sweeris
More information about the swift-evolution