Reconsidering SE-0003 Removing var from Function Parameters and Pattern Matching

The core team met to discuss this, taking input from this thread among other things. I will post a follow-up on a new thread.

-Chris

···

On Jan 28, 2016, at 4:40 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

Although I think "if var" should stay (probably just because of symmetry with "if let"), I have minor concerns with this proposal, as it brings up a more fundamental issue in the evolution process:
When is a decision final?

I completely agree with Kevin, especially with the statement that people having problems understanding how "if var" works will replace it with "if let" followed by "var x = x" and having just the same problem.

-Thorsten

···

Am 28.01.2016 um 20:19 schrieb Kevin Ballard via swift-evolution <swift-evolution@swift.org>:

Oh man, huge +1 from me here.

Apparently I never actually read that proposal. I was under the impression it only removed var from function parameters. And while I find that mildly annoying, I was ok with it because of the argument for removing as many keywords as possible from function parameter lists (e.g. to open up those keywords to be used as external parameter names). Though I'd really prefer to keep var anyway.

But I didn't realize until now that it also prohibits `var` from _all_ pattern matching, such as if-let, guard-let, etc. And I find that incredibly restrictive. I am not ok at all with that restriction. It makes no sense to me, and it makes a lot of very clean code become much messier by the addition of completely spurious `var foo = foo` lines everywhere. What's more, you can't even add lines like that everywhere because of Swift's prohibition from shadowing variables from the same scope (e.g. you can't shadow the variable bound from `guard let` because it's in the same scope).

I see Dave Abrahams arguing that this feature is tripping some people up. But I don't see that as appropriate grounds for removing it from the language. If people don't understand `if var` or `for var x in` then they can just not write code that uses that feature. And if the argument is that people might have to read other code that uses that, well, there's plenty of stuff in Swift that you have to actually learn about before you can understand how it works, and using `var` in patterns does not seem like one of the trickiest things. And if the confusion stems from not understanding the difference between `var` and `inout`, I don't see how preventing someone from writing `if var` will solve that confusion, because the same person would presumably have the same confusion about `var foo = bar`.

-Kevin Ballard

On Fri, Jan 22, 2016, at 09:26 AM, David Farler via swift-evolution 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@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

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
}

These examples don't make sense to me. None of them mutate the 'if var rect' binding at all. Are you sure this is what you meant?

I abbreviated there with // Mutate `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) {
// ...
}

You can approximate this today without any new language features:

protocol Updatable {}
extension Updatable {
func with<T>(change: (inout T) -> ()) -> T {
   var update = value
   change(&update)
   return update
}
}

if let rect = selection?.rect.with { $0.origin = newOrigin } {
}

I think this approach generally leads to cleaner code, since it's not forcing you to bind names to otherwise uninteresting intermediate values.

It's definitely more explicit but I don't know if I agree that it's cleaner with respect to the mutations themselves – it has a lot of the same shape. I also worry about performance with this pattern as is.

I wouldn't expect performance to be an issue, at least in optimized code. If 'with' is inlineable and you're applying 'with' to a temporary value, as in this case, the optimizer ought to be able to forward all the copies and ultimately apply the change in-place on the temporary. I agree that the purely library-based approach isn't beautiful, but I do think there's a hole here we should address. Assignments and mutating operations are definitely great and notationally familiar for updating values, but I feel like 'var' shouldn't be your only gateway to that notation—it ought to be easier to apply updates in otherwise immutable expressions too.

-Joe

···

On Jan 22, 2016, at 10:21 AM, David Farler <dfarler@apple.com> wrote:

On Jan 22, 2016, at 9:45 AM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 22, 2016, at 9:26 AM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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.

I disagree. We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case. Classes make this worse, since 'if var' *will* seem to work that way when projecting through optional class references, and the value vs reference semantics divide is confusing enough as it is.

I totally agree that the subtlety of the semantics easily gets lost but I think we can come up with better ways to make them clearer without blowing away a whole class of syntax. I see this confusion as more of a holistic indictment of how we express the semantics rather than just the syntax of `var`. I just don't feel like removing this now is a slam dunk.

Those of us who do understand the semantics don't save anything either—I at least have to mentally audit any code I see using 'if var' to ensure that writeback wasn't intended by the original author. Code is read and maintained more often than it's written, and it's written by more novices than experts, and 'if var' and its friends feel like very expert-writer-centric features to me.

-Joe

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
}

