> 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