The bind thread

I do not see any necessity in a bind keyword and I don’t believe that it adds any clarity to the language. Furthermore, the current syntax allows one to change the variable name or add additional conditions in transparent manner. I also like that the current syntax make it very obvious that a variable is declared within a local scope. Flow-typing already exists in Swift (via as?) and while it might be a bit more verbose, its also more flexible.

However, I do agree that the specific semantic of let and var in the if context is a bit unexpected. So maybe one should look into making the optional unwrapping semantics more explicit. E.g. what about changing the semantics of ! so that it can be safely used in a conditional context? E.g.

if let x = x! {

}

if let x = x as! SomeType {

}

This would make it very clear that the value is being unwrapped without adding a lot of clutter or additional effort.

Alternative options for making binding more explicit

if let x ?= x
if let x ? x
if let? x = x

etc. But I do like the ! refinement above.

— Taras

···

On 02 Feb 2016, at 01:49, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

I mostly agree with everything you said. I also think "if case" syntax is bad at the moment.

However I think any changes probably have to be an addition rather than a replacement.

I've tried to reconcile these changes with pattern matching and cannot work out how it fits. There's too many inconsistencies and incompatibilities. At best you can make a new pattern matching syntax that's incompatible with switch statements.

On Tuesday, 2 February 2016, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> if bind foo {
> // foo is non-optional in here
> }

If something in a flow control statement should read like an assertion, we don't want "bind" here.

        if has foo {
                // foo is non-optional
        }

However, I do note that pattern matching in an if statement already lets you do the same thing as `if let` more explicitly:

        if case let foo? = bar {

        }

I wonder if we should instead enhance this feature's usability. For instance, as a surgical change, we could drop the `case` keyword when `let` is present in the condition (since `let` isn't allowed in a boolean expression anyway):

        if let foo? = bar {

        }

This is one character longer than the current `if let`, but it falls naturally out of other language features and allows for other similar constructs, like `if let .Success(value) = bar`.

However, the `if case` syntax kind of sucks in other ways, too, and I think it deserves another look. In particular, the `=` isn't great for pattern matching that doesn't bind variables; people have complained about that part of `if case` before. Maybe we can improve that while still making the unwrapping good by introducing a keyword or operator that replaces the `=` while implying the `case` so it doesn't have to be stated explicitly. Here's a strawman of what this would look like, using `matches`:

        if let foo? matches bar
        if let .Success(value) matches bar
        if .Card(let rank, .Heart) matches bar
        if .OK matches bar

Can we do this with `for case` too? Maybe...

        for let foo? matches in bars
        for let .Success(value) matches in bars
        for .Card(let rank, .Heart) matches in bars
        for .OK matches in bars

I think this approach might work; the only question is what `matches` should be. I don't like using a keyword for it; I think it disappears too easily, particularly in the optional case. We do sort of have a pattern matching operator, `~=`, but it's very obscure, the overloading is not really right, and I can never remember which order the characters go in (possibly because Perl uses `=~` as its matching operator). Colon kind of reads well, but it disappears too easily, and it's already associated with typing:

        if let foo?: bar
        if let .Success(value): bar
        if .Card(let rank, .Heart): bar
        if .OK: bar

I don't know what the answer is here, but I think this might be a good line to pursue.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

I'm -1 as stated, I don't think the proposed change adds any clarity, if
anything it adds more things to learn.

I think you can achieve some of your goals with a linter. You need to
consider how this works with pattern matching. It would remove the ability
to mutate the value type in a switch without a reassignment.

I'm closer to liking it if it removes nothing from the language and adds
something like this:

var x: Int?
let y: Int?
if bind x, y where x == y {
    x = 4 // changes the x outside this scope
    y = 5 // compile time error
    x = nil // compile time error
}

I think that makes bind make more sense, and less surprising. However it
doesn't clarify anything about it no longer being optional.

It would be nice if the following worked, although I it has its own issues
with surprises:

let x: Int? = 123
if x != nil {
   ... // x is non-optional here
}
assert(x != nil)
// x is non-optional here

var y: Int? = 456
while y != nil {
    // y is non-optional here
}
// y is optional here

···

On Tuesday, 2 February 2016, T.J. Usiyan via swift-evolution < swift-evolution@swift.org> wrote:

I don't think that the keyword is silly but this is a good point. I forgot
that this application of the `?` postfix exists.

On Mon, Feb 1, 2016 at 2:56 PM, Tyler Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

