[swift-evolution] mutating/non-mutating suggestion from a Rubyist

Howard Lovatt howard.lovatt at gmail.com
Wed Apr 27 20:11:47 CDT 2016


@Tyler,

Excellent summary of concerns which has made me revise my preferences!

I would suggest a few differences from your suggestions (primarily based on
the interpretation of `mutating <name>` as the name of the method, i.e. the
method name includes `mutating`). The couple of areas I suggest are:

    1. Use `mutating` after `func` in declarations: `func mutating
sort(...)`.
    2. Use mutating after `.` in calls: `array.mutating sort(<)`
    3. Allow mutating for classes:

        protocol P { func mutating p() }
        class AP: P { func mutating p() { ... }
        let aP = AP()
        aP.mutating p() // Mutates what `aP` points to

    2. Treat mutating as part of name when chaining:

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


  -- Howard.

On 28 April 2016 at 10:44, Tyler Cloutier via swift-evolution <
swift-evolution at swift.org> wrote:

>
> On Apr 23, 2016, at 1:27 AM, Pyry Jahkola via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> I'd like to second James Campbell's suggestion of a `mutate` keyword.
> Clarifying comments inline below:
>
> On 23 Apr 2016, at 00:24, Dave Abrahams via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> 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.
>
>
>
> 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160428/de82e14b/attachment-0001.html>


More information about the swift-evolution mailing list