[swift-evolution] [Pitch] Circling back to `with`

Greg Parker gparker at apple.com
Tue May 31 04:14:13 CDT 2016


> On May 27, 2016, at 5:19 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at 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`.

What are the differences or benefits of the above examples over the existing `do { let ... }` form?

    do {
      let w = RareMagicalDeviceOwner.shared.spimsterWickets[randomIndex]
      print(w.turns)
      print(w.turnSpeed)
    }

    do {
      let label = tableView.cellForRow(at: indexPath).myLabel
      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)
    }


-- 
Greg Parker     gparker at apple.com     Runtime Wrangler




More information about the swift-evolution mailing list