Proposal proposal: @pure keyword


(Andrew Bennett) #1

I'd like to discuss adding a @pure keyword, and see what it requires and
how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

This will allow us to make more guarantees about what a protocol does, and
what it cannot do. It will also allow APIs like `.map` and `.forEach` to
have a meaningful distinction. It could also allow for something like an
assert to be removed as an optimisation with no side-effects in a release
build.

If something is pure it can be annotated with @pure, if it is not-pure this
will be a compile-time error. The compiler could automatically add this
annotation in the interface.

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this
includes referencing self from a method or property)
* it only externally references let variables of pure type, let properties
on those variables, and methods/computer-properties marked as pure.

A computed property can be marked as pure like this:

@pure var test: A

A function/method/closure signature is marked as pure like this:

(a: A, b: A -> B) @pure -> B

If the function/method/closure is only pure if an argument is pure (similar
to @rethrows), then you could do this:

(start: A, a: A -> B) @pure(b) -> B

Potentially this could be extended to allow a pure closure to be composed
of other pure closures:

func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C {

    return { b(a($0)) }

}

Of course this doesn't preclude you from requiring some of those closures
to be pure:

func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C {

    return { b(a($0)) }

}

Impact on existing code:

No negative impact as if automatic annotation was allowed it would only
happen where it was safe to do so. If it was not allowed then libraries
could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is
not used. From this perspective assert and print should not be marked as
pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but
this can be a gradual process.


(Matthew Johnson) #2

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this includes referencing self from a method or property)
* it only externally references let variables of pure type, let properties on those variables, and methods/computer-properties marked as pure.

I'm concerned that with this definition we won't be able to mark many APIs as pure, even though they actually are pure. The issue is that this definition disallows local mutation. Consider CollectionType.sort() -- the way it is implemented is that it first copies the collection into an array, and then sorts that array in-place. sortInPlace() isn't pure, but because the mutation happens on local state, the whole operation is pure.

The way I ready it is "it only externally references let variables of pure type, let properties on those variables, and methods/computer-properties marked as pure.

Externally is the key word here, which would allow for internal / local mutation. Note: properties of self would be an external reference.

···

On Jan 9, 2016, at 4:29 AM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:
On Sat, Jan 9, 2016 at 10:53 AM, Andrew Bennett via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>>*/
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Michel Fortin) #3

This is actually the most important part to define. There are many ways to define it, each with different tradeoffs. Here are the two base ones:

1. Pure means that the function always return the same value given the same arguments, and has no side effects (it purely computes a result from its inputs), making it possible for the compiler, or a cache, to reuse the result from a previous call. This is the simplest definition, and it provide strong guaranties. Let's call that "strongly pure".

2. Pure just mean that the function has no access to global variables. It can only mutate "outside" things through inout parameters or pointers (including class references) passed to it by the caller. So in the general case you can't reuse the results. But you can use this function to mutate the state inside a strongly pure one. A strongly pure function in this case is one with no inout or pointer in the signature.

It makes more sense to use (2) to define `@pure` in my opinion. Note that this is what the D language has done, after noticing it to be much more useful than what they had before before, which was (1).

All that's good in theory, but there is a major detail that needs addressing. Memory allocation breaks the guaranties of a "strongly pure" function. For instance, if you return a newly allocated object, or a struct with a pointer to an object, the object is going to be a different one every time. That object is mutable memory, and returning a different chunk of mutable memory is quite different in semantics from returning the same one. If you want strong purity guaranties when returning objects (and thus be able to optimize by reusing the result from a previous call), there needs to be a way to return objects that have a language-enforced guaranty of immutability... same for structs that can have a pointer to an object or other memory. Without immutability guaranties, `@pure` has almost no optimization value.

···

Le 9 janv. 2016 à 8:16, Angelo Villegas via swift-evolution <swift-evolution@swift.org> a écrit :

I'm not yet really familiar with this term but correct me if I'm wrong, "pure" (function wise) means functions won't have access to global or static, and mutable variables through their arguments, right?

--
Michel Fortin
https://michelf.ca


(Dmitri Gribenko) #4

I'm concerned that with this definition we won't be able to mark many APIs
as pure, even though they actually are pure. The issue is that this
definition disallows local mutation. Consider CollectionType.sort() -- the
way it is implemented is that it first copies the collection into an array,
and then sorts that array in-place. sortInPlace() isn't pure, but because
the mutation happens on local state, the whole operation is pure.

Dmitri

···

