mutating/non-mutating suggestion from a Rubyist


(Daniel Steinberg) #1

Pardon me if this has been raised before.

I gave a short presentation at our Cleveland CocoaHeads this week on what is coming in Swift 3. One of the attendees stayed behind to ask about the naming guidelines for mutating vs non-mutating. He is fairly new to Swift - coming from Ruby. I have no Ruby experience but am passing his thoughts on to this list.

He said that in Ruby they decorate the name with a symbol (I believe in their case it is “!”) to distinguish between the two. Although usually I’m not a fan of such naming conventions, we do something similar with inout parameters.

For example, if we have

func myFunc(param: inout String) { …}

we call it like this (using the Swift 3 first label convention)

myFunc(param: &aName)

We use the & to signal that the value of aName might be changed by the call to myFunc().

Similarly, instead of settling on a naming convention for verb vs verbed/verbing we could name the methods descriptively and require a symbol (here I use & but only for illustration) to distinguish between mutating and non-mutating

so we would have

myArray.sort&()

and

sortedArray = myArray.sort()

Xcode and other tools could enforce this naming pattern and warn us that a mutating method must end in “&” and that a non-mutating method is not allowed to.

Best,

Daniel


(Haravikk) #2

I think that Swift has this fairly well covered so long as your mutating methods don’t need to return anything, as the type system will handle that, while @warn_unused_result (which I think is becoming the default on methods with return types?) will cover the non-mutating cases. The only place where it gets awkward is if a mutating method needs to return something, but the name of the method should ideally be something clear in such cases.

Basically I think that as long as type-checking/unused result checking and a clear naming scheme solve the problem there should be no need for a custom syntax.

Aside from that I think that is something that an Xcode feature could solve; for example if mutating methods were coloured differently from non-mutating ones.

···

On 21 Apr 2016, at 18:08, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

Pardon me if this has been raised before.

I gave a short presentation at our Cleveland CocoaHeads this week on what is coming in Swift 3. One of the attendees stayed behind to ask about the naming guidelines for mutating vs non-mutating. He is fairly new to Swift - coming from Ruby. I have no Ruby experience but am passing his thoughts on to this list.

He said that in Ruby they decorate the name with a symbol (I believe in their case it is “!”) to distinguish between the two. Although usually I’m not a fan of such naming conventions, we do something similar with inout parameters.

For example, if we have

func myFunc(param: inout String) { …}

we call it like this (using the Swift 3 first label convention)

myFunc(param: &aName)

We use the & to signal that the value of aName might be changed by the call to myFunc().

Similarly, instead of settling on a naming convention for verb vs verbed/verbing we could name the methods descriptively and require a symbol (here I use & but only for illustration) to distinguish between mutating and non-mutating

so we would have

myArray.sort&()

and

sortedArray = myArray.sort()

Xcode and other tools could enforce this naming pattern and warn us that a mutating method must end in “&” and that a non-mutating method is not allowed to.

Best,

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


(Haravikk) #3

I think that Swift has this fairly well covered so long as your mutating methods don’t need to return anything, as the type system will handle that, while @warn_unused_result (which I think is becoming the default on methods with return types?) will cover the non-mutating cases. The only place where it gets awkward is if a mutating method needs to return something, but the name of the method should ideally be something clear in such cases.

Basically I think that as long as type-checking/unused result checking and a clear naming scheme solve the problem there should be no need for a custom syntax.

Aside from that I think that is something that an Xcode feature could solve; for example if mutating methods were coloured differently from non-mutating ones.

···

On 21 Apr 2016, at 18:08, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

Pardon me if this has been raised before.

I gave a short presentation at our Cleveland CocoaHeads this week on what is coming in Swift 3. One of the attendees stayed behind to ask about the naming guidelines for mutating vs non-mutating. He is fairly new to Swift - coming from Ruby. I have no Ruby experience but am passing his thoughts on to this list.

He said that in Ruby they decorate the name with a symbol (I believe in their case it is “!”) to distinguish between the two. Although usually I’m not a fan of such naming conventions, we do something similar with inout parameters.

For example, if we have

func myFunc(param: inout String) { …}

we call it like this (using the Swift 3 first label convention)

myFunc(param: &aName)

We use the & to signal that the value of aName might be changed by the call to myFunc().

Similarly, instead of settling on a naming convention for verb vs verbed/verbing we could name the methods descriptively and require a symbol (here I use & but only for illustration) to distinguish between mutating and non-mutating

so we would have

myArray.sort&()

and

sortedArray = myArray.sort()

Xcode and other tools could enforce this naming pattern and warn us that a mutating method must end in “&” and that a non-mutating method is not allowed to.

Best,

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


(Krishna Kumar) #4

Hey

I think adding “&” to methods will reduce the readability of the code. Also, keyword “mutating” makes it super clear and readable that my method is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function which is this function is mutating a value as compared to 1st. When I read 1st function I start reading with keyword “mutating” making its intentions clear to me.

Also, it might become a symbol nightmare with following type signature of a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes clear at the call site that this method is mutating but still I don’t find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

···

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

swift-evolution@swift.org <mailto:swift-evolution@swift.org>


(Dave Abrahams) #5

This is not a new idea. Something almost identical to this has been
explored and discussed quite thoroughly already:
<https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
In fact, it was implmented and later reverted because it raised
language-design questions for which we had no good answers. I don't
believe the choice of glyph (& vs =) affects any of the fundamental
issues:

* Should the x.=f() syntax be required for *every* mutating method
  invocation?

* Are assignment methods a redundant way to spell mutating methods?
  Should we really have both mechanisms?

* Can we really introduce this feature without having a way to apply it
  to class types?

I should also point out that under the assignment method paradigm one
would probably need to re-evalutate rules for naming. Under the current
API guidelines' approach, we'd write:

    x.=sorted() // sort x in-place

and I am not sure how easy that would be for people to swallow
considering how much more straightforward

    x.sort() // current way to sort x in-place

is, and because the language now contains explicit notation for
mutation, it becomes harder to argue against theis pair:

    y = x.sort()
    x.=sort() // sort x in place

Lastly, I should point out that the proposal does nothing to solve the
problem of `c.formSuccessor(&i)`, since that doesn't mutate the
receiver.

I still like the proposal's basic approach and would love to see it used
to address these naming problems, but I want to be clear that it's by no
means a panacea and there are real obstacles between here and actually
being able to apply it. If you want to move forward with something like
this, you need to solve the problems described above.

···

on Thu Apr 21 2016, Daniel Steinberg <swift-evolution@swift.org> wrote:

Pardon me if this has been raised before.

