@noescape and nil


(Aleksandar Petrovic) #1

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?

Alex


(Jordan Rose) #2

No one’s brought it up yet, but it seems totally reasonable. I’d even consider this a bug fix, not a real language change, but I’m not a core team member.

Jordan

···

On Apr 26, 2016, at 00:15, Aleksandar Petrovic via swift-evolution <swift-evolution@swift.org> wrote:

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?

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


(Chris Lattner) #3

There are two ways to fix this: a horrible hack that special cases optionals, or the more principled solution that treats optional as the underlying enum type that it is, and making @noescape propagate through to the members of the .some case.

You can probably guess this, but I’d prefer to discuss fixing the full generality of the problem, not providing a special case in the compiler for this.

-Chris

···

On Apr 26, 2016, at 12:15 AM, Aleksandar Petrovic via swift-evolution <swift-evolution@swift.org> wrote:

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?


(Alex Hoppen) #4

I think this is a bug similar to this one: https://bugs.swift.org/browse/SR-317. Would you mind filing a bug report for it on bugs.swift.org <http://bugs.swift.org/>?

– Another Alex

···

On 26 Apr 2016, at 09:15, Aleksandar Petrovic via swift-evolution <swift-evolution@swift.org> wrote:

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?

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


(Daniel Duan) #5

Wouldn't this work in Swift 3 though?

func testFunc(times: Int, fn: (@noescape (Int)->Void)? = nil) { … }

···

Sent from my iPad

On Apr 26, 2016, at 11:26 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 26, 2016, at 12:15 AM, Aleksandar Petrovic via swift-evolution <swift-evolution@swift.org> wrote:

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?

There are two ways to fix this: a horrible hack that special cases optionals, or the more principled solution that treats optional as the underlying enum type that it is, and making @noescape propagate through to the members of the .some case.

You can probably guess this, but I’d prefer to discuss fixing the full generality of the problem, not providing a special case in the compiler for this.

-Chris

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


(Jordan Rose) #6

Making @noescape work for an arbitrary type doesn’t make sense because we don’t know what that type uses its generic parameter for. The reason we can do it for Optional is because Optional is essentially just a wrapper around T, and the only reason it’s interesting is because we allow an implicit conversion from a closure literal to an optional function type. Anything else would require the closure to explicitly be passed to an initializer or other function to make the types line up, which would clearly not be considered noescape.

We could consider extending this to all enums, but clearly not all structs. I think it’s perfectly reasonable to do this just for Optional.

Jordan

···

On Apr 26, 2016, at 11:26, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 26, 2016, at 12:15 AM, Aleksandar Petrovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?

There are two ways to fix this: a horrible hack that special cases optionals, or the more principled solution that treats optional as the underlying enum type that it is, and making @noescape propagate through to the members of the .some case.

You can probably guess this, but I’d prefer to discuss fixing the full generality of the problem, not providing a special case in the compiler for this.


(Chris Lattner) #7

Wouldn't this work in Swift 3 though?

func testFunc(times: Int, fn: (@noescape (Int)->Void)? = nil) { … }

Yes, that got implemented in Swift 3, with a narrow Optional-specific hack :-)

-Chris

···

On Apr 26, 2016, at 6:58 PM, Daniel Duan <daniel@duan.org> wrote:

Sent from my iPad

On Apr 26, 2016, at 11:26 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 26, 2016, at 12:15 AM, Aleksandar Petrovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi Swift community, I have a question.

This is a valid Swift code:

func testFunc(times: Int, fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

And this is not:

func testFunc(times: Int, @noescape fn: ((Int)->Void)? = nil) {
  guard let f = fn else { return }
  for i in 1 ..< times {
    f(i)
  }
}

I can't think of any hard reason why the @noescape parameter of the function can't be nullable (and, with default value, be optional), but maybe I'm missing something. Is there any plan to correct this in 3.0?

There are two ways to fix this: a horrible hack that special cases optionals, or the more principled solution that treats optional as the underlying enum type that it is, and making @noescape propagate through to the members of the .some case.

You can probably guess this, but I’d prefer to discuss fixing the full generality of the problem, not providing a special case in the compiler for this.

-Chris

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