These examples don't make sense to me. None of them mutate the 'if var rect' binding at all. Are you sure this is what you meant?

I abbreviated there with // Mutate `rect.

Ah, sorry, missed that. Years of bad documentation have trained my brain to blank out comments.

-Joe

···

On Jan 22, 2016, at 10:21 AM, David Farler <dfarler@apple.com> wrote:

On Jan 22, 2016, at 9:45 AM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 22, 2016, at 9:26 AM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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) {
// ...
}

You can approximate this today without any new language features:

protocol Updatable {}
extension Updatable {
func with<T>(change: (inout T) -> ()) -> T {
   var update = value
   change(&update)
   return update
}
}

if let rect = selection?.rect.with { $0.origin = newOrigin } {
}

I think this approach generally leads to cleaner code, since it's not forcing you to bind names to otherwise uninteresting intermediate values.

It's definitely more explicit but I don't know if I agree that it's cleaner with respect to the mutations themselves – it has a lot of the same shape. I also worry about performance with this pattern as is.

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.

I disagree. We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case. Classes make this worse, since 'if var' *will* seem to work that way when projecting through optional class references, and the value vs reference semantics divide is confusing enough as it is.

I totally agree that the subtlety of the semantics easily gets lost but I think we can come up with better ways to make them clearer without blowing away a whole class of syntax. I see this confusion as more of a holistic indictment of how we express the semantics rather than just the syntax of `var`. I just don't feel like removing this now is a slam dunk.

Those of us who do understand the semantics don't save anything either—I at least have to mentally audit any code I see using 'if var' to ensure that writeback wasn't intended by the original author. Code is read and maintained more often than it's written, and it's written by more novices than experts, and 'if var' and its friends feel like very expert-writer-centric features to me.

-Joe

Disallowing var where inout is allowed is not the same as if var and guard var. I suspect that as a beginner, it could be confusing that sometimes you can use var where you can use let, but other times, you may not. I suspect that I myself might be confused about it for the foreseeable future.

···

On Jan 22, 2016, at 1:05 PM, Nate Birkholz via swift-evolution <swift-evolution@swift.org> wrote:

How *long* is it confusing, though? I feel like removing the utility and especially the fluid expressiveness of "if var" or var parameters for something that people will learn pretty quickly seems a bit spiteful to the face.

On Fri, Jan 22, 2016 at 9:45 AM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> On Jan 22, 2016, at 9:26 AM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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
> }

These examples don't make sense to me. None of them mutate the 'if var rect' binding at all. Are you sure this is what you meant?

>
>
> 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) {
> // ...
> }

You can approximate this today without any new language features:

protocol Updatable {}
extension Updatable {
  func with<T>(change: (inout T) -> ()) -> T {
    var update = value
    change(&update)
    return update
  }
}

if let rect = selection?.rect.with { $0.origin = newOrigin } {
}

I think this approach generally leads to cleaner code, since it's not forcing you to bind names to otherwise uninteresting intermediate values.

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

I disagree. We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case. Classes make this worse, since 'if var' *will* seem to work that way when projecting through optional class references, and the value vs reference semantics divide is confusing enough as it is. Those of us who do understand the semantics don't save anything either—I at least have to mentally audit any code I see using 'if var' to ensure that writeback wasn't intended by the original author. Code is read and maintained more often than it's written, and it's written by more novices than experts, and 'if var' and its friends feel like very expert-writer-centric features to me.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

That's not the purpose; even though I am not a fan of prohibiting "var"
there, I understand that the purpose of doing so is avoiding confusion,
because some people believe they are getting a reference through which
to mutate the contents of the original optional.

···

on Sun Jan 24 2016, David Owens II <swift-evolution@swift.org> wrote:

Removing var from function params, I get that. But the if-binding is
unfortunate. It's literally a line of code for the sole purpose of
making the compiler happy.

--
-Dave

I tend to agree with David here: there’s a lot more confusion inherent in a “var” parameter than “if var.”

P

···

On Jan 24, 2016, at 10:58 AM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

Removing var from function params, I get that. But the if-binding is unfortunate. It's literally a line of code for the sole purpose of making the compiler happy.

Working with optionals is already clumsy enough, we really don't need to make it more so.

-David

On Jan 23, 2016, at 5:03 AM, J. Cheyo Jimenez via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