I gave a short presentation at our Cleveland CocoaHeads this week on
what is coming in Swift 3. One of the attendees stayed behind to ask
about the naming guidelines for mutating vs non-mutating. He is fairly
new to Swift - coming from Ruby. I have no Ruby experience but am
passing his thoughts on to this list.

He said that in Ruby they decorate the name with a symbol (I believe
in their case it is “!”) to distinguish between the two. Although
usually I’m not a fan of such naming conventions, we do something
similar with inout parameters.

For example, if we have

func myFunc(param: inout String) { …}

we call it like this (using the Swift 3 first label convention)

myFunc(param: &aName)

We use the & to signal that the value of aName might be changed by the call to myFunc().

Similarly, instead of settling on a naming convention for verb vs
verbed/verbing we could name the methods descriptively and require a
symbol (here I use & but only for illustration) to distinguish between
mutating and non-mutating

so we would have

myArray.sort&()

and

sortedArray = myArray.sort()

Xcode and other tools could enforce this naming pattern and warn us
that a mutating method must end in “&” and that a non-mutating method
is not allowed to.

--
Dave


(Tyler Cloutier) #6

If I recall correctly there was a thread with a similar idea which instead would create a new operator for mutation or a new way of method invocation, such that mutating methods would be called with &. or something similar. e.g.

foo&.add(5)

I think the consensus was that that was not a particularly familiar syntax and it would add a decent amount of noise.

There may have also been some issues with the grammar, I can't recall.

···

On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution <swift-evolution@swift.org> wrote:

Hey

I think adding “&” to methods will reduce the readability of the code. Also, keyword “mutating” makes it super clear and readable that my method is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function which is this function is mutating a value as compared to 1st. When I read 1st function I start reading with keyword “mutating” making its intentions clear to me.

Also, it might become a symbol nightmare with following type signature of a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes clear at the call site that this method is mutating but still I don’t find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

swift-evolution@swift.org

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


(Tyler Cloutier) #7

That being said I try to follow most of the discussions on swift-evolution and there does seem to be a great deal of hand wringing regarding this and things related to or affected by this.

···

On Apr 22, 2016, at 12:00 AM, Tyler Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

If I recall correctly there was a thread with a similar idea which instead would create a new operator for mutation or a new way of method invocation, such that mutating methods would be called with &. or something similar. e.g.

foo&.add(5)

I think the consensus was that that was not a particularly familiar syntax and it would add a decent amount of noise.

There may have also been some issues with the grammar, I can't recall.

On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution <swift-evolution@swift.org> wrote:

Hey

I think adding “&” to methods will reduce the readability of the code. Also, keyword “mutating” makes it super clear and readable that my method is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function which is this function is mutating a value as compared to 1st. When I read 1st function I start reading with keyword “mutating” making its intentions clear to me.

Also, it might become a symbol nightmare with following type signature of a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes clear at the call site that this method is mutating but still I don’t find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

swift-evolution@swift.org

_______________________________________________
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


(Daniel Steinberg) #8

Sorry I left mutating off by mistake. I'm referring to the call site more

···

On Apr 22, 2016, at 8:40 AM, Krishna Kumar <kkdevenda@gmail.com> wrote:

Hey

I think adding “&” to methods will reduce the readability of the code. Also, keyword “mutating” makes it super clear and readable that my method is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function which is this function is mutating a value as compared to 1st. When I read 1st function I start reading with keyword “mutating” making its intentions clear to me.

Also, it might become a symbol nightmare with following type signature of a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes clear at the call site that this method is mutating but still I don’t find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

swift-evolution@swift.org


(Vladimir) #9

From one point of view, it will be really awesome if we'll have some kind of 'marker' for mutating methods so we can clearly see in code if that method changes the instance(just like we all agree that we must specify & for inout parameter).

From other point of view, this will add a much more noise(and typing) in code as we often(in most cases?) use mutating methods. Have a code with a huge number of & symbols(or other) in it - not the best thing.

I don't see how we can unite both points.

···

On 22.04.2016 10:00, Tyler Cloutier via swift-evolution wrote:

If I recall correctly there was a thread with a similar idea which instead
would create a new operator for mutation or a new way of method invocation,
such that mutating methods would be called with &. or something similar. e.g.

foo&.add(5)

I think the consensus was that that was not a particularly familiar syntax
and it would add a decent amount of noise.

There may have also been some issues with the grammar, I can't recall.

On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hey

I think adding “&” to methods will reduce the readability of the code.
Also, keyword “mutating” makes it super clear and readable that my method
is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function
which is this function is mutating a value as compared to 1st. When I
read 1st function I start reading with keyword “mutating” making its
intentions clear to me.

Also, it might become a symbol nightmare with following type signature of
a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes
clear at the call site that this method is mutating but still I don’t
find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

swift-evolution@swift.org <mailto:swift-evolution@swift.org>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Daniel Steinberg) #10

Thank you Dave.

I appreciate your thoughtful and complete response and will think further on this.

Daniel

···

On Apr 22, 2016, at 11:24 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu Apr 21 2016, Daniel Steinberg <swift-evolution@swift.org> wrote:

Pardon me if this has been raised before.

I gave a short presentation at our Cleveland CocoaHeads this week on
what is coming in Swift 3. One of the attendees stayed behind to ask
about the naming guidelines for mutating vs non-mutating. He is fairly
new to Swift - coming from Ruby. I have no Ruby experience but am
passing his thoughts on to this list.

He said that in Ruby they decorate the name with a symbol (I believe
in their case it is “!”) to distinguish between the two. Although
usually I’m not a fan of such naming conventions, we do something
similar with inout parameters.

For example, if we have

func myFunc(param: inout String) { …}

we call it like this (using the Swift 3 first label convention)

myFunc(param: &aName)

We use the & to signal that the value of aName might be changed by the call to myFunc().

Similarly, instead of settling on a naming convention for verb vs
verbed/verbing we could name the methods descriptively and require a
symbol (here I use & but only for illustration) to distinguish between
mutating and non-mutating

so we would have

myArray.sort&()

and

sortedArray = myArray.sort()

Xcode and other tools could enforce this naming pattern and warn us
that a mutating method must end in “&” and that a non-mutating method
is not allowed to.

This is not a new idea. Something almost identical to this has been
explored and discussed quite thoroughly already:
<https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
In fact, it was implmented and later reverted because it raised
language-design questions for which we had no good answers. I don't
believe the choice of glyph (& vs =) affects any of the fundamental
issues:

* Should the x.=f() syntax be required for *every* mutating method
invocation?

* Are assignment methods a redundant way to spell mutating methods?
Should we really have both mechanisms?

* Can we really introduce this feature without having a way to apply it
to class types?