The bind or exists keywords seem sort of silly to me. There is already
syntax for binding optionals:

if x? {
foo(x) // x type narrowed after binding.
}

Tyler

On Feb 1, 2016, at 11:35 AM, Howard Lovatt via swift-evolution < >> swift-evolution@swift.org> wrote:

I like this proposal. I also think that either bind or exists could be
the keyword. I would suggest that both forms of syntax should be allowed,
e.g.:

    if bind x { /* x is non-nil, unwrapped, and hides original x inside
if statement */ }
    if bind x = object.property { /* x is non-nil and unwrapped */ }

On Tuesday, 2 February 2016, Dave via swift-evolution < >> swift-evolution@swift.org> wrote:

I *think* it’d be _

You could use it to test if the return value is non-nil, but you’d have
to revert to “if let x = …” to actually use the results.

I think.

- Dave Sweeris

On Feb 1, 2016, at 11:22, T.J. Usiyan via swift-evolution < >>> swift-evolution@swift.org> wrote:

This is interesting. What name is created by

  if bind foo.somethingReturningAnOptional {
      // ???
  }

On Mon, Feb 1, 2016 at 2:18 PM, Erica Sadun via swift-evolution < >>> swift-evolution@swift.org> wrote:

Joe says "If you all are serious about this, I think you should start
a new thread about it."
I think it's worth a serious discussion just so it can be evaluated and
either adopted or discarded
and dropped forever. Here goes.

INTRO

The if let x = x {...} and guard let x = x else {...} constructs do
something with let (and var) that's
fundamentally different from let (and var) elsewhere in the language.
The same keywords are used to conditionally unwrap
and bind an item, not just shadow that item's current value.

Introducing a new bind keyword to indicate unwrapping and binding
would disambiguate these uses.

DETAIL DESIGN:

Jacob Bandes-Storch offers two common use-cases. I prefer his "if bind
foo" to my original "if bind foo = foo":

  if bind foo {
      // foo is non-optional in here
  }

  somethingAsync { [weak self] in
      guard bind self else { return }
      // ...
  }

JBS's approach offers my original "bind" keyword to unwrap and shadow
bind, but also provides a way to
strongly bind a weak reference to self, which (presumably) would allow
self semantics in the remaining
lifetime of that scope.

ALTERNATIVE PROPOSALS:

Tino Heth proposes a second use-case one with different semantics. This
case, it seems to make an
alias rather than using binding for shadowing:

bind x = a.property.with.a.long.path
print x // 42
print(a.property.with.a.long.path == 42) => true

presumably this means:

x += 1
print(a.property.with.a.long.path) // 43

DISCUSSION

I'm throwing these both out there. I have nothing to really say about
Tino's but I do think my and Jacob's
proposal has the advantages of:

* Simplifying an mildly complex and potentially misleading statement
* Creating a deliberate and controlled rather than accidental shadowing
style

Have at it.

-- Erica

_______________________________________________
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

--
  -- Howard.

_______________________________________________
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

There is a language, Nice (related to Java), that does:

    if x != nil {
        // x is unwrapped
    }

As Andrew has already suggested as a possibility. However I am not sure
that it is a great idea because why should this particular if statement
have 'magic'?

How about:

     ifsome x { // Equivalent to current `if let x = x`, note `ifsome` is
one word
        // x is unwrapped
    }

This doesn't use `bind` which has some baggage, it doesn't use `var` or
`let` which have other meanings, `ifsome` is an unusual word and hence
unlikely to be useful as a name, and it is clear it is not a normal `if`
statement.

Don't change `case` clauses, they are not confusing, they do introduce a
new variable and hence `let` and `var` are appropriate.

···

On Tuesday, 2 February 2016, Andrew Bennett via swift-evolution < swift-evolution@swift.org> wrote:

I'm -1 as stated, I don't think the proposed change adds any clarity, if
anything it adds more things to learn.

I think you can achieve some of your goals with a linter. You need to
consider how this works with pattern matching. It would remove the ability
to mutate the value type in a switch without a reassignment.

I'm closer to liking it if it removes nothing from the language and adds
something like this:

var x: Int?
let y: Int?
if bind x, y where x == y {
    x = 4 // changes the x outside this scope
    y = 5 // compile time error
    x = nil // compile time error
}

I think that makes bind make more sense, and less surprising. However it
doesn't clarify anything about it no longer being optional.