On Sat, Jan 9, 2016 at 10:53 AM, Andrew Bennett via swift-evolution < swift-evolution@swift.org> wrote:

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this
includes referencing self from a method or property)
* it only externally references let variables of pure type, let
properties on those variables, and methods/computer-properties marked as
pure.

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Angelo Villegas) #5

I'm not yet really familiar with this term but correct me if I'm wrong, "pure" (function wise) means functions won't have access to global or static, and mutable variables through their arguments, right?

···

On Sat, Jan 9, 2016 at 12:54 AM -0800, "Andrew Bennett via swift-evolution" <swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and how possible it is to include.
I'd like to use the annotation @pure on functions, methods and closures.
This will allow us to make more guarantees about what a protocol does, and what it cannot do. It will also allow APIs like `.map` and `.forEach` to have a meaningful distinction. It could also allow for something like an assert to be removed as an optimisation with no side-effects in a release build.
If something is pure it can be annotated with @pure, if it is not-pure this will be a compile-time error. The compiler could automatically add this annotation in the interface.
A function, method or closure is pure if: * all functions, methods and closures it calls are also pure (this includes referencing self from a method or property) * it only externally references let variables of pure type, let properties on those variables, and methods/computer-properties marked as pure.
A computed property can be marked as pure like this:@pure var test: A
A function/method/closure signature is marked as pure like this:(a: A, b: A -> B) @pure -> B
If the function/method/closure is only pure if an argument is pure (similar to @rethrows), then you could do this:(start: A, a: A -> B) @pure(b) -> B
Potentially this could be extended to allow a pure closure to be composed of other pure closures:func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C { return { b(a($0)) }}
Of course this doesn't preclude you from requiring some of those closures to be pure:func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C { return { b(a($0)) }}
Impact on existing code:No negative impact as if automatic annotation was allowed it would only happen where it was safe to do so. If it was not allowed then libraries could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is not used. From this perspective assert and print should not be marked as pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but this can be a gradual process.


(Chris Lattner) #6

FYI, this has come up before, please catch up on the thread:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003684.html

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/003900.html

-Chris

···

On Jan 9, 2016, at 12:53 AM, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.


(Howard Lovatt) #7

I would rather you mark a function as impure and have the default as pure!

···

On 9 Jan 2016, at 7:53 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

This will allow us to make more guarantees about what a protocol does, and what it cannot do. It will also allow APIs like `.map` and `.forEach` to have a meaningful distinction. It could also allow for something like an assert to be removed as an optimisation with no side-effects in a release build.

If something is pure it can be annotated with @pure, if it is not-pure this will be a compile-time error. The compiler could automatically add this annotation in the interface.

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this includes referencing self from a method or property)
* it only externally references let variables of pure type, let properties on those variables, and methods/computer-properties marked as pure.

A computed property can be marked as pure like this:
@pure var test: A

A function/method/closure signature is marked as pure like this:
(a: A, b: A -> B) @pure -> B

If the function/method/closure is only pure if an argument is pure (similar to @rethrows), then you could do this:
(start: A, a: A -> B) @pure(b) -> B

Potentially this could be extended to allow a pure closure to be composed of other pure closures:
func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C {
    return { b(a($0)) }
}

Of course this doesn't preclude you from requiring some of those closures to be pure:
func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C {
    return { b(a($0)) }
}

Impact on existing code:
No negative impact as if automatic annotation was allowed it would only happen where it was safe to do so. If it was not allowed then libraries could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is not used. From this perspective assert and print should not be marked as pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but this can be a gradual process.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Yang Wu) #8

So you are talking about idempotence.

HTTP/1.1 defined it as:

Methods can also have the property of "idempotence" in that (aside from
error or expiration issues) the side-effects of N > 0 identical requests is
the same as for a single request.

···

On Sat, Jan 9, 2016 at 11:01 PM, Michel Fortin via swift-evolution < swift-evolution@swift.org> wrote:

Le 9 janv. 2016 à 8:16, Angelo Villegas via swift-evolution < > swift-evolution@swift.org> a écrit :

> I'm not yet really familiar with this term but correct me if I'm wrong,
"pure" (function wise) means functions won't have access to global or
static, and mutable variables through their arguments, right?

This is actually the most important part to define. There are many ways to
define it, each with different tradeoffs. Here are the two base ones:

1. Pure means that the function always return the same value given the
same arguments, and has no side effects (it purely computes a result from
its inputs), making it possible for the compiler, or a cache, to reuse the
result from a previous call. This is the simplest definition, and it
provide strong guaranties. Let's call that "strongly pure".

