The bind thread


(Erica Sadun) #1

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


(Jacob Bandes-Storch) #2

I think it's also worth mentioning Ceylon's flow-sensitive typing
<http://ceylon-lang.org/documentation/1.2/introduction/#typesafe_null_and_flow_sensitive_typing>
features, pointed out by Thorsten Seitz:

This is called flow typing in Ceylon and they are using "exists" for that

case but testing for conformance with "is" works just the same way there.
The latter is of importance because the common use of union types in Ceylon.
if exists foo {
        // foo is non-optional here
}
if foo is String {
        // foo is of type String here
}

Seems like a neat option to me.

···

On Mon, Feb 1, 2016 at 11:18 AM, 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


(David Owens II) #3

I disagree. The “if let” and “if var” are part of the pattern matching syntax that is fairly unified throughout the language, especially with the reversal for removing “if var” from Swift. Also, does “bind” also replace the “let” and “var” usage in case statements? And how do you handle this case?

let items: [Int]? = [1, 5, 4]

if var items = items {
    items.sortInPlace()
}

-David

···

On Feb 1, 2016, at 11:18 AM, 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


(Lily Ballard) #4

We've had multiple threads in the past suggesting many different
variants on

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

The only difference with this one is it uses the keyword "bind" instead
of any of the various similar alternatives in the other threads.

And my answer is the same to all of this: This is a bad idea. Your
construct here does not actually include any notion of assignment or
initialization. The construct `if bind foo { ... }` looks like nonsense
to anyone who doesn't already explicitly know that it's shorthand for
`if let foo = foo { ... }`.

If your goal here is to just avoid having to write the `= foo`, then I
disagree with the whole motive. If your goal here is to just use a
keyword `bind` instead of `let` (e.g. if you want to use `if bind foo =
foo { ... }`), I still disagree, because this new keyword serves no
purpose. `if let foo = bar { ... }` is not "fundamentally different"
than `let foo = bar`, it's still binding a new identifier to a value,
the only difference is it binds it to an optional value. And it's
really just a specialization of `if case let foo? = bar { ... }`. I've
asked in the past about whether it's worth keeping the special case
around now that we have `if case let` (or more specifically, if we
should just turn `if let` into the generalized version, so you'd say
`if let foo? = bar {... }`) and the answer from the core team was that
they already tried it internally and found that the usage of optionals
was so prevalent that the special-case optional-specific form of `if
let` was worth keeping.

-Kevin Ballard

···

On Mon, Feb 1, 2016, at 11:18 AM, Erica Sadun via swift-evolution 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


(TJ Usiyan) #5

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


(Brent Royal-Gordon) #6

  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


(Paul Cantrell) #7

Pulling & updating my comments from the old thread:

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.

I don’t agree. Wherever they appear, let and var declare a new variable. And they always shadow variables from an outer scope in exactly the same way:

    let x = "hi"
    if 3 < 7 {
        let x = ["different", "scope", "different", "x"]
        print(x)
    }

This consistency of meaning for let/var gives the correct implication: “if let” is just a normal variable declaration, even though it appears in the middle of an if condition.

The same keywords are used to conditionally unwrap
and bind an item, not just shadow that item's current value.

In my head, it’s “if”, not “let”, that conveys the conditionality. Really, “if” + “let” is exactly the right combination of concepts; the words just come in a grammatically confusing order.

To me, “bind” misleadingly implies that this is something other than a normal variable declaration: maybe an alias, or a reactive binding, or something like that.

Cheers,

Paul

···

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


(David Waite) #8

Meta-comments:

"if let y = x { … } “ actually corresponds closest to

if x != nil {
   let y = x!
   …
}

e.g. has the following behaviors:
1. a comparison to nil
2. a copy of the reference or value w/o optionality
3. execution of a block

