Just some alternate naming suggestions for with() and withVar(), as the naming 
guidelines suggest -ed/-ing:

withVar
altered() // Changes a value copy / reference and returns it
mutated() // Or this, but uses value-specific term ‘mutate’

with
inspect() // Works with an immutable copy, has @discardableResult
use()


> On 28 May 2016, at 10:19 AM, Brent Royal-Gordon via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>>> - A plain `with` whose closure parameter is not mutable and which is marked 
>>> `@discardableResult`.
>> 
>> I would like to see this version restricted to AnyObject.  It has extremely 
>> limited utility with value types.  It would usually be a mistake to call it 
>> with a value type.
> 
> I would not. It gives you a way to give a value type a short, scoped, 
> immutable alias:
> 
>       with(RareMagicalDeviceOwner.shared.spimsterWickets[randomIndex]) {
>               print($0.turns)
>               print($0.turnSpeed)
>       }
> 
> And in this form, there is no danger of mistakenly mutating the value type, 
> because mutating methods would not be allowed:
> 
>       with(RareMagicalDeviceOwner.shared.spimsterWickets[randomIndex]) {
>               $0.turnRepeatedly(times: 3)     // Error: can't call mutating 
> method on immutable parameter
>       }
> 
> To be clear, I'm not convinced there's a need to make any change from the 
> proposed version at all. I'm spitballing alternate designs here, trying to 
> see if there might be something a little better out there. But so far, I 
> think the proposal balances the feature size against strictness pretty well, 
> whereas these stricter designs I'm discussing increase the surface of the 
> feature more than they improve it. This is a small (but significant!) 
> convenience, and I feel pretty strongly that it should have a small 
> implementation.
> 
>> That said, I am not convinced these non-copying functions would be worth 
>> having after method cascades are introduced.  Are there any use cases left 
>> for them in that future?
> 
> Yes, absolutely. Method cascades have a narrow use case: methods on `self`. 
> Not everything in Swift is a method, and not all methods are on `self`.
> 
>       with(tableView.cellForRow(at: indexPath).myLabel) { label in
>               print("Constraining label: \(label)")
>               
>               NSLayoutConstraint.activate(
>                       NSLayoutConstraint.withVisualFormat("|-[label]-|", 
> options: [], metrics: [:], views: ["label": label]) +
>                       NSLayoutConstraint.withVisualFormat("V:|[label]|", 
> options: [], metrics: [:], views: ["label": label])
>               )
>               
>               constrainedLabels.append(label)
>       }
> 
> None of the calls in that `with` block would benefit from method cascades, 
> but they all benefit from `with`.
> 
>>> - A `withVar` whose parameter *is* mutable and which is *not* marked 
>>> `@discardableResult`. (This would help with the fact that our use of 
>>> `@discardableResult` is a little dangerous, in that people might expect 
>>> mutations to affect the original variable even if it's a value type.)
>>> 
>>> `withVar` does, I think, make it pretty clear that you're working with a 
>>> copy of the variable.
>> 
>> One thing to consider in choosing a name here is the cases where this 
>> function would still be useful in a future that includes method cascades.  
>> The one thing this function does that method cascades don’t is make a copy 
>> of the value before operating on it and returning it.  
>> 
>> With that in mind, I think it is worthwhile to consider the name `withCopy` 
>> and make the closure argument optional.
> 
> I specifically considered and rejected `withCopy` because it only creates a 
> copy of a value type, not a reference type. (Of course, it does create a copy 
> of the reference itself, but that's a very subtle distinction.) I chose 
> `withVar` to make it very clear that you're getting the same semantics as you 
> would for a `var` temporary.
> 
>> public func withCopy<T>(_ item: T, update: (@noescape (inout T) throws -> 
>> Void)?) rethrows -> T {
>>   var this = item
>>   try update?(&this)
>>   return this
>> }
>> 
>> This function would be more clear and useful in conjunction with method 
>> cascades:
>> 
>> let bar = withCopy(foo)
>>   ..cascaded = “value"
>>   ..operations()
>>   ..onFoo()
> 
> Honestly, I'm not sure there's a coherent way to make method cascades work 
> with your `withCopy` (or the `copy` function you mentioned upthread) at all.
> 
> Here's the problem. Suppose you have a property like this:
> 
>       var array: [Int]
> 
> And then you write this:
> 
>       array = [1, 2, 3]
>       return array
>                       ..remove(at: 1)
>                       ..remove(at: 0)
> 
> I assume you think this should not only *return* `[3]`, but also *set* 
> `array` to `[3]`. That's kind of implied by the fact that you think we need a 
> `withCopy(array)` call to protect `array` from being affected by these calls.
> 
> But that means that in this version:
> 
>       array = [1, 2, 3]
>       return withCopy(array)
>                       ..remove(at: 1)
>                       ..remove(at: 0)
> 
> You are trying to call `mutating` methods on an *immutable* value, the return 
> value of `withCopy`. Normally, the compiler would reject that.
> 
> Perhaps you could say that method cascades operate on a copy if the receiver 
> is immutable, but that makes code vague and its behavior subtle and easily 
> changed by accident. For instance, if a property is `internal private(set)`, 
> then moving a method cascade from code which can't see the setter to code 
> which can would silently change the code from immutable to mutable. 
> Similarly, adding the `private(set)` would not cause the code which 
> previously modified it to produce an error; it would instead silently change 
> to no longer mutate where it used to before. That's not acceptable behavior 
> from a language feature.
> 
> About the only solution to this I can come up with is to make `withCopy` have 
> an `inout` return. But this at best forms an attractive nuisance: If you use 
> normal `mutating` method calls instead of method cascading, your changes are 
> going to disappear into the ether. And depending on how `inout` returns are 
> actually implemented, it could lead to worse misbehavior.
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to