2. Pure just mean that the function has no access to global variables. It
can only mutate "outside" things through inout parameters or pointers
(including class references) passed to it by the caller. So in the general
case you can't reuse the results. But you can use this function to mutate
the state inside a strongly pure one. A strongly pure function in this case
is one with no inout or pointer in the signature.

It makes more sense to use (2) to define `@pure` in my opinion. Note that
this is what the D language has done, after noticing it to be much more
useful than what they had before before, which was (1).

All that's good in theory, but there is a major detail that needs
addressing. Memory allocation breaks the guaranties of a "strongly pure"
function. For instance, if you return a newly allocated object, or a struct
with a pointer to an object, the object is going to be a different one
every time. That object is mutable memory, and returning a different chunk
of mutable memory is quite different in semantics from returning the same
one. If you want strong purity guaranties when returning objects (and thus
be able to optimize by reusing the result from a previous call), there
needs to be a way to return objects that have a language-enforced guaranty
of immutability... same for structs that can have a pointer to an object or
other memory. Without immutability guaranties, `@pure` has almost no
optimization value.

--
Michel Fortin
https://michelf.ca

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue
<http://www.pinxue.net>


(Andrew Bennett) #9

Dmitri,

Thanks, that's a good point. That's related to why I was wondering about
self as inout in my reply to Howard. My rules were a starting point, I'm
sure there's things that can be improved. I'm glad we've got the
conversation started :slight_smile:

The type of Array<Int>.sort is (Array<Int>) -> () -> Array<Int>

This type could be marked as pure like this:

(Array<Int>) @pure -> () @pure -> Array<Int>

The partial application of the function captures the current state of the
input array (value type), then the full application of the function sorts
and returns that array. I don't think there's a problem with purity here,
there's on *external* references.

It gets more interesting with a mutating function, Array<Int>.sortInPlace
is potentially pure as well:

(inout Array<Int>) @pure -> Void

This type signature could be considered equivalent to the type of
Array<Int>.sort. You're taking an array in, and sending an array out. It's
replacing the in array with the out one.

I think the important thing is that everything affected by the function is
in the type signature.

Andrew

···

On Sat, Jan 9, 2016 at 9:29 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Sat, Jan 9, 2016 at 10:53 AM, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> wrote:

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this
includes referencing self from a method or property)
* it only externally references let variables of pure type, let
properties on those variables, and methods/computer-properties marked as
pure.

I'm concerned that with this definition we won't be able to mark many APIs
as pure, even though they actually are pure. The issue is that this
definition disallows local mutation. Consider CollectionType.sort() -- the
way it is implemented is that it first copies the collection into an array,
and then sorts that array in-place. sortInPlace() isn't pure, but because
the mutation happens on local state, the whole operation is pure.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Andrew Bennett) #10

Thanks Chris, I've caught up on that thread now. Somehow between then and
new-years I'd forgotten about it (I didn't party *that* hard). I think I
searched the December archive but it seems to only be two days of December
so far.

I'm not sure if there's a good way to merge threads, but I suggest we move
the conversation there. I'm not sure how to reference this thread from that
one though as it's not yet archived.

···

On Sun, Jan 10, 2016 at 12:31 PM, Chris Lattner <clattner@apple.com> wrote:

On Jan 9, 2016, at 12:53 AM, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and
how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

FYI, this has come up before, please catch up on the thread:

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003684.html

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151221/003900.html

-Chris


(John Randolph) #11

On a related note, I can imagine a circumstance where a function might not meet the first definition here of “pure”, but I would still want the compiler to go ahead reuse the result of the first call it gets, throughout a given scope. Say for example that I want to expensively look up some user info, and I can rely on that not changing during a single run of my app.

Qualifying a method with something like @resultsReusable would cover the situation I have in mind.

-jcr

···

On Jan 9, 2016, at 7:01 AM, Michel Fortin via swift-evolution <swift-evolution@swift.org> wrote:

Le 9 janv. 2016 à 8:16, Angelo Villegas via swift-evolution <swift-evolution@swift.org> a écrit :

I'm not yet really familiar with this term but correct me if I'm wrong, "pure" (function wise) means functions won't have access to global or static, and mutable variables through their arguments, right?

This is actually the most important part to define. There are many ways to define it, each with different tradeoffs. Here are the two base ones:

