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

Tyler Fleming Cloutier cloutiertyler at aol.com
Thu Apr 28 02:59:42 CDT 2016


> On Apr 28, 2016, at 12:34 AM, Pyry Jahkola <pyry.jahkola at iki.fi> wrote:
> 
> 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 <mailto: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.
> 
>> 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 <https://github.com/apple/swift-evolution/blob/master/proposals/0009-require-self-for-accessing-instance-members.md>, it's unusual to use `self` here.
>             mutate halve()      // Where would you put the `&` prefix in this?
>         }
>     }
> 
> — Pyry
> 

You are very correct. Yup, that pretty much addresses all of my concerns. So count me amongst the fans. 

I had something like popLast in mind, but as you point out, return values are immutable in Swift.

struct Foo {
    var y = [5, 6]
    func foo() -> [Int] {
        return y
    }
}
var x = Foo()
x.foo().popLast()?.advanced(by: 1) // error: Cannot use mutating member on immutable value: function call returns immutable value


Thanks! 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160428/dd288a77/attachment.html>


More information about the swift-evolution mailing list