> On Apr 28, 2016, at 12:34 AM, Pyry Jahkola <[email protected]> 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 <[email protected] 
>> <mailto:[email protected]>> 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! 
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to