[swift-evolution] Reconsidering SE-0003 Removing var from Function Parameters and Pattern Matching

Marc Knaup marc at knaup.koeln
Sat Jan 23 04:30:51 CST 2016


Scanning through our iOS project with ~600 Swift files we barely use `var`
for function parameters or for if/guard statements.

I think the problems you outline should not be solved by using `var` but by
making the code's intent much clearer by using distinct variable names.

In your example it is not clear what the purpose of the shadowed `rect`
variable is. The same is true if you use `if var rect = …`:

var selection = getRectangularSelection()
if let rect = selection?.rect {
  var rect = rect // what is rect used for? the variable name is quite
generic
  // mutate `rect` ...
  // probably a lot of code
  // …

  selection.rect = rect // what rect again?
}

A better solution is to name the variables differently and make their
intent very clear:

var selection = getRectangularSelection()
if let currentRect = selection?.rect {
  var expandedRect = currentRect // intent becomes clear now
  // expand `expandedRect` ...
  // probably a lot of code
  // …

  selection.rect = expandedRect // ah, THAT rect!
}

So `if var` is really not necessary and causes more harm than good due to
reduced clarity.

-1 for reversing the proposal from me.

On Fri, Jan 22, 2016 at 6:26 PM, David Farler via swift-evolution <
swift-evolution at swift.org> wrote:

> Hello everyone,
>
> I'd like to reconsider SE-0003 for Swift 3 and propose cancelling the
> change in its entirety. After collecting feedback since Swift's open source
> launch, I no longer feel this is a good move and there are a few reasons
> why.
>
> There are two main patterns that the removal penalizes:
>
> - Get-Modify-Reassign
> - Get-Modify-Return
>
> I've found that many of the problems with this proposal stem from the uses
> before and after the "Modify" part, before returning or reassigning with
> the new value.
>
> I've seen a few common responses to the var removal. Consider a
> `Rectangle` struct:
>
>
> struct Rectangle {
>  var origin: (x: Double, y: Double)
>  var size: (width: Double, height: Double)
> }
>
>
> Even with mutable variables `origin` and `size`, this pattern would be
> impossible:
>
>
> var selection = getRectangularSelection()
> if var rect = selection?.rect {
>  // Mutate `rect` ...
>  selection.rect = rect
> }
>
>
> So, one might shadow the variable, which is not ideal:
>
>
> var selection = getRectangularSelection()
> if let rect = selection?.rect {
>  var rect = rect // Not so great
>  // Mutate `rect` ...
>  selection.rect = rect
> }
>
>
> Or, you might make a transformation function on `Rect`:
>
>
> struct Rectangle {
>  var origin: (x: Double, y: Double)
>  var size: (width: Double, height: Double)
>  func withOrigin(x: Double, y: Double) -> Rect {
>    var r = self
>    r.origin = (x, y)
>    return r
>  }
> }
>
>
> This is a much better solution than shadowing but you would need one of
> these for any property that you want to mutate and I think you'll agree
> that it doesn't scale with the language we have today. This response begs
> for a kind of initializer that takes all of the fields of the original
> struct except any that you want to override:
>
>
> if let rect = selection?.rect.with(origin: newOrigin) {
>  // ...
> }
>
>
> Straw syntax, but maybe you'll see something along these lines on
> swift-evolution in the future, which would provide a clear alternative to
> direct mutation patterns. Even then, I think having complementary patterns
> in the language isn't a bad thing.
>
> These problems come up with the other variable bindings but the one that
> ended up bothering me the most was `guard var`:
>
>
> func transform(selection: Rect?) {
>  guard let rect = selection else { return }
>  var _rect = rect
>  // Mutate `_rect` ...
> }
>
>
> One of the guard statement's main purposes is to conditionally bind a
> value as a peer in its own scope, not an inner scope like if statements.
> Not having var makes the guard statement much weaker.
>
> There is certainly a bit of confusion about the nuances between value and
> reference semantics, who owns a value and when, how effects are propagated
> back to values, but I think we can attack the problem with more finesse.
>
> Value types are one of the attractive features of Swift – because of their
> semantics, mutating algorithms are written in a familiar style but keeping
> effects limited to your unique reference. I don't think we should give that
> up now to address confusion about semantics, out of principle, or in
> anticipation of new language features. I propose cancelling this change for
> Swift 3 and continue to allow `var` in the grammar everywhere it occurs in
> Swift 2.2.
>
> Regards,
> David
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160123/cd93a061/attachment.html>


More information about the swift-evolution mailing list