1. Pure means that the function always return the same value given the same arguments, and has no side effects (it purely computes a result from its inputs), making it possible for the compiler, or a cache, to reuse the result from a previous call. This is the simplest definition, and it provide strong guaranties. Let's call that "strongly pure".

2. Pure just mean that the function has no access to global variables. It can only mutate "outside" things through inout parameters or pointers (including class references) passed to it by the caller. So in the general case you can't reuse the results. But you can use this function to mutate the state inside a strongly pure one. A strongly pure function in this case is one with no inout or pointer in the signature.


(Michel Fortin) #12

I'm not so sure about this. By the above definition, making one request is the same thing as making two requests, but not necessarily the same as making zero requests.

···

Le 9 janv. 2016 à 10:09, 品雪 <pinxue@gmail.com> a écrit :

So you are talking about idempotence.

HTTP/1.1 defined it as:

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

--
Michel Fortin
https://michelf.ca


(Andrew Bennett) #13

That would be nice, although I'm not sure how practical that is in current
swift usage. I imagine it would require a lot of changes to existing code
and libraries.

Is a method impure if it uses self? I suppose it could be. I guess self is
an inout parameter. I presume an inout parameter is a known expected
side-effect.

Closures would probably be the largest impact if things were pure by
default.

It would be interesting though to do a code survey and see what portion
would need to be marked as @impure, and what conditions lead them to that
requirement.

I'm happy to discuss @impure too, but my focus is still @pure, as I think
it is a more attainable target, at the moment.

Perhaps after everything is annotated, impure functions are minimised, and
if swift is streamlined for pure function use, then we can introduce
@impure and deprecate @pure.

···

On Sat, Jan 9, 2016 at 7:56 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

I would rather you mark a function as impure and have the default as pure!

On 9 Jan 2016, at 7:53 PM, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and
how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

This will allow us to make more guarantees about what a protocol does, and
what it cannot do. It will also allow APIs like `.map` and `.forEach` to
have a meaningful distinction. It could also allow for something like an
assert to be removed as an optimisation with no side-effects in a release
build.

If something is pure it can be annotated with @pure, if it is not-pure
this will be a compile-time error. The compiler could automatically add
this annotation in the interface.

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this
includes referencing self from a method or property)
* it only externally references let variables of pure type, let
properties on those variables, and methods/computer-properties marked as
pure.

A computed property can be marked as pure like this:

@pure var test: A

A function/method/closure signature is marked as pure like this:

(a: A, b: A -> B) @pure -> B

If the function/method/closure is only pure if an argument is pure
(similar to @rethrows), then you could do this:

(start: A, a: A -> B) @pure(b) -> B

Potentially this could be extended to allow a pure closure to be composed
of other pure closures:

func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C {

    return { b(a($0)) }

}

Of course this doesn't preclude you from requiring some of those closures
to be pure:

func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C {

    return { b(a($0)) }

}

Impact on existing code:

No negative impact as if automatic annotation was allowed it would only
happen where it was safe to do so. If it was not allowed then libraries
could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is
not used. From this perspective assert and print should not be marked as
pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but
this can be a gradual process.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Howard Lovatt) #14

Comment in-line below.

That would be nice, although I'm not sure how practical that is in current swift usage. I imagine it would require a lot of changes to existing code and libraries.

Not sure how hard this would be or if a migration tool and enhanced Obj-C importer would be good enough.

Is a method impure if it uses self? I suppose it could be. I guess self is an inout parameter. I presume an inout parameter is a known expected side-effect.

If it doesn’t change self then it is pure.

Closures would probably be the largest impact if things were pure by default.

I think this would be a great change. We are part way there with @noescape and @autoclosure already

It would be interesting though to do a code survey and see what portion would need to be marked as @impure, and what conditions lead them to that requirement.

I'm happy to discuss @impure too, but my focus is still @pure, as I think it is a more attainable target, at the moment.

Perhaps after everything is annotated, impure functions are minimised, and if swift is streamlined for pure function use, then we can introduce @impure and deprecate @pure.

