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

Dany St-Amant dsa.mls at icloud.com
Thu Apr 28 21:01:54 CDT 2016


> Le 28 avr. 2016 à 03:34, Pyry Jahkola via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> Good that you brought the topic of "fluent" interfaces up. I don't see any problem with explicit value type mutation and method chaining because fluent interfaces are constrained to reference types by the language. Details below:
> 
>> On 28 Apr 2016, at 03:44, Tyler Cloutier <cloutiertyler at aol.com> wrote:
>> 
>> 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.
> 
> I think I can guess what you wanted the above to mean but, mind you, the in-place sort returns `()` so you wouldn't chain its result like that. On the other hand, the above code already works using the non-mutating `.sort()` (to be known as `.sorted()` in Swift 3), and—correct me if I'm wrong—the compiler probably optimises the copy away using copy-on-write anyway.
> 
>> Or will this type of thing just be disallowed in favor of.
>> 
>> let array = foo.calculateBigHugeArray()
>> mutate array.sort()
>> let median = array.medianValue() 
> 
> Yes, I think mutating code should be written in many statements rather than squeezing everything into one long expression.
> 
> Indeed, no currently working method chaining would be disallowed in my proposal. Let's consider the example of "fluent API" for value types, i.e. one where you'd extensively `return self` in `mutating` methods. Firstly, the stdlib doesn't practice that at all. And I failed to find any popular Swift libraries that would do so on Github either. The reason is simple: fluent mutating APIs on value types don't work.
> 
> Consider the following silly example that shortens an array in half (but demonstrates the use of `return self` in a `mutating` method):
> 
>     extension Array {
>         mutating func halve() -> Array {
>             self = self[0 ..< count / 2]
>             return self
>         }
>     }
> 
> Suppose I want to get the result of halving an array twice. What happens?
> 
>     var xs = [1,2,3,4,5,6,7,8]
>     xs.halve().halve()
>     // error: cannot use mutating member on immutable value: function call returns immutable value
> 
> So no, fluent APIs on value types are not a thing in Swift. Not now at least. Making mutation explicit along this proposal has nothing to do with fluent APIs.

But is this limitation as per design, or just something that no one reported as a bug yet? When acting on large piece of data and simple operations one might want to chain mutable version (to avoid large allocation) of the operations as a single stream (à la functional programming)  instead of having to use multiple line of:
  mutate largeData.operation()

On a side note, this "long" explicit 'mutate' keyword could be seen by some as a way to impose the use immutability by making it harder (more to type) to use mutability.

Also, this 'mutate' could maybe help to differentiate between sort() 2.2-style and sort() 3.0-style, and avoid endless discussion on InPlace/form/ed/ing. But for language uniformity, would this new 'mutate' keyword be required on nearly every single standard OOP methods?

mutate graph.pencil.changeColor(Red) // the color properties of pencil is mutated
mutate graph.pencil.changeWidth(wide)
mutate graph.drawFrame() // the graphic is altered/mutated

Not proposing, just asking.

Dany

> 
>> Alternately you could replace the method invocation operator with &
>> 
>> let median = foo.calculateBigHugeArray()&sort().medianValue()
> 
> Don't you think that's too prone to getting mixed up with the binary `&` operator?
> 
>> Also, if you wanted to stick with consistent & syntax, you could do:
>> 
>> &c.frobnicate(i)
>> and 
>> let k = &c.frobnicate(&i)
> 
> 
> Yeah, probably. However, one place where that notation falls short compared to a prefixing keyword like `mutate` is when mutating `self`:
> 
>     extension Array {
>         // Apologies for not having the time to think of a less contrived example than this!
>         mutating func quarter() {
>             mutate self.halve() // Ever since SE-0009, it's unusual to use `self` here.
>             mutate halve()      // Where would you put the `&` prefix in this?
>         }
>     }
> 
> — Pyry
> 
> _______________________________________________
> 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/10e0541a/attachment.html>


More information about the swift-evolution mailing list