It would be nice if the following worked, although I it has its own issues
with surprises:

let x: Int? = 123
if x != nil {
   ... // x is non-optional here
}
assert(x != nil)
// x is non-optional here

var y: Int? = 456
while y != nil {
    // y is non-optional here
}
// y is optional here

On Tuesday, 2 February 2016, T.J. Usiyan via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

I don't think that the keyword is silly but this is a good point. I
forgot that this application of the `?` postfix exists.

On Mon, Feb 1, 2016 at 2:56 PM, Tyler Cloutier via swift-evolution < >> swift-evolution@swift.org> wrote:

The bind or exists keywords seem sort of silly to me. There is already
syntax for binding optionals:

if x? {
foo(x) // x type narrowed after binding.
}

Tyler

On Feb 1, 2016, at 11:35 AM, Howard Lovatt via swift-evolution < >>> swift-evolution@swift.org> wrote:

I like this proposal. I also think that either bind or exists could be
the keyword. I would suggest that both forms of syntax should be allowed,
e.g.:

    if bind x { /* x is non-nil, unwrapped, and hides original x inside
if statement */ }
    if bind x = object.property { /* x is non-nil and unwrapped */ }

On Tuesday, 2 February 2016, Dave via swift-evolution < >>> swift-evolution@swift.org> wrote:

I *think* it’d be _

You could use it to test if the return value is non-nil, but you’d have
to revert to “if let x = …” to actually use the results.

I think.

- Dave Sweeris

On Feb 1, 2016, at 11:22, T.J. Usiyan via swift-evolution < >>>> swift-evolution@swift.org> wrote:

This is interesting. What name is created by

  if bind foo.somethingReturningAnOptional {
      // ???
  }

On Mon, Feb 1, 2016 at 2:18 PM, Erica Sadun via swift-evolution < >>>> swift-evolution@swift.org> wrote:

Joe says "If you all are serious about this, I think you should start
a new thread about it."
I think it's worth a serious discussion just so it can be evaluated
and either adopted or discarded
and dropped forever. Here goes.

INTRO

The if let x = x {...} and guard let x = x else {...} constructs do
something with let (and var) that's
fundamentally different from let (and var) elsewhere in the
language. The same keywords are used to conditionally unwrap
and bind an item, not just shadow that item's current value.

Introducing a new bind keyword to indicate unwrapping and binding
would disambiguate these uses.

DETAIL DESIGN:

Jacob Bandes-Storch offers two common use-cases. I prefer his "if bind
foo" to my original "if bind foo = foo":

  if bind foo {
      // foo is non-optional in here
  }

  somethingAsync { [weak self] in
      guard bind self else { return }
      // ...
  }

JBS's approach offers my original "bind" keyword to unwrap and shadow
bind, but also provides a way to
strongly bind a weak reference to self, which (presumably) would allow
self semantics in the remaining
lifetime of that scope.

ALTERNATIVE PROPOSALS:

Tino Heth proposes a second use-case one with different semantics.
This case, it seems to make an
alias rather than using binding for shadowing:

bind x = a.property.with.a.long.path
print x // 42
print(a.property.with.a.long.path == 42) => true

presumably this means:

x += 1
print(a.property.with.a.long.path) // 43

DISCUSSION

I'm throwing these both out there. I have nothing to really say about
Tino's but I do think my and Jacob's
proposal has the advantages of:

* Simplifying an mildly complex and potentially misleading statement
* Creating a deliberate and controlled rather than accidental
shadowing style

Have at it.

-- Erica

_______________________________________________
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

--
  -- Howard.

_______________________________________________
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

--
  -- Howard.

The thing I like about “if let x = y” over all these alternatives — either shorthand like “ifsome” or Ceylon/Kotlin-like expression analysis— is that it generalizes to y being an arbitrary expression.

No special case needed for this:

    if let x = foo.bar?.baz

…or this:

    if let x = y as? SomeType

They just fall out naturally.

P

···

On Feb 1, 2016, at 5:04 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

There is a language, Nice (related to Java), that does:

    if x != nil {
        // x is unwrapped
    }

As Andrew has already suggested as a possibility. However I am not sure that it is a great idea because why should this particular if statement have 'magic'?

How about:

     ifsome x { // Equivalent to current `if let x = x`, note `ifsome` is one word
        // x is unwrapped
    }