Not sure either will happen any time soon :(. Therefore the most useful thing would be the survey you suggest.

···

On 9 Jan 2016, at 8:04 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

On Sat, Jan 9, 2016 at 7:56 PM, Howard Lovatt <howard.lovatt@gmail.com <mailto:howard.lovatt@gmail.com>> wrote:
I would rather you mark a function as impure and have the default as pure!

On 9 Jan 2016, at 7:53 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

This will allow us to make more guarantees about what a protocol does, and what it cannot do. It will also allow APIs like `.map` and `.forEach` to have a meaningful distinction. It could also allow for something like an assert to be removed as an optimisation with no side-effects in a release build.

If something is pure it can be annotated with @pure, if it is not-pure this will be a compile-time error. The compiler could automatically add this annotation in the interface.

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this includes referencing self from a method or property)
* it only externally references let variables of pure type, let properties on those variables, and methods/computer-properties marked as pure.

A computed property can be marked as pure like this:
@pure var test: A

A function/method/closure signature is marked as pure like this:
(a: A, b: A -> B) @pure -> B

If the function/method/closure is only pure if an argument is pure (similar to @rethrows), then you could do this:
(start: A, a: A -> B) @pure(b) -> B

Potentially this could be extended to allow a pure closure to be composed of other pure closures:
func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C {
    return { b(a($0)) }
}

Of course this doesn't preclude you from requiring some of those closures to be pure:
func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C {
    return { b(a($0)) }
}

Impact on existing code:
No negative impact as if automatic annotation was allowed it would only happen where it was safe to do so. If it was not allowed then libraries could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is not used. From this perspective assert and print should not be marked as pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but this can be a gradual process.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Yang Wu) #15

So what's the semantic difference between @pure and @impure type?

"c and objective-c would not be marked as pure." It sounds like pure swift.

"Pure functions can be safely removed by the optimizer if their result is
not used. " It sounds like no-side-effects or immutable.

···

On Sat, Jan 9, 2016 at 5:14 PM, Howard Lovatt via swift-evolution < swift-evolution@swift.org> wrote:

Comment in-line below.

On 9 Jan 2016, at 8:04 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

That would be nice, although I'm not sure how practical that is in current
swift usage. I imagine it would require a lot of changes to existing code
and libraries.

Not sure how hard this would be or if a migration tool and enhanced Obj-C
importer would be good enough.

Is a method impure if it uses self? I suppose it could be. I guess self is
an inout parameter. I presume an inout parameter is a known expected
side-effect.

If it doesn’t change self then it is pure.

Closures would probably be the largest impact if things were pure by
default.

I think this would be a great change. We are part way there with @noescape
and @autoclosure already

It would be interesting though to do a code survey and see what portion
would need to be marked as @impure, and what conditions lead them to that
requirement.

I'm happy to discuss @impure too, but my focus is still @pure, as I think
it is a more attainable target, at the moment.

Perhaps after everything is annotated, impure functions are minimised, and
if swift is streamlined for pure function use, then we can introduce
@impure and deprecate @pure.

Not sure either will happen any time soon :(. Therefore the most useful
thing would be the survey you suggest.

On Sat, Jan 9, 2016 at 7:56 PM, Howard Lovatt <howard.lovatt@gmail.com> > wrote:

I would rather you mark a function as impure and have the default as pure!

On 9 Jan 2016, at 7:53 PM, Andrew Bennett via swift-evolution < >> swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and
how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

This will allow us to make more guarantees about what a protocol does,
and what it cannot do. It will also allow APIs like `.map` and `.forEach`
to have a meaningful distinction. It could also allow for something like an
assert to be removed as an optimisation with no side-effects in a release
build.

If something is pure it can be annotated with @pure, if it is not-pure
this will be a compile-time error. The compiler could automatically add
this annotation in the interface.

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this
includes referencing self from a method or property)
* it only externally references let variables of pure type, let
properties on those variables, and methods/computer-properties marked as
pure.

A computed property can be marked as pure like this:

@pure var test: A

A function/method/closure signature is marked as pure like this:

(a: A, b: A -> B) @pure -> B

If the function/method/closure is only pure if an argument is pure
(similar to @rethrows), then you could do this:

(start: A, a: A -> B) @pure(b) -> B

Potentially this could be extended to allow a pure closure to be composed
of other pure closures:

func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C {

    return { b(a($0)) }

}

Of course this doesn't preclude you from requiring some of those closures
to be pure:

func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C {

    return { b(a($0)) }

}

Impact on existing code:

No negative impact as if automatic annotation was allowed it would only
happen where it was safe to do so. If it was not allowed then libraries
could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is
not used. From this perspective assert and print should not be marked as
pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but
this can be a gradual process.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue
<http://www.pinxue.net>


(Andrew Bennett) #16

Hi 品雪,