if let currentRect = selection?.rect {
  var expandedRect = currentRect

VS

if var expandedRec = selection?.rect {

If let is perfectly fine if most of the code base is with classes. Perhaps I can see the argument on why pattern matching and even why functions should only allow let but for guard and if binding, the uses of var are more practical and less boiler plate specially when dealing with mutable value types.

On Saturday, January 23, 2016, Marc Knaup via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
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@swift.org <javascript:_e(%7B%7D,'cvml','swift-evolution@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@swift.org <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

Good idea.

-Joe

···

On Jan 28, 2016, at 12:43 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case.

Can we address this with a diagnostic?

  var bar: Int? = 1
  if var foo = bar {
    foo += 1 // Warning: Value is never used after modification (foo is a copy, not an alias)
  }
  print(bar)

Neither for or agains the if var, I just wanted to comment on the generic example used in this discussion.

The vast majority of the example provided in this discussion use variable shadowing, and a brief context
if var x = x {
    x =+ x
    print("x is \(x)")
}

It is easy for the original code writer to fully know that the mutation on x is not visible outside the if
if var x = x {
    x =+ x
    print("x is \(x)") // Modified copy
}
print("x is \(x)") // Original copy

We can even say that the future code maintainer will quickly get it due to the short span of the code.

But as the code grows:
if var x = x {
    // some 25 lines of implementation
    x =+ x
    print("x is \(x)")
}
print("x is \(x)")

For the code maintainer, the if var can then easily fall outside his visual range, so the code look like:
    x =+ x
    print("x is \(x)")
}
print("x is \(x)")

The reason as to why the two print display different result can then be quite a head scratcher.

Having support for if var without shadowing might have its merit:
if var y = x { /* */ }
which need to be currently one as
if let tmp = x {
    var y = tmp
}

But it seems that either way, the presence/need of if var, encourage people to use variable shadowing. Shadowing is a required evil in the world of name clashing, but in this if var concept it is a really bad habit.

Dany

···

Le 28 janv. 2016 à 16:45, Jarod Long via swift-evolution <swift-evolution@swift.org> a écrit :

I agree completely with Kevin. It doesn't seem intuitive to me that var in parameters and pattern matching is confusing. I actually see it the opposite way -- "why can I use var here but not there?". Allowing var wherever let can be used increases consistency, which is rarely a bad thing.

I checked for functions that use var parameters in one of my larger projects and found 29 cases (roughly half of which are implementations of arithmetic operators for custom types, which is an area that benefits significantly from this feature). Most of those cases are functions that return a mutated version of a parameter, which I find to be a common and useful pattern. Less common, but still valuable, are cases where it's convenient and logical to track some internal state in one of the function's parameters. For example, a function that draws a list of items of variable height starting at some Y position passed as a parameter can naturally calculate the Y position of the next item by adding each item's height to the initial Y value as it is rendered.

As someone mentioned earlier, I also think that this is a pretty unfortunate pattern:

if let x = x {
  var x = x

Now there are three x's -- an optional one, an immutable one, and a mutable one, all with the same name. That seems to me to create more possibility for confusion than if var does. You can give each one a different name, but I've found that more often than not, it's very difficult to come up with non-arbitrary distinct names in these kinds of situations, and using names like optionalX or mutableX is so off-putting as to be out of the question for me personally.

I agree that it's important to always weigh a feature's value vs. its complexity, but I believe this is a case where the value justifies the complexity.

Jarod

On Jan 28, 2016, at 11:19, Kevin Ballard via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Oh man, huge +1 from me here.

Apparently I never actually read that proposal. I was under the impression it only removed var from function parameters. And while I find that mildly annoying, I was ok with it because of the argument for removing as many keywords as possible from function parameter lists (e.g. to open up those keywords to be used as external parameter names). Though I'd really prefer to keep var anyway.

But I didn't realize until now that it also prohibits `var` from _all_ pattern matching, such as if-let, guard-let, etc. And I find that incredibly restrictive. I am not ok at all with that restriction. It makes no sense to me, and it makes a lot of very clean code become much messier by the addition of completely spurious `var foo = foo` lines everywhere. What's more, you can't even add lines like that everywhere because of Swift's prohibition from shadowing variables from the same scope (e.g. you can't shadow the variable bound from `guard let` because it's in the same scope).

I see Dave Abrahams arguing that this feature is tripping some people up. But I don't see that as appropriate grounds for removing it from the language. If people don't understand `if var` or `for var x in` then they can just not write code that uses that feature. And if the argument is that people might have to read other code that uses that, well, there's plenty of stuff in Swift that you have to actually learn about before you can understand how it works, and using `var` in patterns does not seem like one of the trickiest things. And if the confusion stems from not understanding the difference between `var` and `inout`, I don't see how preventing someone from writing `if var` will solve that confusion, because the same person would presumably have the same confusion about `var foo = bar`.

-Kevin Ballard

On Fri, Jan 22, 2016, at 09:26 AM, David Farler via swift-evolution 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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

+1 for the reversal. Removing var introduces inconsistencies. I never use
var in these contexts, but it's good to have the option.

···

On Fri, Jan 22, 2016 at 1:27 PM Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 10:21 AM, David Farler <dfarler@apple.com> wrote:

On Jan 22, 2016, at 9:45 AM, Joe Groff <jgroff@apple.com> wrote:

On Jan 22, 2016, at 9:26 AM, David Farler via swift-evolution < > swift-evolution@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
}

These examples don't make sense to me. None of them mutate the 'if var
rect' binding at all. Are you sure this is what you meant?

I abbreviated there with // Mutate `rect.

Ah, sorry, missed that. Years of bad documentation have trained my brain
to blank out comments.

-Joe

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) {
// ...
}

You can approximate this today without any new language features:

protocol Updatable {}
extension Updatable {
func with<T>(change: (inout T) -> ()) -> T {
   var update = value
   change(&update)
   return update
}
}

if let rect = selection?.rect.with { $0.origin = newOrigin } {
}

I think this approach generally leads to cleaner code, since it's not
forcing you to bind names to otherwise uninteresting intermediate values.

It's definitely more explicit but I don't know if I agree that it's
cleaner with respect to the mutations themselves – it has a lot of the same
shape. I also worry about performance with this pattern as is.

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.

I disagree. We have a lot of evidence that 'if var' confuses people—a lot
of users think that 'if var' and 'var' bindings in case patterns will write
back to the original value when this isn't the case. Classes make this
worse, since 'if var' *will* seem to work that way when projecting through
optional class references, and the value vs reference semantics divide is
confusing enough as it is.

I totally agree that the subtlety of the semantics easily gets lost but I
think we can come up with better ways to make them clearer without blowing
away a whole class of syntax. I see this confusion as more of a holistic
indictment of how we express the semantics rather than just the syntax of
`var`. I just don't feel like removing this now is a slam dunk.

Those of us who do understand the semantics don't save anything either—I
at least have to mentally audit any code I see using 'if var' to ensure
that writeback wasn't intended by the original author. Code is read and
maintained more often than it's written, and it's written by more novices
than experts, and 'if var' and its friends feel like very
expert-writer-centric features to me.

-Joe

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

But that’s not what assigning something to a var means in any other context. Why should it be any different here?

Charles

···

On Jan 24, 2016, at 12:31 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Sun Jan 24 2016, David Owens II <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Removing var from function params, I get that. But the if-binding is
unfortunate. It's literally a line of code for the sole purpose of
making the compiler happy.

That's not the purpose; even though I am not a fan of prohibiting "var"
there, I understand that the purpose of doing so is avoiding confusion,
because some people believe they are getting a reference through which
to mutate the contents of the original optional.

-1 for me. I think it is clearer if people have to manually copy into a var that copy semantics are in use.

···

Sent from my iPad

On 23 Jan 2016, at 5:27 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 22, 2016, at 10:21 AM, David Farler <dfarler@apple.com> wrote:

On Jan 22, 2016, at 9:45 AM, Joe Groff <jgroff@apple.com> wrote:

On Jan 22, 2016, at 9:26 AM, David Farler via swift-evolution <swift-evolution@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
}

