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

Dave Abrahams dabrahams at apple.com
Thu Jan 28 12:56:01 CST 2016


on Thu Jan 28 2016, Jordan Rose <swift-evolution at swift.org> wrote:

> I still don't understand how value types and reference types are
> different here. Here's a contrived "confusion" example (but we have
> seen similar real-world code):
>
> for var element in array {
>   if element.isNotUpToMyStandards {
>     element = makeANewElement()
>     // 'element' is not stored back into 'array', but was meant to be.
>   }
> }
>
> This code, or rather the behavior the developer intended, is perfectly
> reasonable. But it's exactly the same code whether there's a value
> type or a reference type involved. I get that there are other examples
> where this is not the case, but I can't see how those would be any
> less confusing by adding this rule.

The difference between value types and reference types here is that in
many examples (but not this one), a reference type will hide the fact
that "var" doesn't produce writeback semantics, and the user who expects
writeback will only discover it much later.

[IMO this mis-expectation is better treated through education than
through language surface changes, FWIW]

>
> But maybe I'm just too familiar with Swift, and so have trouble
> putting myself in the shoes of a new learner.
>
> Jordan
>
>> On Jan 27, 2016, at 20:45 , J. Cheyo Jimenez
>> <cheyo at masters3d.com> wrote:
>> 
>> Reassigning of class objects probably occurs less than mutations of
>> structs inside `if var` or `guard var`.
>> The main reason for the removal of `if var` or `guard var`, AFAIK,
>> is that people get confuse about references.  Perhaps just limiting
>> their use for value types could then clear up the confusion.
>> example of warning. 
>> "'if var' is restricted to value types, did you mean 'if let'?"
>> 
>> One of the issues is that now all comma separated optionals need to
>> be value types or offer alternative syntax.
>> 
>> if var value1 = value1, ref1 = ref1 {} /// This would not work
>> 
>> if var value1 = value1, let ref1 = ref1 {} /// Possible solution, notice the `let`
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> On Wed, Jan 27, 2016 at 8:05 PM, Jordan Rose
>> <jordan_rose at apple.com
>> <mailto:jordan_rose at apple.com>> wrote:
>> That doesn't make sense to me. If it's sometimes necessary to
>> reassign a struct containing a single reference, then surely it may
>> be necessary to reassign a single reference not contained in a
>> struct.
>> 
>> Jordan
>> 
>>> On Jan 26, 2016, at 20:37 , Nate Birkholz via swift-evolution
>>> <swift-evolution at swift.org
>>> <mailto:swift-evolution at swift.org>>
>>> wrote:
>>> 
>>> Seems in line with other compiler warnings.
>>> 
>>> Sent from my iPhone, please excuse brevity and errors
>>> 
>>> On Jan 26, 2016, at 8:30 PM, J. Cheyo Jimenez via swift-evolution
>>> <swift-evolution at swift.org
>>> <mailto:swift-evolution at swift.org>>
>>> wrote:
>>> 
>>>> Would it be confusing if `guard var ` or  `if var ` was only allowed for value types? 
>>>> 
>>>> 
>>>> On Tuesday, January 26, 2016, Dave Abrahams via swift-evolution
>>>> <swift-evolution at swift.org
>>>> <mailto:swift-evolution at swift.org>>
>>>> wrote:
>>>> 
>>>> on Tue Jan 26 2016, Tian Zhang
>>>> <swift-evolution at swift.org <>>
>>>> wrote:
>>>> 
>>>> > I’m also curious how most people fix “guard var” or “if var”?
>>>> > Especially for checking a class object for protocol conformation and
>>>> > set variable on the object?
>>>> >
>>>> > like in this case,
>>>> >
>>>> >> if var vc = vc as? ControlPanelConfigurationProtocol {
>>>> >>         vc.servicePresentationObject = service
>>>> >>         vc.presentAsPanel = true
>>>> >> }
>>>> >
>>>> > become
>>>> >
>>>> >> if let vc = vc as? ControlPanelConfigurationProtocol {
>>>> >>         var vc = vc
>>>> >>
>>>> >>         vc.servicePresentationObject = service
>>>> >>         vc.presentAsPanel = true
>>>> >> }
>>>> 
>>>> 
>>>> If vc has class type, you don't need the var at all.
>>>> 
>>>> > I saw a few people suggest to create a method on the protocol like
>>>> > “configureObject(...)” with all potential args and have the object to
>>>> > figure it out but doing so I feel we’re losing the benefits offered by
>>>> > property observation for the underlying object. Using pattern “if let”
>>>> > with a “var” in the block just to make the property mutable again
>>>> > feels really strange.
>>>> >
>>>> > Best Wishes,
>>>> > Tian
>>>> >> An alternative would certainly be interesting but I would prefer to
>>>> >> take it one step at a time and avoid being hasty so we can come up
>>>> >> with something really great. What did most of your var fixes look
>>>> >> like, by the way? Did you end up changing the layout of your value
>>>> >> types or did you decide to add more vars?
>>>> >>
>>>> >> David
>>>> >>
>>>> >> > On Jan 24, 2016, at 7:19 PM, Zach Waldowski via swift-evolution
>>>> >> > <swift-evolution at swift.org <http://swift.org/>
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution>>>
>>>> >> > wrote:
>>>> >> >
>>>> >> > -1
>>>> >> >
>>>> >> > Having already adopted the syntax in my projects in anticipation of 2.2,
>>>> >> > the increase in clarity at the expense of terseness is appreciated. A
>>>> >> > proposal should not be discussing an alternative, not a rollback.
>>>> >> >
>>>> >> > Cheers!
>>>> >> > Zachary Waldowski
>>>> >> > zach at waldowski.me <http://waldowski.me/>
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution>>
>>>> >> >
>>>> >> > On Fri, Jan 22, 2016, at 12:26 PM, 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 at swift.org <http://swift.org/>
>>>> >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>>
>>>> >> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>>
>>>> >> > _______________________________________________
>>>> >> > swift-evolution mailing list
>>>> >> > swift-evolution at swift.org <http://swift.org/>
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution>>
>>>> >> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> >> > <https://lists.swift.org/mailman/listinfo/swift-evolution>>
>>>> > _______________________________________________
>>>> > swift-evolution mailing list
>>>> > swift-evolution at swift.org <>
>>>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> > <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> 
>>>> --
>>>> -Dave
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
>> 
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-- 
-Dave



More information about the swift-evolution mailing list