> On Apr 23, 2016, at 1:27 AM, Pyry Jahkola via swift-evolution 
> <[email protected]> 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 
>> <[email protected] <mailto:[email protected]>> 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 
>> <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
>  
> <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
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to