These examples don't make sense to me. None of them mutate the 'if var rect' binding at all. Are you sure this is what you meant?

I abbreviated there with // Mutate `rect.

Ah, sorry, missed that. Years of bad documentation have trained my brain to blank out comments.

-Joe

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) {
// ...
}

You can approximate this today without any new language features:

protocol Updatable {}
extension Updatable {
func with<T>(change: (inout T) -> ()) -> T {
   var update = value
   change(&update)
   return update
}
}

if let rect = selection?.rect.with { $0.origin = newOrigin } {
}

I think this approach generally leads to cleaner code, since it's not forcing you to bind names to otherwise uninteresting intermediate values.

It's definitely more explicit but I don't know if I agree that it's cleaner with respect to the mutations themselves – it has a lot of the same shape. I also worry about performance with this pattern as is.

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.

I disagree. We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case. Classes make this worse, since 'if var' *will* seem to work that way when projecting through optional class references, and the value vs reference semantics divide is confusing enough as it is.

I totally agree that the subtlety of the semantics easily gets lost but I think we can come up with better ways to make them clearer without blowing away a whole class of syntax. I see this confusion as more of a holistic indictment of how we express the semantics rather than just the syntax of `var`. I just don't feel like removing this now is a slam dunk.

Those of us who do understand the semantics don't save anything either—I at least have to mentally audit any code I see using 'if var' to ensure that writeback wasn't intended by the original author. Code is read and maintained more often than it's written, and it's written by more novices than experts, and 'if var' and its friends feel like very expert-writer-centric features to me.