This doesn't use `bind` which has some baggage, it doesn't use `var` or `let` which have other meanings, `ifsome` is an unusual word and hence unlikely to be useful as a name, and it is clear it is not a normal `if` statement.

Don't change `case` clauses, they are not confusing, they do introduce a new variable and hence `let` and `var` are appropriate.

On Tuesday, 2 February 2016, Andrew Bennett via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I'm -1 as stated, I don't think the proposed change adds any clarity, if anything it adds more things to learn.

I think you can achieve some of your goals with a linter. You need to consider how this works with pattern matching. It would remove the ability to mutate the value type in a switch without a reassignment.

I'm closer to liking it if it removes nothing from the language and adds something like this:

var x: Int?
let y: Int?
if bind x, y where x == y {
    x = 4 // changes the x outside this scope
    y = 5 // compile time error
    x = nil // compile time error
}

I think that makes bind make more sense, and less surprising. However it doesn't clarify anything about it no longer being optional.

It would be nice if the following worked, although I it has its own issues with surprises:

let x: Int? = 123
if x != nil {
   ... // x is non-optional here
}
assert(x != nil)
// x is non-optional here

var y: Int? = 456
while y != nil {
    // y is non-optional here
}
// y is optional here

On Tuesday, 2 February 2016, T.J. Usiyan via swift-evolution <swift-evolution@swift.org <>> wrote:
I don't think that the keyword is silly but this is a good point. I forgot that this application of the `?` postfix exists.

On Mon, Feb 1, 2016 at 2:56 PM, Tyler Cloutier via swift-evolution <swift-evolution@swift.org <>> wrote:
The bind or exists keywords seem sort of silly to me. There is already syntax for binding optionals:

if x? {
  foo(x) // x type narrowed after binding.
}

Tyler

On Feb 1, 2016, at 11:35 AM, Howard Lovatt via swift-evolution <swift-evolution@swift.org <>> wrote:

I like this proposal. I also think that either bind or exists could be the keyword. I would suggest that both forms of syntax should be allowed, e.g.:

    if bind x { /* x is non-nil, unwrapped, and hides original x inside if statement */ }
    if bind x = object.property { /* x is non-nil and unwrapped */ }

On Tuesday, 2 February 2016, Dave via swift-evolution <swift-evolution@swift.org <>> wrote:
I think it’d be _

You could use it to test if the return value is non-nil, but you’d have to revert to “if let x = …” to actually use the results.

I think.

- Dave Sweeris

On Feb 1, 2016, at 11:22, T.J. Usiyan via swift-evolution <swift-evolution@swift.org <>> wrote:

This is interesting. What name is created by

  if bind foo.somethingReturningAnOptional {
      // ???
  }

On Mon, Feb 1, 2016 at 2:18 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <>>wrote:
Joe says "If you all are serious about this, I think you should start a new thread about it."
I think it's worth a serious discussion just so it can be evaluated and either adopted or discarded
and dropped forever. Here goes.

INTRO

The if let x = x {...} and guard let x = x else {...} constructs do something with let (and var) that's
fundamentally different from let (and var) elsewhere in the language. The same keywords are used to conditionally unwrap
and bind an item, not just shadow that item's current value.

Introducing a new bind keyword to indicate unwrapping and binding would disambiguate these uses.

DETAIL DESIGN:

Jacob Bandes-Storch offers two common use-cases. I prefer his "if bind foo" to my original "if bind foo = foo":

  if bind foo {
      // foo is non-optional in here
  }

  somethingAsync { [weak self] in
      guard bind self else { return }
      // ...
  }

JBS's approach offers my original "bind" keyword to unwrap and shadow bind, but also provides a way to
strongly bind a weak reference to self, which (presumably) would allow self semantics in the remaining
lifetime of that scope.

ALTERNATIVE PROPOSALS:

Tino Heth proposes a second use-case one with different semantics. This case, it seems to make an
alias rather than using binding for shadowing:

bind x = a.property.with.a.long.path
print x // 42
print(a.property.with.a.long.path == 42) => true

presumably this means:

x += 1
print(a.property.with.a.long.path) // 43

DISCUSSION

I'm throwing these both out there. I have nothing to really say about Tino's but I do think my and Jacob's
proposal has the advantages of:

* Simplifying an mildly complex and potentially misleading statement
* Creating a deliberate and controlled rather than accidental shadowing style

Have at it.

-- Erica

_______________________________________________
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

--
  -- Howard.

_______________________________________________
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

--
  -- Howard.

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