As I understand Howard's intentions @pure and @impure are just antonyms,
like true versus false. The important distinction is that if we only had a
@pure keyword then functions are allowed to be impure by default, which is
easier for existing code and probably beginner programmers. Functions are
not checked for purity unless annotated.

C and Objective-C may be able to be marked as pure in future, but I think
it's too difficult to do so at the moment. It's probably the case that
there will be some kind of import attribute that could allow c functions to
be marked as pure for the standard library, however I doubt there will be
any automated checking.

"no-side-effects" is essentially the same. It's mainly a matter of defining
what side-effects are and are not allowed. Side-effects could mean that it
doesn't take any processor time, or it doesn't change registers, or cannot
abort execution, allocate memory, etc.

Andrew

···

On Sat, Jan 9, 2016 at 8:59 PM, 品雪 <pinxue@gmail.com> wrote:

So what's the semantic difference between @pure and @impure type?

"c and objective-c would not be marked as pure." It sounds like pure
swift.

"Pure functions can be safely removed by the optimizer if their result is
not used. " It sounds like no-side-effects or immutable.

On Sat, Jan 9, 2016 at 5:14 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

Comment in-line below.

On 9 Jan 2016, at 8:04 PM, Andrew Bennett <cacoyi@gmail.com> wrote:

That would be nice, although I'm not sure how practical that is in
current swift usage. I imagine it would require a lot of changes to
existing code and libraries.

Not sure how hard this would be or if a migration tool and enhanced Obj-C
importer would be good enough.

Is a method impure if it uses self? I suppose it could be. I guess self
is an inout parameter. I presume an inout parameter is a known expected
side-effect.

If it doesn’t change self then it is pure.

Closures would probably be the largest impact if things were pure by
default.

I think this would be a great change. We are part way there with
@noescape and @autoclosure already

It would be interesting though to do a code survey and see what portion
would need to be marked as @impure, and what conditions lead them to that
requirement.

I'm happy to discuss @impure too, but my focus is still @pure, as I think
it is a more attainable target, at the moment.

Perhaps after everything is annotated, impure functions are minimised,
and if swift is streamlined for pure function use, then we can introduce
@impure and deprecate @pure.

Not sure either will happen any time soon :(. Therefore the most useful
thing would be the survey you suggest.

On Sat, Jan 9, 2016 at 7:56 PM, Howard Lovatt <howard.lovatt@gmail.com> >> wrote:

I would rather you mark a function as impure and have the default as
pure!

On 9 Jan 2016, at 7:53 PM, Andrew Bennett via swift-evolution < >>> swift-evolution@swift.org> wrote:

I'd like to discuss adding a @pure keyword, and see what it requires and
how possible it is to include.

I'd like to use the annotation @pure on functions, methods and closures.

This will allow us to make more guarantees about what a protocol does,
and what it cannot do. It will also allow APIs like `.map` and `.forEach`
to have a meaningful distinction. It could also allow for something like an
assert to be removed as an optimisation with no side-effects in a release
build.

If something is pure it can be annotated with @pure, if it is not-pure
this will be a compile-time error. The compiler could automatically add
this annotation in the interface.

A function, method or closure is pure if:
* all functions, methods and closures it calls are also pure (this
includes referencing self from a method or property)
* it only externally references let variables of pure type, let
properties on those variables, and methods/computer-properties marked as
pure.

A computed property can be marked as pure like this:

@pure var test: A

A function/method/closure signature is marked as pure like this:

(a: A, b: A -> B) @pure -> B

If the function/method/closure is only pure if an argument is pure
(similar to @rethrows), then you could do this:

(start: A, a: A -> B) @pure(b) -> B

Potentially this could be extended to allow a pure closure to be
composed of other pure closures:

func compose(a: A -> B, b: B -> C) @pure -> A @pure(a,b) -> C {

    return { b(a($0)) }

}

Of course this doesn't preclude you from requiring some of those
closures to be pure:

func compose(a: A @pure -> B, b: B -> C) @pure -> A @pure(b) -> C {

    return { b(a($0)) }

}

Impact on existing code:

No negative impact as if automatic annotation was allowed it would only
happen where it was safe to do so. If it was not allowed then libraries
could be slowly annotated to be marked as pure.

c and objective-c would not be marked as pure.

Pure functions can be safely removed by the optimiser if their result is
not used. From this perspective assert and print should not be marked as
pure (they would have to be an exception anyway).

Ideally existing libraries would be annotated, the more the better, but
this can be a gradual process.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue
<http://www.pinxue.net>