I should also point out that under the assignment method paradigm one
would probably need to re-evalutate rules for naming. Under the current
API guidelines' approach, we'd write:

   x.=sorted() // sort x in-place

and I am not sure how easy that would be for people to swallow
considering how much more straightforward

   x.sort() // current way to sort x in-place

is, and because the language now contains explicit notation for
mutation, it becomes harder to argue against theis pair:

   y = x.sort()
   x.=sort() // sort x in place

Lastly, I should point out that the proposal does nothing to solve the
problem of `c.formSuccessor(&i)`, since that doesn't mutate the
receiver.

I still like the proposal's basic approach and would love to see it used
to address these naming problems, but I want to be clear that it's by no
means a panacea and there are real obstacles between here and actually
being able to apply it. If you want to move forward with something like
this, you need to solve the problems described above.

--
Dave

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


(Pyry Jahkola) #11

I'd like to second James Campbell's suggestion of a `mutate` keyword. Clarifying comments inline below:

This is not a new idea. Something almost identical to this has been
explored and discussed quite thoroughly already:
<https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
In fact, it was implmented and later reverted because it raised
language-design questions for which we had no good answers.

I don't know if the following are particularly good answers, but I'll try anyway:

I don't believe the choice of glyph (& vs =) affects any of the
fundamental issues:

* Should the x.=f() syntax be required for *every* mutating method
invocation?

Allow me to ask it differently: Should some specific syntax be required for every mutating method? — Yes.

Should the syntax be `x.=f()`? — Not necessarily. I kinda like James Campbell's idea of a `mutate` keyword. Consider the following:

    var numbers = [5, 12, 6, 2]
    mutate numbers.append(10)
    mutate numbers.sort()
    if let biggest = mutate numbers.popLast() {
        print("The biggest number was:", biggest)
    }

So `mutate` would work much like `try` but—unlike `try` which can move further to the left—`mutate` would have to always prefix the mutating receiver. Here's a contrived example of a corner case:

    enum Error : ErrorType { case BadNumber }

    func demo() throws -> Int {
        
    }

* Are assignment methods a redundant way to spell mutating methods?
Should we really have both mechanisms?