but also:
4. implication that this is safe within the block (my eyes would be drawn to that "let y = x!” every time)
5. ability to shadow outer optional variable with non-optional inner variable (e.g. if let x = x { … } )

You could do all of this of course via .flatMap, but there is an obvious desire for something closer to the traditional/familiar syntax of a conditional.

Having a special case of variable assignment within a conditional that casts off optionality feels odd, and I can understand why people have proposed changes. However, the proposals so far seem to have gotten hung up around point #2, having issues with either:

a) making it less clear that a copy is being made,
b) making it less clear that a copy is shadowing the original value, and/or
c) changing the capabilities of the actual statement, such that a copy is *not* being made, and the original value is effectively inout. This means that you are not actually replacing all uses of the syntax at all, but instead defining a new kind of operation.

Issues with a) and b) are syntactic. We can possibly come up with a more clear way to explain the current behavior, although its very hard to make it more clear that a copy is being made than a ‘let’ declaration and assignment.

Issues with c) are mostly just around clarity of purpose - you are defining something new, and "if let x = x” will likely still exist because uses for that operation are still likely valid.

-DW

···

On Feb 1, 2016, at 12: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


(ilya) #9

I respectfully disagree with the need for bind operator, see below:

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.

let A = B does exactly the same in all instances: evaluate the expression B
in current scope and bind the result to a local name A, and if let x =
x meaning
is no different. If a person doesn't know the precise meaning of if let,
with the similarity to normal let one is likely to guess at least the "name
binding" part. This is a big advantage of if let syntax.

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
  }

Let's consider the case where foo was originally a property. Unfortunately,
the syntax above is then very likely to confuse people into thinking that
self.foo is non-optional inside the inner scope, which is far from
guaranteed:

if bind foo {
    // we have created a local variable foo here
    // foo is non-optional
    // no guarantees about self.foo can be made, however
    // as it's value may have changed
}

The same applies if foo is a local variable captured by an escaped closure
which may be executing concurrently with the inner block.

So it seems like the bind statement is most helpful only when foo is a
local name and either declared with let or not captured by any escaped
closure. In that case the original foo can be used directly without
shadowing.

One sees how such a statement can be useful, but I'm not sure if the word
bind is the best one for it. After all, both let and var perform name
binding. Also, there were suggestions to make

// foo is local and not escaping
if foo != nil {
    // foo is non-optional
}

simply work without any additional syntax. Perhaps one can look into that.

  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.

The 'big picture argument' is that shadowing is likely to introduce more
errors, so we should be discouraging it, not encouraging. In real life I
find creating a local variable with a different name more natural anyway,
e.g:

// issuesViewController is a property
// we want to present it, if it can be constructed

if let to_present = issuesViewController {
    presentViewController(to_present, animated: true)
}

Ilya.

-- Erica

···

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

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


(David Sweeris) #10

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 <mailto: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 <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


(Erica Sadun) #11

It would have to be something along the lines of $0 wouldn't it? If there was no clear single symbol to shadow?

That's a very good point, and thank you for bringing it up.

-- Erica

···

On Feb 1, 2016, at 12:22 PM, T.J. Usiyan <griotspeak@gmail.com> 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 <mailto: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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Erica Sadun) #12

Yes, but they don't unwrap. Which is the extra something special.

if let x = x {...}

is kind of really

x.map({f(x)}) // Bless you Kevin!

if you follow what I'm saying. It's not just binding.

-- E

···

On Feb 1, 2016, at 2:52 PM, Paul Cantrell <cantrell@pobox.com> wrote:

Pulling & updating my comments from the old thread:

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

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.

I don’t agree. Wherever they appear, let and var declare a new variable. And they always shadow variables from an outer scope in exactly the same way:

    let x = "hi"
    if 3 < 7 {
        let x = ["different", "scope", "different", "x"]
        print(x)
    }

This consistency of meaning for let/var gives the correct implication: “if let” is just a normal variable declaration, even though it appears in the middle of an if condition.

The same keywords are used to conditionally unwrap
and bind an item, not just shadow that item's current value.

