> Le 28 avr. 2016 à 03:34, Pyry Jahkola via swift-evolution 
> <[email protected]> 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 <[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.

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
> [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