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

Nate Birkholz nbirkholz at gmail.com
Thu Jan 28 12:20:57 CST 2016


Interestingly for me, my first "real" language was Swift (unless you count
fortran in the 80s) so the behaviors of Swift are "normal" to me, but I
still made the mistake of thinking var == object mutability  when coming
back to Swift last month after a year of Objective-C. I get the confusion.
But I also think the removal of the expressiveness of "if var foo {}" is a
shame and would like to see an alternate plan.

I can live without var parameters because it's just a bit of a trick,
really, however convenient.



On Thu, Jan 28, 2016 at 10:05 AM, Jordan Rose via swift-evolution <
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.
>
> 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>
> 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> 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> 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> 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
>>> >> > <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 <
>>> 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 <
>>> 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
>>> >> > <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
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> 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
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> 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
>
>


-- 
Nate Birkholz
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160128/aafa4d77/attachment.html>


More information about the swift-evolution mailing list