(I had to look up the definition of an assignment method. For the uninitiated, Dave is talking about what's written here: https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst#use-one-simple-name.)

— Yes they are redundant, and no, we should not have both.

With `mutate` required at the call site, we could simply allow both overloads `func sort()` and `mutating func sort()` to coexist, because the call sites become unambiguous:

    let originals = [2, 1, 3, 0, 4, 2]
    var copies = originals

    originals.sort() // warning: result of call to 'sort()' is unused
    mutate originals.sort() // compiler error
    let xs = originals.sort() // ok

    copies.sort() // warning: result of call to 'sort()' is unused
    mutate copies.sort() // ok
    let ys = copies.sort() // ok
    let zs = mutate copies.sort() // warning: constant 'x' inferred to have type '()', which may be unexpected

The language could also allow the use of

    mutate x.next()

as shorthand for

    x = x.next()

when only the non-mutating variant `func next() -> Self` exists with compatible return type.

* Can we really introduce this feature without having a way to apply it
to class types?

Yes we can. Why complicate the naming of value type members with the complexities of reference semantics? The current API naming conventions are good for reference types which sometimes come with unobvious to obscure behaviour (i.e. anything from bumping an internal counter to firing missiles and wiping hard drives).

But value types ought to have no side effects (besides memory allocation and logging maybe), and so we don't necessarily need that strong a naming convention to limit their collateral damage.

If the `mutate` keyword became required for calling `mutating` methods, then operators would remain the only place where naming convention were needed to distinguish mutation:

Mutating assignment is explicit: `xs = [1, 2] + xs + [2, 1]` (i.e. `=` without `let` or `var` means mutation)
Mutating method call becomes explicit: `mutate xs.sort()` and `let x = mutate xs.removeAtIndex(2)`
Mutating function arguments are explicit with the `&` prefix: `swap(&xs, &ys)`
Mutating operators are implicit and by convention, should end with the `=` symbol: `xs += [8, 9]`
Reference types have no notion of `mutating` members (and probably ought to remain that way) so they mutate implicitly.

I should also point out that under the assignment method paradigm one
would probably need to re-evalutate rules for naming. Under the current
API guidelines' approach, we'd write:

   x.=sorted() // sort x in-place

and I am not sure how easy that would be for people to swallow
considering how much more straightforward

   x.sort() // current way to sort x in-place

is, and because the language now contains explicit notation for
mutation, it becomes harder to argue against theis pair:

   y = x.sort()
   x.=sort() // sort x in place

I agree that the current API guidelines wouldn't work for value types anymore. Both `sort` and `sorted` would be called `sort`.

Lastly, I should point out that the proposal does nothing to solve the
problem of `c.formSuccessor(&i)`, since that doesn't mutate the
receiver.

This proposal does address the problem of `c.formSuccessor(&i)`. Given that it's value types at play here, what mutates in the following is unambiguous even to non-native English speakers:

    c.frobnicate(&i) // cannot possibly mutate c but mutates i
    let j = c.frobnicate(i) // cannot possibly mutate either
    mutate c.frobnicate(i) // mutates c
    let k = mutate c.frobnicate(&i) // mutates both

I still like the proposal's basic approach and would love to see it used
to address these naming problems, but I want to be clear that it's by no
means a panacea and there are real obstacles between here and actually
being able to apply it. If you want to move forward with something like
this, you need to solve the problems described above.

I think this proposal would simplify all code handling value types. Yes, it adds one keyword of boilerplate but wins clarity in return. I think reference types should stay separate from this discussion, as their mutation has always been implicit anyway. The API guidelines set a good convention for them.

— Pyry

···

On 23 Apr 2016, at 00:24, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:


(Radek Pietruszewski) #12

Q: Would it be possible to allow some sigil in method names (say, prefix/postfix `=`) without any automatic/magic treatment of these methods?

In Ruby, after all, postfix `!` is just allowed in names. It doesn’t have any semantic meaning for the interpreter, it’s just the (strong, well agreed upon) convention to use it to mark mutating methods in mutating/non-mutating pairs, like `foo.map(…)` vs `foo.map!(…)`.

It works out well for Ruby. Would it be out of question to allow the same thing in Swift? A naming convention (`foo.sort()` vs `foo.sort=()`), not an automatic language feature?

— Radek

···

On 22 Apr 2016, at 23:24, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu Apr 21 2016, Daniel Steinberg <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Pardon me if this has been raised before.

I gave a short presentation at our Cleveland CocoaHeads this week on
what is coming in Swift 3. One of the attendees stayed behind to ask
about the naming guidelines for mutating vs non-mutating. He is fairly
new to Swift - coming from Ruby. I have no Ruby experience but am
passing his thoughts on to this list.

He said that in Ruby they decorate the name with a symbol (I believe
in their case it is “!”) to distinguish between the two. Although
usually I’m not a fan of such naming conventions, we do something
similar with inout parameters.

For example, if we have

func myFunc(param: inout String) { …}

we call it like this (using the Swift 3 first label convention)

myFunc(param: &aName)

We use the & to signal that the value of aName might be changed by the call to myFunc().

Similarly, instead of settling on a naming convention for verb vs
verbed/verbing we could name the methods descriptively and require a
symbol (here I use & but only for illustration) to distinguish between
mutating and non-mutating

so we would have

myArray.sort&()

and

sortedArray = myArray.sort()

Xcode and other tools could enforce this naming pattern and warn us
that a mutating method must end in “&” and that a non-mutating method
is not allowed to.

This is not a new idea. Something almost identical to this has been
explored and discussed quite thoroughly already:
<https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
In fact, it was implmented and later reverted because it raised
language-design questions for which we had no good answers. I don't
believe the choice of glyph (& vs =) affects any of the fundamental
issues:

* Should the x.=f() syntax be required for *every* mutating method
invocation?

* Are assignment methods a redundant way to spell mutating methods?
Should we really have both mechanisms?

* Can we really introduce this feature without having a way to apply it
to class types?

I should also point out that under the assignment method paradigm one
would probably need to re-evalutate rules for naming. Under the current
API guidelines' approach, we'd write:

   x.=sorted() // sort x in-place

and I am not sure how easy that would be for people to swallow
considering how much more straightforward

   x.sort() // current way to sort x in-place

is, and because the language now contains explicit notation for
mutation, it becomes harder to argue against theis pair:

   y = x.sort()
   x.=sort() // sort x in place

Lastly, I should point out that the proposal does nothing to solve the
problem of `c.formSuccessor(&i)`, since that doesn't mutate the
receiver.

I still like the proposal's basic approach and would love to see it used
to address these naming problems, but I want to be clear that it's by no
means a panacea and there are real obstacles between here and actually
being able to apply it. If you want to move forward with something like
this, you need to solve the problems described above.

--
Dave

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


(Patrick Smith) #13

Well, you could actually have something like this now, and use whether the returned result was used or not to know if was a mutating or nonmutating method or not.

Patrick

···

On Fri, Apr 22, 2016 at 4:53 AM -0700, "James Campbell via swift-evolution" <swift-evolution@swift.org> wrote:

What if we had a concept similar to errors and try ?
Given this function:
func sort() -> Self {}
mutating sort() -> Self {}

If a developer calls:
array.sort()
It will sort a copy of that array, in order to sort in place the developer must confirm the mutation like so:
mutate array.sort()
This will then call the mutating version of sort :slight_smile:

___________________________________

James⎥Chief Of Fun

james@supmenow.com⎥supmenow.com

Sup

Runway East

10 Finsbury Square

London

EC2A 1AF

On 22 April 2016 at 12:31, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:
This is why I mentioned Xcode; while we can have ampersand as a language feature for marking such things explicitly (i.e- developer consents to doing it), we could also just have Xcode highlight inout parameters and mutating methods differently, but would these represent the same explicit “I know that what I’m doing here will have side-effects” impact (especially if other IDEs add Swift support but don’t do this).

On 22 Apr 2016, at 11:54, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

From one point of view, it will be really awesome if we'll have some kind of 'marker' for mutating methods so we can clearly see in code if that method changes the instance(just like we all agree that we must specify & for inout parameter).

From other point of view, this will add a much more noise(and typing) in code as we often(in most cases?) use mutating methods. Have a code with a huge number of & symbols(or other) in it - not the best thing.

I don't see how we can unite both points.

On 22.04.2016 10:00, Tyler Cloutier via swift-evolution wrote:

If I recall correctly there was a thread with a similar idea which instead

would create a new operator for mutation or a new way of method invocation,

such that mutating methods would be called with &. or something similar. e.g.

foo&.add(5)

I think the consensus was that that was not a particularly familiar syntax

and it would add a decent amount of noise.

There may have also been some issues with the grammar, I can't recall.

On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hey

I think adding “&” to methods will reduce the readability of the code.

Also, keyword “mutating” makes it super clear and readable that my method

is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function

which is this function is mutating a value as compared to 1st. When I

read 1st function I start reading with keyword “mutating” making its

intentions clear to me.

Also, it might become a symbol nightmare with following type signature of

a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes

clear at the call site that this method is mutating but still I don’t

find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

swift-evolution@swift.org <mailto:swift-evolution@swift.org>

_______________________________________________

swift-evolution mailing list

swift-evolution@swift.org <mailto: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

_______________________________________________

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


(Haravikk) #14

This is why I mentioned Xcode; while we can have ampersand as a language feature for marking such things explicitly (i.e- developer consents to doing it), we could also just have Xcode highlight inout parameters and mutating methods differently, but would these represent the same explicit “I know that what I’m doing here will have side-effects” impact (especially if other IDEs add Swift support but don’t do this).

···

On 22 Apr 2016, at 11:54, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

From one point of view, it will be really awesome if we'll have some kind of 'marker' for mutating methods so we can clearly see in code if that method changes the instance(just like we all agree that we must specify & for inout parameter).

From other point of view, this will add a much more noise(and typing) in code as we often(in most cases?) use mutating methods. Have a code with a huge number of & symbols(or other) in it - not the best thing.

I don't see how we can unite both points.

On 22.04.2016 10:00, Tyler Cloutier via swift-evolution wrote:

If I recall correctly there was a thread with a similar idea which instead
would create a new operator for mutation or a new way of method invocation,
such that mutating methods would be called with &. or something similar. e.g.

foo&.add(5)

I think the consensus was that that was not a particularly familiar syntax
and it would add a decent amount of noise.

There may have also been some issues with the grammar, I can't recall.

On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hey

I think adding “&” to methods will reduce the readability of the code.
Also, keyword “mutating” makes it super clear and readable that my method
is mutating the values.

1. mutating func add(value: Double){…}

2. func add&(value: Double){…}

I think it’s easy to skip the information encoded into the 2nd function
which is this function is mutating a value as compared to 1st. When I
read 1st function I start reading with keyword “mutating” making its
intentions clear to me.

Also, it might become a symbol nightmare with following type signature of
a function-

func nightmare&(title: String?) -> String? -> String?{…}

I can see the advantage of using “&” when calling a function. It makes
clear at the call site that this method is mutating but still I don’t
find eliminating “mutating” a good step for the reasons mentioned above.

Maybe we can think of some better solution.

Thanks

-Krishna

On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

swift-evolution@swift.org <mailto:swift-evolution@swift.org>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

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


(James Campbell) #15

What if we had a concept similar to errors and try ?

Given this function:

func sort() -> Self {
}

mutating sort() -> Self {
}

If a developer calls:

array.sort()

It will sort a copy of that array, in order to sort in place the developer
must confirm the mutation like so:

mutate array.sort()

This will then call the mutating version of sort :slight_smile:

···

*___________________________________*

*James⎥Chief Of Fun*

*james@supmenow.com <james@supmenow.com>⎥supmenow.com <http://supmenow.com>*

*Sup*

*Runway East *

*10 Finsbury Square*

*London*

* EC2A 1AF *

On 22 April 2016 at 12:31, Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

This is why I mentioned Xcode; while we can have ampersand as a language
feature for marking such things explicitly (i.e- developer consents to
doing it), we could also just have Xcode highlight inout parameters and
mutating methods differently, but would these represent the same explicit
“I know that what I’m doing here will have side-effects” impact (especially
if other IDEs add Swift support but don’t do this).

> On 22 Apr 2016, at 11:54, Vladimir.S via swift-evolution < > swift-evolution@swift.org> wrote:
>
> From one point of view, it will be really awesome if we'll have some
kind of 'marker' for mutating methods so we can clearly see in code if that
method changes the instance(just like we all agree that we must specify &
for inout parameter).
>
> From other point of view, this will add a much more noise(and typing) in
code as we often(in most cases?) use mutating methods. Have a code with a
huge number of & symbols(or other) in it - not the best thing.
>
> I don't see how we can unite both points.
>
> On 22.04.2016 10:00, Tyler Cloutier via swift-evolution wrote:
>> If I recall correctly there was a thread with a similar idea which
instead
>> would create a new operator for mutation or a new way of method
invocation,
>> such that mutating methods would be called with &. or something
similar. e.g.
>>
>> foo&.add(5)
>>
>> I think the consensus was that that was not a particularly familiar
syntax
>> and it would add a decent amount of noise.
>>
>> There may have also been some issues with the grammar, I can't recall.
>>
>> On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution > >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>>> Hey
>>>
>>> I think adding “&” to methods will reduce the readability of the code.
>>> Also, keyword “mutating” makes it super clear and readable that my
method
>>> is mutating the values.
>>>
>>> 1. mutating func add(value: Double){…}
>>>
>>> 2. func add&(value: Double){…}
>>>
>>> I think it’s easy to skip the information encoded into the 2nd function
>>> which is this function is mutating a value as compared to 1st. When I
>>> read 1st function I start reading with keyword “mutating” making its
>>> intentions clear to me.
>>>
>>> Also, it might become a symbol nightmare with following type signature
of
>>> a function-
>>>
>>> func nightmare&(title: String?) -> String? -> String?{…}
>>>
>>> I can see the advantage of using “&” when calling a function. It makes
>>> clear at the call site that this method is mutating but still I don’t
>>> find eliminating “mutating” a good step for the reasons mentioned
above.
>>>
>>> Maybe we can think of some better solution.
>>>
>>> Thanks
>>>
>>> -Krishna
>>>
>>>> On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution > >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>
>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto: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
>>
> _______________________________________________
> 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


(TJ Usiyan) #16

The benefit, as I see it, to this approach is not that it reduces noise. It
is that it standardizes the naming decision in a broadly applicable manner.
Look at the discussion that took place around `union` and `formUnion` to
see that this standardization could be beneficial. The argument that this
would 'add noise' seems flawed to me, since there is at least as much
'noise' in distinguishing between `sort` and `sorted`.

All of that said, I do have a concern that whatever character we use might
be too subtle or easily confused with some other meaning. I understand that
`&` was just a suggestion but, for example, the proximity to another place
where that glyph would be valid and have a different meaning is a potential
issue.

I think that we should seriously consider this, 'noise' ideas aside. If we
could agree on a convention that didn't need to consider the specific
grammar of the methods, we would have removed a major wrinkle in designing
Swift APIs.

TJ

···

On Fri, Apr 22, 2016 at 8:04 AM, Patrick Smith via swift-evolution < swift-evolution@swift.org> wrote:

Well, you could actually have something like this now, and use whether the
returned result was used or not to know if was a mutating or nonmutating
method or not.

Patrick

On Fri, Apr 22, 2016 at 4:53 AM -0700, "James Campbell via > swift-evolution" <swift-evolution@swift.org> wrote:

What if we had a concept similar to errors and try ?

Given this function:

func sort() -> Self {
}

mutating sort() -> Self {
}

If a developer calls:

array.sort()

It will sort a copy of that array, in order to sort in place the
developer must confirm the mutation like so:

mutate array.sort()

This will then call the mutating version of sort :slight_smile:

*___________________________________*

*James⎥Chief Of Fun*

*james@supmenow.com <james@supmenow.com>⎥supmenow.com
<http://supmenow.com>*

*Sup*

*Runway East *

*10 Finsbury Square*

*London*

* EC2A 1AF *

On 22 April 2016 at 12:31, Haravikk via swift-evolution < >> swift-evolution@swift.org> wrote:

This is why I mentioned Xcode; while we can have ampersand as a language
feature for marking such things explicitly (i.e- developer consents to
doing it), we could also just have Xcode highlight inout parameters and
mutating methods differently, but would these represent the same explicit
“I know that what I’m doing here will have side-effects” impact (especially
if other IDEs add Swift support but don’t do this).

> On 22 Apr 2016, at 11:54, Vladimir.S via swift-evolution < >>> swift-evolution@swift.org> wrote:
>
> From one point of view, it will be really awesome if we'll have some
kind of 'marker' for mutating methods so we can clearly see in code if that
method changes the instance(just like we all agree that we must specify &
for inout parameter).
>
> From other point of view, this will add a much more noise(and typing)
in code as we often(in most cases?) use mutating methods. Have a code with
a huge number of & symbols(or other) in it - not the best thing.
>
> I don't see how we can unite both points.
>
> On 22.04.2016 10:00, Tyler Cloutier via swift-evolution wrote:
>> If I recall correctly there was a thread with a similar idea which
instead
>> would create a new operator for mutation or a new way of method
invocation,
>> such that mutating methods would be called with &. or something
similar. e.g.
>>
>> foo&.add(5)
>>
>> I think the consensus was that that was not a particularly familiar
syntax
>> and it would add a decent amount of noise.
>>
>> There may have also been some issues with the grammar, I can't recall.
>>
>> On Apr 21, 2016, at 11:40 PM, Krishna Kumar via swift-evolution >>> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>>> Hey
>>>
>>> I think adding “&” to methods will reduce the readability of the
code.
>>> Also, keyword “mutating” makes it super clear and readable that my
method
>>> is mutating the values.
>>>
>>> 1. mutating func add(value: Double){…}
>>>
>>> 2. func add&(value: Double){…}
>>>
>>> I think it’s easy to skip the information encoded into the 2nd
function
>>> which is this function is mutating a value as compared to 1st. When I
>>> read 1st function I start reading with keyword “mutating” making its
>>> intentions clear to me.
>>>
>>> Also, it might become a symbol nightmare with following type
signature of
>>> a function-
>>>
>>> func nightmare&(title: String?) -> String? -> String?{…}
>>>
>>> I can see the advantage of using “&” when calling a function. It
makes
>>> clear at the call site that this method is mutating but still I don’t
>>> find eliminating “mutating” a good step for the reasons mentioned
above.
>>>
>>> Maybe we can think of some better solution.
>>>
>>> Thanks
>>>
>>> -Krishna
>>>
>>>> On Apr 21, 2016, at 10:38 PM, Daniel Steinberg via swift-evolution >>> >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >>> wrote:
>>>>
>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto: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
>>
> _______________________________________________
> 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

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


(Dave Abrahams) #17

I'd like to second James Campbell's suggestion of a `mutate` keyword. Clarifying
comments inline below:

    This is not a new idea. Something almost identical to this has been
    explored and discussed quite thoroughly already:
    <https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
    In fact, it was implmented and later reverted because it raised
    language-design questions for which we had no good answers.

I don't know if the following are particularly good answers, but I'll try
anyway:

    I don't believe the choice of glyph (& vs =) affects any of the

    fundamental issues:

    * Should the x.=f() syntax be required for *every* mutating method
    invocation?

Allow me to ask it differently: Should some specific syntax be required for
every mutating method? — Yes.

Should the syntax be `x.=f()`? — Not necessarily. I kinda like James Campbell's
idea of a `mutate` keyword. Consider the following:

var numbers = [5, 12, 6, 2]
mutate numbers.append(10)
mutate numbers.sort()
if let biggest = mutate numbers.popLast() {
print("The biggest number was:", biggest)
}

Not that syntax is the most important question here, but that syntax is
super-heavyweight by comparison and unlikely to fly with many people
(including me) for that reason.

So `mutate` would work much like `try` but—unlike `try` which can move
further to the left—`mutate` would have to always prefix the mutating
receiver. Here's a contrived example of a corner case:

enum Error : ErrorType { case BadNumber }

func demo() throws -> Int {
}

    * Are assignment methods a redundant way to spell mutating methods?
    Should we really have both mechanisms?

(I had to look up the definition of an assignment method. For the uninitiated,
Dave is talking about what's written here:
https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst#use-one-simple-name.)

— Yes they are redundant, and no, we should not have both.

With `mutate` required at the call site, we could simply allow both overloads
`func sort()` and `mutating func sort()` to coexist, because the call sites
become unambiguous:

let originals = [2, 1, 3, 0, 4, 2]
var copies = originals

originals.sort() // warning: result of call to 'sort()' is unused
mutate originals.sort() // compiler error
let xs = originals.sort() // ok

copies.sort() // warning: result of call to 'sort()' is unused
mutate copies.sort() // ok
let ys = copies.sort() // ok
let zs = mutate copies.sort() // warning: constant 'x' inferred to have type '
()', which may be unexpected

The language could also allow the use of

mutate x.next()

as shorthand for

x = x.next()

when only the non-mutating variant `func next() -> Self` exists with
compatible return type.

    * Can we really introduce this feature without having a way to apply it
    to class types?

Yes we can. Why complicate the naming of value type members with the
complexities of reference semantics?

Because some people still imagine that classes should have all the same
basic capabilities as value types, and that protocols should unify them.
That makes these people suspicious of language features that could
threaten to make classes “second-class citizens.”

Maybe the Foundation value types effort will begin to change that; I'm
not sure.

The current API naming conventions are good for reference types which
sometimes come with unobvious to obscure behaviour (i.e. anything from
bumping an internal counter to firing missiles and wiping hard
drives).

But value types ought to have no side effects (besides memory allocation and
logging maybe), and so we don't necessarily need that strong a naming convention
to limit their collateral damage.

If the `mutate` keyword became required for calling `mutating` methods, then
operators would remain the only place where naming convention were needed to
distinguish mutation:

* Mutating assignment is explicit: `xs = [1, 2] + xs + [2, 1]` (i.e. `=` without
  `let` or `var` means mutation)
* Mutating method call becomes explicit: `mutate xs.sort()` and `let x = mutate
  xs.removeAtIndex(2)`
* Mutating function arguments are explicit with the `&` prefix: `swap(&xs, &ys)`
* Mutating operators are implicit and by convention, should end with the `=`
  symbol: `xs += [8, 9]`
* Reference types have no notion of `mutating` members (and probably ought to
  remain that way) so they mutate implicitly.

    I should also point out that under the assignment method paradigm one
    would probably need to re-evalutate rules for naming. Under the current
    API guidelines' approach, we'd write:

    x.=sorted() // sort x in-place

    and I am not sure how easy that would be for people to swallow
    considering how much more straightforward

    x.sort() // current way to sort x in-place

    is, and because the language now contains explicit notation for
    mutation, it becomes harder to argue against theis pair:

    y = x.sort()
    x.=sort() // sort x in place

I agree that the current API guidelines wouldn't work for value types anymore.
Both `sort` and `sorted` would be called `sort`.

    Lastly, I should point out that the proposal does nothing to solve the
    problem of `c.formSuccessor(&i)`, since that doesn't mutate the
    receiver.

This proposal does address the problem of `c.formSuccessor(&i)`. Given that it's
value types at play here, what mutates in the following is unambiguous even to
non-native English speakers:

c.frobnicate(&i) // cannot possibly mutate c but mutates i
let j = c.frobnicate(i) // cannot possibly mutate either
mutate c.frobnicate(i) // mutates c
let k = mutate c.frobnicate(&i) // mutates both

That's one possible answer.

    I still like the proposal's basic approach and would love to see it used
    to address these naming problems, but I want to be clear that it's by no
    means a panacea and there are real obstacles between here and actually
    being able to apply it. If you want to move forward with something like
    this, you need to solve the problems described above.

I think this proposal would simplify all code handling value types. Yes, it adds
one keyword of boilerplate but wins clarity in return. I think reference types
should stay separate from this discussion, as their mutation has always been
implicit anyway. The API guidelines set a good convention for them.

Interesting. When you say it, it all sounds so reasonable… yet, I was
making the same arguments when the feature was pulled out of Swift.
Maybe someone other than me needs to lay out the issues more clearly.

···

on Sat Apr 23 2016, Pyry Jahkola <pyry.jahkola-AT-iki.fi> wrote:

    On 23 Apr 2016, at 00:24, Dave Abrahams via swift-evolution > <swift-evolution@swift.org> wrote:

--
Dave


(Dave Abrahams) #18

Q: Would it be possible to allow some sigil in method names (say, prefix/postfix
`=`) without any automatic/magic treatment of these methods?

Almost anything is possible ;-).

In Ruby, after all, postfix `!` is just allowed in names. It doesn’t have any
semantic meaning for the interpreter, it’s just the (strong, well agreed upon)
convention to use it to mark mutating methods in mutating/non-mutating pairs,
like `foo.map(…)` vs `foo.map!(…)`.

It works out well for Ruby. Would it be out of question to allow the same thing
in Swift? A naming convention (`foo.sort()` vs `foo.sort=()`), not an automatic
language feature?

I don't think we'd want to allow this without tying it to mutation; just IMO.

···

on Mon Apr 25 2016, Radosław Pietruszewski <radexpl-AT-gmail.com> wrote:

--
Dave


(Thorsten Seitz) #19

I'd like to second James Campbell's suggestion of a `mutate` keyword. Clarifying comments inline below:

This is not a new idea. Something almost identical to this has been
explored and discussed quite thoroughly already:
<https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
In fact, it was implmented and later reverted because it raised
language-design questions for which we had no good answers.

I don't know if the following are particularly good answers, but I'll try anyway:

I don't believe the choice of glyph (& vs =) affects any of the
fundamental issues:

* Should the x.=f() syntax be required for *every* mutating method
invocation?

Allow me to ask it differently: Should some specific syntax be required for every mutating method? — Yes.

I think I like that idea.

Should the syntax be `x.=f()`? — Not necessarily. I kinda like James Campbell's idea of a `mutate` keyword. Consider the following:

    var numbers = [5, 12, 6, 2]
    mutate numbers.append(10)
    mutate numbers.sort()
    if let biggest = mutate numbers.popLast() {
        print("The biggest number was:", biggest)
    }

So `mutate` would work much like `try` but—unlike `try` which can move further to the left—`mutate` would have to always prefix the mutating receiver.

That doesn't look so bad (we might shorten 'mutate' to 'mut', though I don't think that would be really necessary).
I'm wondering how to deal with fluent interfaces which do mutate the receiver and return 'self', i.e. the builder pattern. I think we can simply require that such a chained expression is required to consist of only mutating calls (or only non-mutating calls), so that one 'mutate' for the whole expression would be sufficient.
Expressions combining mutating calls to different receivers which have return values would simply be prohibited. This would probably be bad style anyway (contrary to the fluent example), or does anyone have a good counter example?