In my head, it’s “if”, not “let”, that conveys the conditionality. Really, “if” + “let” is exactly the right combination of concepts; the words just come in a grammatically confusing order.

To me, “bind” misleadingly implies that this is something other than a normal variable declaration: maybe an alias, or a reactive binding, or something like that.

Cheers,

Paul


(TJ Usiyan) #13

Ok, would that mean that we could use closure syntax to …associate the
value with a name?

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

I think that the question brings me back to my initial thought when reading
this that it is dangerously "close but not quite the same as" the 'other'
meaning of `bind`. I don't thank that the closeness should shut down
discussion of this but I would like to float the name `unwrap` instead.
This makes a near-implementation that is currently possible make more sense.

func unwrap<Wrapped>(wrapped: Wrapped?, handler: Wrapped -> Void) -> Bool

The `Bool` represents whether or not the unwrap was successful and the
`else` flows from that thought without issue. (`bind` works in this regard
as well but becomes, in my opinion, it becomes even more confusing to have
a bind with the suggested signature.)

TJ

···

On Mon, Feb 1, 2016 at 2:27 PM, Erica Sadun <erica@ericasadun.com> wrote:

It would have to be something along the lines of $0 wouldn't it? If there
was no clear single symbol to shadow?

That's a very good point, and thank you for bringing it up.

-- Erica

On Feb 1, 2016, at 12:22 PM, T.J. Usiyan <griotspeak@gmail.com> 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


(Howard Lovatt) #14

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 > <javascript:_e(%7B%7D,'cvml','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 > <javascript:_e(%7B%7D,'cvml','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
<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
<javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
  -- Howard.


(Andrew Bennett) #15

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


(Thorsten Seitz) #16

I respectfully disagree with the need for bind operator, see below:

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.

let A = B does exactly the same in all instances: evaluate the expression B in current scope and bind the result to a local name A, and if let x = x meaning is no different. If a person doesn't know the precise meaning of if let, with the similarity to normal let one is likely to guess at least the "name binding" part. This is a big advantage of if let syntax.

The meaning of `if let x = y` differs from `let x = y` in the type inferred for x (non-optional vs. optional).

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
  }

Let's consider the case where foo was originally a property. Unfortunately, the syntax above is then very likely to confuse people into thinking that self.foo is non-optional inside the inner scope, which is far from guaranteed:

Actually that semantics (I would prefer `exists` to `bind` to make this more explicit in the syntax) is the whole point of flow typing.

if bind foo {
    // we have created a local variable foo here
    // foo is non-optional
    // no guarantees about self.foo can be made, however
    // as it's value may have changed
}

The same applies if foo is a local variable captured by an escaped closure which may be executing concurrently with the inner block.

In Ceylon flow typing is only allowed for constants (i.e. let bindings), probably for that reason, so foo would have to be constant and the problem you mention would not exist.

In Ceylon if `foo` is a variable you have to rebind to a constant which looks like follows (Swiftified, and I’m using `exists` rather than `bind` because I don’t like the latter for the aforementioned reason):

// foo is a var
if exists x = foo {
    // x is a let binding to foo
}

So this is exactly the same as Swift’s current `if let x = foo` except that it makes the unwrapping (or mapping as Erica pointed out) clear and can be used without a (possibly shadowing) assignment for constant values (`if exists x { … }` vs. `if let x = x { … }`).

As I already posted in the original thread `if var` would have to be expressed more clumsily as `if exists x { var copy = x … }` like originally proposed in SE-0003 (that part was recently thankfully revoked). With `exists` there would be no additional shadowing (`if let x = x { let copy = x … } `) so it might be not so bad.

There is a potential advantage of the current `if let` syntax, though: it would allow to be generalized to work for monadic types, i.e. it might just be desugared into `map`.
This could be extended to `for` loops where `for x in foo, y in bar { … }` would be desugared into `flatMap` for all `in` expressions but the last which would be desugared into `map`. In both cases a `where` clause would be desugared into `filter`. For a type to be applicable in `if let` statements it would have to conform to a protocol providing `map`, for support of `where` clauses it would have to conform to another protocol providing `filter` and for being used in `for` statements with nesting it would have to conform to yet another protocol providing `flatMap`.

