[swift-evolution] pure functions

Andrew Bennett cacoyi at gmail.com
Fri Sep 29 02:38:53 CDT 2017


> 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.

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.

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.

Purity could initial be defined in two levels, weak and strong.

   - *strong purity*: everything in the function has strong purity, what
   we've been discussing
   - *weak purity*: everything in the function is strong-pure, weak-pure,
   or says "trust me"


The following code suggest how this might work, it introduces a few things:

   - *pure* keyword, indicates that a function is has either weak or strong
   purity
   - *pretendPure* (ignore the name) pretends whatever happens inside it is
   pure, it has weak purity

func strongPurityFunction(_ lhs: Int, rhs: Int) pure -> Int {

    return lhs + rhs

}


func weakPurityFunction(value: Int) pure -> Int {

    return pretendPure {

        functionFromAnotherLibrary(value)

    }

}


func anotherWeakPurityFunction(value: Int) pure -> Int {

    return weakPurityFunction(value: value)

}



When this gets compiled to SIL the pure annotations would specialised as:

func strongPurityFunction(_ lhs: Int, rhs: Int) _strong_pure -> Int
func weakPurityFunction(value: Int) _weak_pure -> Int

func anotherWeakPurityFunction(value: Int) _weak_pure -> Int



Marking a function as pure, but using an unannotated function could start
as a warning, then become an error.

func failingFunction(value: Int) pure -> Int {

    return nonPureFunction(value: value)

}


The staged rollout could go something like this:

   - _weak_pure only with *pretendPure* or equivalent
   - _strong_pure, _weak_pure, and *pretendPure*
   - _strong_pure, deprecate _weak_pure, and *pretendPure*
   - _strong_pure only



On Sun, Sep 10, 2017 at 3:01 PM, David Sweeris via swift-evolution <
swift-evolution at swift.org> wrote:

>
> > On Sep 9, 2017, at 10:48 AM, Dave Abrahams via swift-evolution <
> swift-evolution at swift.org> wrote:
> >
> > on Wed Aug 23 2017, Joe Groff <swift-evolution at swift.org> wrote:
> >>>> On Aug 18, 2017, at 12:10 PM, 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. 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.
> >> 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.
> >
> > 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.
>
> 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)
>
> 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.
>
> - Dave Sweeris
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170929/520cc5a0/attachment.html>


More information about the swift-evolution mailing list