-Joe

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

Do you realize how much confusion it would save if Swift just went with

if bind foo = bar {...}

with let semantics?

-- Erica

···

On Jan 28, 2016, at 11:03 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 28, 2016, at 12:43 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case.

Can we address this with a diagnostic?

  var bar: Int? = 1
  if var foo = bar {
    foo += 1 // Warning: Value is never used after modification (foo is a copy, not an alias)
  }
  print(bar)

Good idea.

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

Im for keeping this

if var x = x {

Actually, I'm hoping Swift allows us to group let/var/optional and
non-optional together. At the moment, a lot of my functions start out with
a couple groups of declarations, before I get to the "meat" of my function.
I'm hoping someday we can do this:

// set up, make sure we unwrap whatever needs unwrapping, and set up
whatever vars we'll use

guard
result_var = Gronk.init()
foo_const = arg.bar_opt,
baz_var = do_something( )
quux_const = 1567
else { return nil }

// the "meat" of my function

...

The reason I'd like to arrange things this way is that I could spend more
time focusing on the logic side of my functions, instead of having to parse
though where my nil checks, and declarations end.

This might be obvious bad form to someone who's taken more CompSci classes
than I have. I realize that for example, having one point of failure for
several unrelated things is ambiguous, and that there would need to be more
syntax to specify what is being declared as let vs var.

Is it though? I mean, I can understand clashes occurring when you use the same local variable/parameter name as you do for a property, but this is easily solved by always using self. in front of usage of the actual property.

Other than that, in my experience at least, a lot of clashes come from poor variable naming; while I understand the appeal of short names for loop indices, it’s not as if we need them a lot thanks to the wealth of options available for accessing sequences so it’s not really a huge burden to use someIndex or whatever as a name. Besides which descriptive variable names are a huge benefit to maintenance in general. At lot the examples are let x = x, to which my first thought is “pick two actual names that tell me something"

Personally I’d prefer to see shadowing of local variables eliminated entirely, as there should be no excuse for running out of names within the scope of a single function, because well designed function implementations shouldn’t be so long (or use so many variables) as to make that a possibility. The only shadowing I’m fine with is parameters over properties, but that’s only because everyone should (in my opinion) be using self. for properties all the time anyway (even when there’s no current naming conflict).

···

On 29 Jan 2016, at 12:25, Dany St-Amant via swift-evolution <swift-evolution@swift.org> wrote:

Shadowing is a required evil in the world of name clashing, but in this if var concept it is a really bad habit.

Hmm, so is this clear or surprising?

  var y = 0
  var x = y
  x += 1
  print(y) // prints 0

If it's unsurprising, can you explain why it's different from var in
all the other contexts?

···

on Fri Jan 22 2016, David Waite <swift-evolution@swift.org> wrote:

-1 for the reversal, because I have been burned by this myself.

The var parameters, cases, and “if var” could all be interpreted as
either making a copy or having inout semantics. The problem is that
the syntax doesn’t make the behavior explicit. IMHO you should be
striving not for a reversal but for a counterproposal.

--
-Dave

-1 for the reversal, because I have been burned by this myself.

The var parameters, cases, and “if var” could all be interpreted as either making a copy or having inout semantics. The problem is that the syntax doesn’t make the behavior explicit. IMHO you should be striving not for a reversal but for a counterproposal.

-DW

···

On Jan 22, 2016, at 12:31 PM, Ilya Belenkiy via swift-evolution <swift-evolution@swift.org> wrote:

+1 for the reversal. Removing var introduces inconsistencies. I never use var in these contexts, but it's good to have the option.
On Fri, Jan 22, 2016 at 1:27 PM Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 22, 2016, at 10:21 AM, David Farler <dfarler@apple.com <mailto:dfarler@apple.com>> wrote:

On Jan 22, 2016, at 9:45 AM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 22, 2016, at 9:26 AM, David Farler via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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
}