In that case I’d definitely prefer to stay with the current syntax, because `let` makes more sense in a generalization than `exists` which only applies to optionals.

I think that’s the direction I’d prefer most.

-Thorsten

···

Am 02.02.2016 um 07:44 schrieb ilya via swift-evolution <swift-evolution@swift.org>:
On Mon, Feb 1, 2016 at 8:18 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

So it seems like the bind statement is most helpful only when foo is a local name and either declared with let or not captured by any escaped closure. In that case the original foo can be used directly without shadowing.

One sees how such a statement can be useful, but I'm not sure if the word bind is the best one for it. After all, both let and var perform name binding. Also, there were suggestions to make

// foo is local and not escaping
if foo != nil {
    // foo is non-optional
}

simply work without any additional syntax. Perhaps one can look into that.

  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.

The 'big picture argument' is that shadowing is likely to introduce more errors, so we should be discouraging it, not encouraging. In real life I find creating a local variable with a different name more natural anyway, e.g:

// issuesViewController is a property
// we want to present it, if it can be constructed

if let to_present = issuesViewController {
    presentViewController(to_present, animated: true)
}

Ilya.

-- Erica

_______________________________________________
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


(Tyler Cloutier) #17

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 <mailto: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 <javascript:_e(%7B%7D,'cvml','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 <javascript:_e(%7B%7D,'cvml','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 <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 <javascript:_e(%7B%7D,'cvml','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


(TJ Usiyan) #18

My apologies for the double post but 2.2 (no need for backticks around
'else' as a parameter name) allows a slightly different approach right now
(I am not exactly suggesting that this solves the problem completely, just
seeing what it looks like.)

        func unwrap<Wrapped>(wrapped: Wrapped?, _ unwrapHandler: Wrapped ->
Void, else failureHandler: Void -> Void) {
   switch wrapped {
   case let .Some(value):
       unwrapHandler(value)
   case .None:
       failureHandler()
   }
}

// allows

let theBox:Int? = 4

unwrap(theBox, { print("the value is \($0)") }
   , else: {
   print ("Nothing in the box!")
})

···

On Mon, Feb 1, 2016 at 3:14 PM, T.J. Usiyan <griotspeak@gmail.com> wrote:

Ok, would that mean that we could use closure syntax to …associate the
value with a name?

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

I think that the question brings me back to my initial thought when
reading this that it is dangerously "close but not quite the same as" the
'other' meaning of `bind`. I don't thank that the closeness should shut
down discussion of this but I would like to float the name `unwrap`
instead. This makes a near-implementation that is currently possible make
more sense.

func unwrap<Wrapped>(wrapped: Wrapped?, handler: Wrapped -> Void) -> Bool

The `Bool` represents whether or not the unwrap was successful and the
`else` flows from that thought without issue. (`bind` works in this regard
as well but becomes, in my opinion, it becomes even more confusing to have
a bind with the suggested signature.)

TJ

On Mon, Feb 1, 2016 at 2:27 PM, Erica Sadun <erica@ericasadun.com> wrote:

It would have to be something along the lines of $0 wouldn't it? If there
was no clear single symbol to shadow?

That's a very good point, and thank you for bringing it up.

-- Erica

On Feb 1, 2016, at 12:22 PM, T.J. Usiyan <griotspeak@gmail.com> 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


(TJ Usiyan) #19

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


(TJ Usiyan) #20

I didn't actually try

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

in a swift file and I should have.

To misquote a movie
*That code, you keep using that code. I do not think it does what you think
it does.*

I *do* recall discussion of this syntax and it might have been in an
earlier version, but it does not work now. What I receive is `error:
optional type '_?' cannot be used as a boolean; test for '!= nil' instead`.
I agree with this because that question mark was not, in my opinion, sigil
enough for the action.

···

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