Here's a contrived example of a corner case:

    enum Error : ErrorType { case BadNumber }

    func demo() throws -> Int {
        
    }

* Are assignment methods a redundant way to spell mutating methods?
Should we really have both mechanisms?

(I had to look up the definition of an assignment method. For the uninitiated, Dave is talking about what's written here: https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst#use-one-simple-name.)

— Yes they are redundant, and no, we should not have both.

With `mutate` required at the call site, we could simply allow both overloads `func sort()` and `mutating func sort()` to coexist, because the call sites become unambiguous:

    let originals = [2, 1, 3, 0, 4, 2]
    var copies = originals

    originals.sort() // warning: result of call to 'sort()' is unused
    mutate originals.sort() // compiler error
    let xs = originals.sort() // ok

    copies.sort() // warning: result of call to 'sort()' is unused
    mutate copies.sort() // ok
    let ys = copies.sort() // ok
    let zs = mutate copies.sort() // warning: constant 'x' inferred to have type '()', which may be unexpected

The language could also allow the use of

    mutate x.next()

as shorthand for

    x = x.next()

when only the non-mutating variant `func next() -> Self` exists with compatible return type.

* Can we really introduce this feature without having a way to apply it
to class types?

Yes we can. Why complicate the naming of value type members with the complexities of reference semantics? The current API naming conventions are good for reference types which sometimes come with unobvious to obscure behaviour (i.e. anything from bumping an internal counter to firing missiles and wiping hard drives).

But value types ought to have no side effects (besides memory allocation and logging maybe), and so we don't necessarily need that strong a naming convention to limit their collateral damage.

If the `mutate` keyword became required for calling `mutating` methods, then operators would remain the only place where naming convention were needed to distinguish mutation:

Mutating assignment is explicit: `xs = [1, 2] + xs + [2, 1]` (i.e. `=` without `let` or `var` means mutation)
Mutating method call becomes explicit: `mutate xs.sort()` and `let x = mutate xs.removeAtIndex(2)`
Mutating function arguments are explicit with the `&` prefix: `swap(&xs, &ys)`
Mutating operators are implicit and by convention, should end with the `=` symbol: `xs += [8, 9]`
Reference types have no notion of `mutating` members (and probably ought to remain that way) so they mutate implicitly.

I should also point out that under the assignment method paradigm one
would probably need to re-evalutate rules for naming. Under the current
API guidelines' approach, we'd write:

   x.=sorted() // sort x in-place

and I am not sure how easy that would be for people to swallow
considering how much more straightforward

   x.sort() // current way to sort x in-place

is, and because the language now contains explicit notation for
mutation, it becomes harder to argue against theis pair:

   y = x.sort()
   x.=sort() // sort x in place

I agree that the current API guidelines wouldn't work for value types anymore. Both `sort` and `sorted` would be called `sort`.

Lastly, I should point out that the proposal does nothing to solve the
problem of `c.formSuccessor(&i)`, since that doesn't mutate the
receiver.

This proposal does address the problem of `c.formSuccessor(&i)`. Given that it's value types at play here, what mutates in the following is unambiguous even to non-native English speakers:

    c.frobnicate(&i) // cannot possibly mutate c but mutates i
    let j = c.frobnicate(i) // cannot possibly mutate either
    mutate c.frobnicate(i) // mutates c
    let k = mutate c.frobnicate(&i) // mutates both

That's really very straightforward.

As an alternative to the mutate keyword I rather like using '&' because it already means 'inout'. Using '&.' as mutating method call would therefore be quite understandable.

c&.frobnicate(i)
let k = c&.frobnicate(&i)

Or marking the method like suggested elsewhere:

c.frobnicate&(i)
let k = c.frobnicate&(&i)

-Thorsten

···

Am 23.04.2016 um 10:27 schrieb Pyry Jahkola via swift-evolution <swift-evolution@swift.org>:

On 23 Apr 2016, at 00:24, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

I still like the proposal's basic approach and would love to see it used
to address these naming problems, but I want to be clear that it's by no
means a panacea and there are real obstacles between here and actually
being able to apply it. If you want to move forward with something like
this, you need to solve the problems described above.

I think this proposal would simplify all code handling value types. Yes, it adds one keyword of boilerplate but wins clarity in return. I think reference types should stay separate from this discussion, as their mutation has always been implicit anyway. The API guidelines set a good convention for them.

— Pyry

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


(Tyler Cloutier) #20

I'd like to second James Campbell's suggestion of a `mutate` keyword. Clarifying comments inline below:

This is not a new idea. Something almost identical to this has been
explored and discussed quite thoroughly already:
<https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst>.
In fact, it was implmented and later reverted because it raised
language-design questions for which we had no good answers.

I don't know if the following are particularly good answers, but I'll try anyway:

I don't believe the choice of glyph (& vs =) affects any of the
fundamental issues:

* Should the x.=f() syntax be required for *every* mutating method
invocation?

Allow me to ask it differently: Should some specific syntax be required for every mutating method? — Yes.

Should the syntax be `x.=f()`? — Not necessarily. I kinda like James Campbell's idea of a `mutate` keyword. Consider the following:

    var numbers = [5, 12, 6, 2]
    mutate numbers.append(10)
    mutate numbers.sort()
    if let biggest = mutate numbers.popLast() {
        print("The biggest number was:", biggest)
    }

So `mutate` would work much like `try` but—unlike `try` which can move further to the left—`mutate` would have to always prefix the mutating receiver. Here's a contrived example of a corner case:

    enum Error : ErrorType { case BadNumber }

    func demo() throws -> Int {
        
    }

* Are assignment methods a redundant way to spell mutating methods?
Should we really have both mechanisms?

(I had to look up the definition of an assignment method. For the uninitiated, Dave is talking about what's written here: https://github.com/apple/swift/blob/master/docs/proposals/Inplace.rst#use-one-simple-name.)

— Yes they are redundant, and no, we should not have both.

With `mutate` required at the call site, we could simply allow both overloads `func sort()` and `mutating func sort()` to coexist, because the call sites become unambiguous:

    let originals = [2, 1, 3, 0, 4, 2]
    var copies = originals

    originals.sort() // warning: result of call to 'sort()' is unused
    mutate originals.sort() // compiler error
    let xs = originals.sort() // ok

    copies.sort() // warning: result of call to 'sort()' is unused
    mutate copies.sort() // ok
    let ys = copies.sort() // ok
    let zs = mutate copies.sort() // warning: constant 'x' inferred to have type '()', which may be unexpected

The language could also allow the use of

    mutate x.next()

as shorthand for

    x = x.next()

when only the non-mutating variant `func next() -> Self` exists with compatible return type.

* Can we really introduce this feature without having a way to apply it
to class types?

Yes we can. Why complicate the naming of value type members with the complexities of reference semantics? The current API naming conventions are good for reference types which sometimes come with unobvious to obscure behaviour (i.e. anything from bumping an internal counter to firing missiles and wiping hard drives).

But value types ought to have no side effects (besides memory allocation and logging maybe), and so we don't necessarily need that strong a naming convention to limit their collateral damage.

If the `mutate` keyword became required for calling `mutating` methods, then operators would remain the only place where naming convention were needed to distinguish mutation:

Mutating assignment is explicit: `xs = [1, 2] + xs + [2, 1]` (i.e. `=` without `let` or `var` means mutation)
Mutating method call becomes explicit: `mutate xs.sort()` and `let x = mutate xs.removeAtIndex(2)`
Mutating function arguments are explicit with the `&` prefix: `swap(&xs, &ys)`
Mutating operators are implicit and by convention, should end with the `=` symbol: `xs += [8, 9]`
Reference types have no notion of `mutating` members (and probably ought to remain that way) so they mutate implicitly.

I should also point out that under the assignment method paradigm one
would probably need to re-evalutate rules for naming. Under the current
API guidelines' approach, we'd write:

   x.=sorted() // sort x in-place

and I am not sure how easy that would be for people to swallow
considering how much more straightforward

   x.sort() // current way to sort x in-place

is, and because the language now contains explicit notation for
mutation, it becomes harder to argue against theis pair:

   y = x.sort()
   x.=sort() // sort x in place

I agree that the current API guidelines wouldn't work for value types anymore. Both `sort` and `sorted` would be called `sort`.

Lastly, I should point out that the proposal does nothing to solve the
problem of `c.formSuccessor(&i)`, since that doesn't mutate the
receiver.

This proposal does address the problem of `c.formSuccessor(&i)`. Given that it's value types at play here, what mutates in the following is unambiguous even to non-native English speakers:

    c.frobnicate(&i) // cannot possibly mutate c but mutates i
    let j = c.frobnicate(i) // cannot possibly mutate either
    mutate c.frobnicate(i) // mutates c
    let k = mutate c.frobnicate(&i) // mutates both

How would this chain if I wanted to do something like:

let median = foo.calculateBigHugeArray().sort().medianValue()

and I want the sort to be done in place. Or will this type of thing just be disallowed in favor of.

let array = foo.calculateBigHugeArray()
mutate array.sort()
let median = array.medianValue()

Alternately you could replace the method invocation operator with &

let median = foo.calculateBigHugeArray()&sort().medianValue()

Or depending how sacrilegious you’re feeling you could use the only character on the keyboard that isn’t currently used and doesn’t require the shift key and is easily distinguished from a ‘.’

let median = foo.calculateBigHugeArray()'sort().medianValue()

This is definitely more confusing than the & and mutate, since & is used to indicate mutation elsewhere.

Also, if you wanted to stick with consistent & syntax, you could do:

&c.frobnicate(i)
and
let k = &c.frobnicate(&i)

Dave, to your point about classes, there is currently already special syntax for value types with the & as parameters. Reference semantics is the wild west there anyway.

···

On Apr 23, 2016, at 1:27 AM, Pyry Jahkola via swift-evolution <swift-evolution@swift.org> wrote:

On 23 Apr 2016, at 00:24, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I still like the proposal's basic approach and would love to see it used
to address these naming problems, but I want to be clear that it's by no
means a panacea and there are real obstacles between here and actually
being able to apply it. If you want to move forward with something like
this, you need to solve the problems described above.

I think this proposal would simplify all code handling value types. Yes, it adds one keyword of boilerplate but wins clarity in return. I think reference types should stay separate from this discussion, as their mutation has always been implicit anyway. The API guidelines set a good convention for them.

— Pyry

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