These examples don't make sense to me. None of them mutate the 'if var rect' binding at all. Are you sure this is what you meant?

I abbreviated there with // Mutate `rect.

Ah, sorry, missed that. Years of bad documentation have trained my brain to blank out comments.

-Joe

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) {
// ...
}

You can approximate this today without any new language features:

protocol Updatable {}
extension Updatable {
func with<T>(change: (inout T) -> ()) -> T {
   var update = value
   change(&update)
   return update
}
}

if let rect = selection?.rect.with { $0.origin = newOrigin } {
}

I think this approach generally leads to cleaner code, since it's not forcing you to bind names to otherwise uninteresting intermediate values.

It's definitely more explicit but I don't know if I agree that it's cleaner with respect to the mutations themselves – it has a lot of the same shape. I also worry about performance with this pattern as is.

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.

I disagree. We have a lot of evidence that 'if var' confuses people—a lot of users think that 'if var' and 'var' bindings in case patterns will write back to the original value when this isn't the case. Classes make this worse, since 'if var' *will* seem to work that way when projecting through optional class references, and the value vs reference semantics divide is confusing enough as it is.

I totally agree that the subtlety of the semantics easily gets lost but I think we can come up with better ways to make them clearer without blowing away a whole class of syntax. I see this confusion as more of a holistic indictment of how we express the semantics rather than just the syntax of `var`. I just don't feel like removing this now is a slam dunk.

Those of us who do understand the semantics don't save anything either—I at least have to mentally audit any code I see using 'if var' to ensure that writeback wasn't intended by the original author. Code is read and maintained more often than it's written, and it's written by more novices than experts, and 'if var' and its friends feel like very expert-writer-centric features to me.

-Joe

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

I would think the concept of having var on pattern matching at least to be…. problematic since the pattern matching variable would be part of what you are matching.

I would actually prefer pattern matching to be able to infer (hoping) the let since it really looks like horrible clutter on the case statements with regards to pattern matching.

···

On 2016-01-23, at 4:14:54, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Fri Jan 22 2016, David Waite <swift-evolution@swift.org> wrote:

-1 for the reversal, because I have been burned by this myself.

The var parameters, cases, and “if var” could all be interpreted as
either making a copy or having inout semantics. The problem is that
the syntax doesn’t make the behavior explicit. IMHO you should be
striving not for a reversal but for a counterproposal.

Hmm, so is this clear or surprising?

var y = 0
var x = y
x += 1
print(y) // prints 0

If it's unsurprising, can you explain why it's different from var in
all the other contexts?

--
-Dave

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

I made the same argument myself, but you can't argue with empirical
evidence: some people have been tripped up by this anyway.

···

on Sun Jan 24 2016, Charles Srstka <cocoadev-AT-charlessoft.com> wrote:

On Jan 24, 2016, at 12:31 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:

on Sun Jan 24 2016, David Owens II <swift-evolution@swift.org >> <mailto:swift-evolution@swift.org>> wrote:

Removing var from function params, I get that. But the if-binding is
unfortunate. It's literally a line of code for the sole purpose of
making the compiler happy.

That's not the purpose; even though I am not a fan of prohibiting "var"
there, I understand that the purpose of doing so is avoiding confusion,
because some people believe they are getting a reference through which
to mutate the contents of the original optional.

But that’s not what assigning something to a var means in any other
context. Why should it be any different here?

--
-Dave

In the case of "if let x = x { … }”, the shadowing/copying of the original value is not apparent - from the user perspective, the language just “knows” within the block to stop treating “x” like an optional.

In the case of a function parameter, it looks like it is a modifier of the signature, not an internal behavior of the function. Compare:

func foo(var a:String) { }
func bar(inout a:String) { }

This is why I personally recommended earlier in the thread proposing an alternative than a reversal - disallowing the current syntax increases clarity at the expense of terseness, which is one of fundamental design decision driving Swift. If someone has an alternative that increases clarity and terseness together when compared to SE-0003, they will have a much easier time.

-DW

···

On Jan 24, 2016, at 6:44 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 24, 2016, at 12:31 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

That's not the purpose; even though I am not a fan of prohibiting "var"
there, I understand that the purpose of doing so is avoiding confusion,
because some people believe they are getting a reference through which
to mutate the contents of the original optional.

But that’s not what assigning something to a var means in any other context. Why should it be any different here?