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

Ilya Belenkiy ilya.belenkiy at gmail.com
Fri Jan 22 13:31:47 CST 2016


+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 at swift.org> wrote:

> On Jan 22, 2016, at 10:21 AM, David Farler <dfarler at apple.com> wrote:
>
>
> On Jan 22, 2016, at 9:45 AM, Joe Groff <jgroff at apple.com> wrote:
>
>
> On Jan 22, 2016, at 9:26 AM, 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
> }
>
>
> 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 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/20160122/e7c5aacc/attachment.html>


More information about the swift-evolution mailing list