[Pitch] Improving capturing semantics of local functions

adding to the list of options:

6. func fn<T>(param: T) throws -> T where T: Equatable [foo, bar] { … }

otherwise +1 to #1 and to the one in proposal. also see about #4 below.

plus, if 90%+ of use cases in practice would be [weak self] -- (the only
examples shown in the proposals FTM) -- i would strongly consider this
syntax sugar in addition to a generic notation:

weak func fn<T>(param: T) throws -> T where T: Equatable { … }

works with "unowned" as a bonus.

if implement this sugar than some variation of #4 looks appealing to have
these capture things close.

Mike

···

On Mon, 13 Nov 2017 22:30:25 +0100 David Hart <david@hartbit.com> wrote:

On 13 Nov 2017, at 05:52, Slava Pestov <spestov@apple.com> wrote:
>
>> On Nov 12, 2017, at 8:11 PM, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> By analogy with the current closure syntax, the capture list ought to
go somewhere before the parameter list, in one of these slots:
>>
>> 1. func fn<T>[foo, bar](param: T) throws -> T where T: Equatable { … }
>> 2. func fn[foo, bar]<T>(param: T) throws -> T where T: Equatable { … }
>> 3. func [foo, bar] fn<T>(param: T) throws -> T where T: Equatable { …
}
>> 4. [foo, bar] func fn<T>(param: T) throws -> T where T: Equatable { …
}
>>
>> Of these options, I actually think #4 reads best; 1 and 2 are very
cluttered, and 3 just seems weird. But it seems like the one that would be
easiest to misparse.
>
> Another option that reads nicely IMHO is
>
> func fn<T>(param: T) throws -> T where T : Equatable [foo, bar] { … }
>
> I think #4 is ambiguous with array literals unfortunately.

the closer we have it to this English sentence the better IMHO:

weak throwing function "fn", capturing "foo" and "bar" weakly, using
generic type "T" which is "Equatable", having parameter "param" of type
"T", returning type "T", with the following body { ... }

Mike

···

On 14 November 2017 at 19:02, Mike Kluev <mike.kluev@gmail.com> wrote:

On Mon, 13 Nov 2017 22:30:25 +0100 David Hart <david@hartbit.com> wrote:

> On 13 Nov 2017, at 05:52, Slava Pestov <spestov@apple.com> wrote:

>
>> On Nov 12, 2017, at 8:11 PM, Brent Royal-Gordon via swift-evolution < >> swift-evolution@swift.org> wrote:
>>
>> By analogy with the current closure syntax, the capture list ought to
go somewhere before the parameter list, in one of these slots:
>>
>> 1. func fn<T>[foo, bar](param: T) throws -> T where T: Equatable { …
}
>> 2. func fn[foo, bar]<T>(param: T) throws -> T where T: Equatable { …
}
>> 3. func [foo, bar] fn<T>(param: T) throws -> T where T: Equatable {
… }
>> 4. [foo, bar] func fn<T>(param: T) throws -> T where T: Equatable {
… }
>>
>> Of these options, I actually think #4 reads best; 1 and 2 are very
cluttered, and 3 just seems weird. But it seems like the one that would be
easiest to misparse.
>
> Another option that reads nicely IMHO is
>
> func fn<T>(param: T) throws -> T where T : Equatable [foo, bar] { … }
>
> I think #4 is ambiguous with array literals unfortunately.

adding to the list of options:

6. func fn<T>(param: T) throws -> T where T: Equatable [foo, bar] { … }

otherwise +1 to #1 and to the one in proposal. also see about #4 below.

plus, if 90%+ of use cases in practice would be [weak self] -- (the only
examples shown in the proposals FTM) -- i would strongly consider this
syntax sugar in addition to a generic notation:

weak func fn<T>(param: T) throws -> T where T: Equatable { … }

works with "unowned" as a bonus.

if implement this sugar than some variation of #4 looks appealing to have
these capture things close.

>
>>
>> By analogy with the current closure syntax, the capture list ought to
go somewhere before the parameter list, in one of these slots:
>>
>> 1. func fn<T>[foo, bar](param: T) throws -> T where T: Equatable { …
}
>> 2. func fn[foo, bar]<T>(param: T) throws -> T where T: Equatable { …
}
>> 3. func [foo, bar] fn<T>(param: T) throws -> T where T: Equatable {
… }
>> 4. [foo, bar] func fn<T>(param: T) throws -> T where T: Equatable {
… }
>>
>> Of these options, I actually think #4 reads best; 1 and 2 are very
cluttered, and 3 just seems weird. But it seems like the one that would be
easiest to misparse.
>
> Another option that reads nicely IMHO is
>
> func fn<T>(param: T) throws -> T where T : Equatable [foo, bar] { … }
>
> I think #4 is ambiguous with array literals unfortunately.

adding to the list of options:

6. func fn<T>(param: T) throws -> T where T: Equatable [foo, bar] { … }

otherwise +1 to #1 and to the one in proposal. also see about #4 below.

plus, if 90%+ of use cases in practice would be [weak self] -- (the only
examples shown in the proposals FTM) -- i would strongly consider this
syntax sugar in addition to a generic notation:

weak func fn<T>(param: T) throws -> T where T: Equatable { … }

works with "unowned" as a bonus.

weak func to imply [weak self] is a good idea.

weak func foo() {
  self?.bar();
}

unowned func foo() {
  self.bar();
}

Maybe this to:

onChange = weak { self?.bar() }

But we still have the problem using capture list.

And to avoid inconsistencies, I would leave the same way as the proposal.

func local() { [weak self] in
            self?.bar()
        }

There's no perfect solution. And in this works fine today.

···

Em ter, 14 de nov de 2017 às 17:02, Mike Kluev via swift-evolution < swift-evolution@swift.org> escreveu:

On Mon, 13 Nov 2017 22:30:25 +0100 David Hart <david@hartbit.com> wrote:

> On 13 Nov 2017, at 05:52, Slava Pestov <spestov@apple.com> wrote:
>> On Nov 12, 2017, at 8:11 PM, Brent Royal-Gordon via swift-evolution < >> swift-evolution@swift.org> wrote:

if implement this sugar than some variation of #4 looks appealing to have
these capture things close.

Mike

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

this is the closet one (hence +1 to #2):

weak throwing func fn [foo, bar] <T: Equatable> (param: T) -> T {...}

Mike

···

On 14 November 2017 at 19:17, Mike Kluev <mike.kluev@gmail.com> wrote:

On 14 November 2017 at 19:02, Mike Kluev <mike.kluev@gmail.com> wrote:

On Mon, 13 Nov 2017 22:30:25 +0100 David Hart <david@hartbit.com> wrote:

> On 13 Nov 2017, at 05:52, Slava Pestov <spestov@apple.com> wrote:

>
>> On Nov 12, 2017, at 8:11 PM, Brent Royal-Gordon via swift-evolution < >>> swift-evolution@swift.org> wrote:
>>
>> By analogy with the current closure syntax, the capture list ought to
go somewhere before the parameter list, in one of these slots:
>>
>> 1. func fn<T>[foo, bar](param: T) throws -> T where T: Equatable {
… }
>> 2. func fn[foo, bar]<T>(param: T) throws -> T where T: Equatable {
… }
>> 3. func [foo, bar] fn<T>(param: T) throws -> T where T: Equatable {
… }
>> 4. [foo, bar] func fn<T>(param: T) throws -> T where T: Equatable {
… }
>>
>> Of these options, I actually think #4 reads best; 1 and 2 are very
cluttered, and 3 just seems weird. But it seems like the one that would be
easiest to misparse.
>
> Another option that reads nicely IMHO is
>
> func fn<T>(param: T) throws -> T where T : Equatable [foo, bar] { … }
>
> I think #4 is ambiguous with array literals unfortunately.

adding to the list of options:

6. func fn<T>(param: T) throws -> T where T: Equatable [foo, bar] { … }

otherwise +1 to #1 and to the one in proposal. also see about #4 below.

plus, if 90%+ of use cases in practice would be [weak self] -- (the only
examples shown in the proposals FTM) -- i would strongly consider this
syntax sugar in addition to a generic notation:

weak func fn<T>(param: T) throws -> T where T: Equatable { … }

works with "unowned" as a bonus.

if implement this sugar than some variation of #4 looks appealing to have
these capture things close.

the closer we have it to this English sentence the better IMHO:

weak throwing function "fn", capturing "foo" and "bar" weakly, using
generic type "T" which is "Equatable", having parameter "param" of type
"T", returning type "T", with the following body { ... }

>
>>
>> By analogy with the current closure syntax, the capture list ought to go somewhere before the parameter list, in one of these slots:
>>
>> 1. func fn<T>[foo, bar](param: T) throws -> T where T: Equatable { … }
>> 2. func fn[foo, bar]<T>(param: T) throws -> T where T: Equatable { … }
>> 3. func [foo, bar] fn<T>(param: T) throws -> T where T: Equatable { … }
>> 4. [foo, bar] func fn<T>(param: T) throws -> T where T: Equatable { … }
>>
>> Of these options, I actually think #4 reads best; 1 and 2 are very cluttered, and 3 just seems weird. But it seems like the one that would be easiest to misparse.
>
> Another option that reads nicely IMHO is
>
> func fn<T>(param: T) throws -> T where T : Equatable [foo, bar] { … }
>
> I think #4 is ambiguous with array literals unfortunately.

adding to the list of options:

6. func fn<T>(param: T) throws -> T where T: Equatable [foo, bar] { … }

otherwise +1 to #1 and to the one in proposal. also see about #4 below.

plus, if 90%+ of use cases in practice would be [weak self] -- (the only examples shown in the proposals FTM) -- i would strongly consider this syntax sugar in addition to a generic notation:

weak func fn<T>(param: T) throws -> T where T: Equatable { … }

works with "unowned" as a bonus.

weak func to imply [weak self] is a good idea.

I’d be very hesitant to introduce this syntax:

it’s new syntax, so it comes with a complexity tax (it isn’t naturally obvious what it means for a func to be weak)
it’s only sugar for the capture of self
it doesn’t transpose well to local closures

On the other hand, the proposal attempts to resolve the problems mentioned in the Motivation section by introducing as little syntax as possible. And the little it does (capture lists) is no similar to closures that increased complexity tax is fairly low.

···

On 14 Nov 2017, at 20:41, Wallacy <wallacyf@gmail.com> wrote:
Em ter, 14 de nov de 2017 às 17:02, Mike Kluev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> escreveu:
On Mon, 13 Nov 2017 22:30:25 +0100 David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
> On 13 Nov 2017, at 05:52, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:
>> On Nov 12, 2017, at 8:11 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

weak func foo() {
  self?.bar();
}

unowned func foo() {
  self.bar();
}

Maybe this to:

onChange = weak { self?.bar() }

But we still have the problem using capture list.

And to avoid inconsistencies, I would leave the same way as the proposal.

func local() { [weak self] in
            self?.bar()
        }

There's no perfect solution. And in this works fine today.

if implement this sugar than some variation of #4 looks appealing to have these capture things close.

Mike

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

The inference algebra just suggested was enjoyable to read, but is still a
new syntax. Which is interesting and deserving of its own proposal. The
purpose of this proposal is simply to introduce the existing capture syntax
to local functions. Thanks to everyone's feedback pointing out that the
`self` reference analysis is a deeper question than initially realized.

Alex

···

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution < swift-evolution@swift.org> wrote:

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

   - it’s new syntax, so it comes with a complexity tax (it isn’t
   naturally obvious what it means for a func to be weak)
   - it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic"

estimate)... if someone has a quick way to scan and analyse, say, github
swift sources we may even know that current percentage number of real life
usage.

   - it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

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

I’d be very hesitant to introduce this syntax:

   - it’s new syntax, so it comes with a complexity tax (it isn’t
   naturally obvious what it means for a func to be weak)
   - it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic"

estimate)... if someone has a quick way to scan and analyse, say, github
swift sources we may even know that current percentage number of real life
usage.

   - it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

···

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

i did a quick & dirty search on github (queries below). here are some stats:

1) "weak var" - 946K hits

2) "weak self" - 168K hits

3) "weak" - 1127K hits

the summ of "weak var" + "weak self" = 1114K hits

number of "weak" - 1114K = 13K

let's assume this 13K is for weak "something" which is not "self"

number of "weak something" + "weak self" = 181K

"weak self" = 168K / 181K = 93%

"weak something" = 13K / 181K = 7%

the search queries for those interested:

https://github.com/search?utf8=✓&q="weak+var"+filename%3A.swift&type=Code
<https://github.com/search?utf8=✓&q="weak+var"+filename%3A.swift&type=Code>
https://github.com/search?utf8=✓&q="weak+self"+filename%3A.swift&type=Code
<https://github.com/search?utf8=✓&q="weak+self"+filename%3A.swift&type=Code>
https://github.com/search?utf8=✓&q="weak"+filename%3A.swift&type=Code
<https://github.com/search?utf8=✓&q="weak"+filename%3A.swift&type=Code>

note that you have to rerun the search multiple times until it settles
around some number.
also note, you can't easily use [ ] or other punctuation in github builtin
search.

the stat suggests that in 90%+ real-life cases [weak self] is used so the
"weak func" syntax sugar is worth to consider as an addition to this
proposal.

Mike

···

On 14 November 2017 at 21:36, Mike Kluev <mike.kluev@gmail.com> wrote:

it might cover well over 90% of use cases (by my "pessimistic"
estimate)... if someone has a quick way to scan and analyse, say, github
swift sources we may even know that current percentage number of real life
usage.

Having read all the arguments for what to add to local functions it still
strikes me as a poor use of engineering resources to fix them (though I do
agree they have problems). A better use of resources would be:

  1. Deprecate local functions.
  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term
result of better closures which would be much more widely applicable as
well as addressing the issues with local functions.

It also gives a better long term result of not having to maintain local
functions.

  -- Howard.

···

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution < swift-evolution@swift.org> wrote:

The inference algebra just suggested was enjoyable to read, but is still a
new syntax. Which is interesting and deserving of its own proposal. The
purpose of this proposal is simply to introduce the existing capture syntax
to local functions. Thanks to everyone's feedback pointing out that the
`self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution < > swift-evolution@swift.org> wrote:

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

   - it’s new syntax, so it comes with a complexity tax (it isn’t
   naturally obvious what it means for a func to be weak)
   - it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic"

estimate)... if someone has a quick way to scan and analyse, say, github
swift sources we may even know that current percentage number of real life
usage.

   - it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

Having read all the arguments for what to add to local functions it still strikes me as a poor use of engineering resources to fix them (though I do agree they have problems). A better use of resources would be:

  1. Deprecate local functions.
  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term result of better closures which would be much more widely applicable as well as addressing the issues with local functions.

I believe generic closures would require adding higher rank types to Swift. That would be pretty cool but I suspect the engineering effort is at least an order of magnitude greater than the changes discussed in this thread.

···

Sent from my iPhone

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

It also gives a better long term result of not having to maintain local functions.
  
  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution <swift-evolution@swift.org> wrote:
The inference algebra just suggested was enjoyable to read, but is still a new syntax. Which is interesting and deserving of its own proposal. The purpose of this proposal is simply to introduce the existing capture syntax to local functions. Thanks to everyone's feedback pointing out that the `self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution <swift-evolution@swift.org> wrote:

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

it’s new syntax, so it comes with a complexity tax (it isn’t naturally obvious what it means for a func to be weak)
it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic" estimate)... if someone has a quick way to scan and analyse, say, github swift sources we may even know that current percentage number of real life usage.

it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

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

  2. Allow closures when assigned to a function type to be:
      2a. Recursive.

Local functions can also be mutually recursive:

func f() {
  func foo() { bar() }
  func bar() { foo() }
}

This would not work with let bindings, which are not visible before the location where they are defined.

      2b. Annotatable with:
            2bi. @inline

Neither closures nor local functions benefit from being annotated with @_inlineable, because they can only be referenced from inside their defining function, and not across module boundaries. So the optimizer can already inline the function or closure if needed.

            2bii. @escaping
      2c. Generic.

See my other response to this thread.

Slava

···

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

A quick thing I noticed on a first read (sort of tangential to the rest of the discussion) is that it would be a good idea to land warnings for potential reference cycles sooner rather than later.

I have an (un-rebased) branch that lays out what parts of Sema needs to be touched to make this happen and have SR-1807 (https://bugs.swift.org/browse/SR-1807) open for this in general if anybody would like to pick this up and carry it over the goal line. Note that it’s not quite a starter bug.

Otherwise I’ll allocate time to it later on this winter.

~Robert Widmann

2017/11/15 2:01、David Hart via swift-evolution <swift-evolution@swift.org>のメール:

···

On 15 Nov 2017, at 03:56, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

Having read all the arguments for what to add to local functions it still strikes me as a poor use of engineering resources to fix them (though I do agree they have problems). A better use of resources would be:

  1. Deprecate local functions.

Even if I agreed, which I don’t, I’m fairly sure it’s much too late in Swift’s timeline to deprecate something as huge as local functions.

  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term result of better closures which would be much more widely applicable as well as addressing the issues with local functions.

It also gives a better long term result of not having to maintain local functions.
  
  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution <swift-evolution@swift.org> wrote:
The inference algebra just suggested was enjoyable to read, but is still a new syntax. Which is interesting and deserving of its own proposal. The purpose of this proposal is simply to introduce the existing capture syntax to local functions. Thanks to everyone's feedback pointing out that the `self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution <swift-evolution@swift.org> wrote:

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

it’s new syntax, so it comes with a complexity tax (it isn’t naturally obvious what it means for a func to be weak)
it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic" estimate)... if someone has a quick way to scan and analyse, say, github swift sources we may even know that current percentage number of real life usage.

it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

_______________________________________________
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

~Robert Widmann

2017/11/14 22:02、Matthew Johnson via swift-evolution <swift-evolution@swift.org>のメール:

Sent from my iPhone

Having read all the arguments for what to add to local functions it still strikes me as a poor use of engineering resources to fix them (though I do agree they have problems). A better use of resources would be:

  1. Deprecate local functions.
  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term result of better closures which would be much more widely applicable as well as addressing the issues with local functions.

I believe generic closures would require adding higher rank types to Swift. That would be pretty cool but I suspect the engineering effort is at least an order of magnitude greater than the changes discussed in this thread.

100% correct. Slava raises good points about implementation, I’ll raise one about semantics:

Without sufficient restrictions on this kind of polymorphism, type checking will become significantly more difficult for little corresponding benefit. Enabling the formation of polymorphic types just because you’re near an arrow means all sorts of fun things now get to happen

let f = { x in { y in y } }

This program is illegal without a type signature, but still typeable in that Swift will try to look for bindings to the tn’s in this signature

f : <T0, T1> (T0) -> (T1) -> T1

This is good - this is the most general unifier for this expression promised to us by the “Hindley-Milner-like” label we have in the type checker docs.

Given even rank-2 types, the most general unifier is (ideally) now

f : <T0> (T0) -> (<T1> (T1) -> T1)

Which is significant because despite an obvious isomorphism, the former is not a specialization of the latter. It is a completely separate polytype that would require additional structural rules to recover the correct behavior. This can also block inference or generate counterintuitive unifiers if we’re forced to e.g. unify nested polytypes against each other.

~Robert Widmann

···

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

It also gives a better long term result of not having to maintain local functions.
  
  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution <swift-evolution@swift.org> wrote:
The inference algebra just suggested was enjoyable to read, but is still a new syntax. Which is interesting and deserving of its own proposal. The purpose of this proposal is simply to introduce the existing capture syntax to local functions. Thanks to everyone's feedback pointing out that the `self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution <swift-evolution@swift.org> wrote:
On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

it’s new syntax, so it comes with a complexity tax (it isn’t naturally obvious what it means for a func to be weak)
it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic" estimate)... if someone has a quick way to scan and analyse, say, github swift sources we may even know that current percentage number of real life usage.

it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

_______________________________________________
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

Having read all the arguments for what to add to local functions it still strikes me as a poor use of engineering resources to fix them (though I do agree they have problems). A better use of resources would be:

  1. Deprecate local functions.

Even if I agreed, which I don’t, I’m fairly sure it’s much too late in Swift’s timeline to deprecate something as huge as local functions.

···

On 15 Nov 2017, at 03:56, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term result of better closures which would be much more widely applicable as well as addressing the issues with local functions.

It also gives a better long term result of not having to maintain local functions.
  
  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
The inference algebra just suggested was enjoyable to read, but is still a new syntax. Which is interesting and deserving of its own proposal. The purpose of this proposal is simply to introduce the existing capture syntax to local functions. Thanks to everyone's feedback pointing out that the `self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On 14 November 2017 at 21:02, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

I’d be very hesitant to introduce this syntax:

it’s new syntax, so it comes with a complexity tax (it isn’t naturally obvious what it means for a func to be weak)
it’s only sugar for the capture of self
it might cover well over 90% of use cases (by my "pessimistic" estimate)... if someone has a quick way to scan and analyse, say, github swift sources we may even know that current percentage number of real life usage.
it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

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

You can add generic closures with some name mangling and simple
transformations, nothing very hard.

The compiler can emit the following for example:

// User writes
let increment: <T: Numeric>(T) -> T = { $0 + 1 }
increment(1) // 2
increment(1.1) // 2.1

// Compiler issues
struct _Generic_Increment<T: Numeric> { // Mangle name
    let increment: (T) -> T = { $0 + 1 }
}
_Generic_Increment<Int>().increment(1) // 2
_Generic_Increment<Double>().increment(1.1) // 2.1

It's plausible that the compiler can do better than the above, but the
above would be sufficient and is easy to do.

  -- Howard.

···

On 15 November 2017 at 14:02, Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPhone

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

Having read all the arguments for what to add to local functions it still
strikes me as a poor use of engineering resources to fix them (though I do
agree they have problems). A better use of resources would be:

  1. Deprecate local functions.
  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term
result of better closures which would be much more widely applicable as
well as addressing the issues with local functions.

I believe generic closures would require adding higher rank types to
Swift. That would be pretty cool but I suspect the engineering effort is
at least an order of magnitude greater than the changes discussed in this
thread.

It also gives a better long term result of not having to maintain local
functions.

  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution < > swift-evolution@swift.org> wrote:

The inference algebra just suggested was enjoyable to read, but is still
a new syntax. Which is interesting and deserving of its own proposal. The
purpose of this proposal is simply to introduce the existing capture syntax
to local functions. Thanks to everyone's feedback pointing out that the
`self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution < >> swift-evolution@swift.org> wrote:

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

   - it’s new syntax, so it comes with a complexity tax (it isn’t
   naturally obvious what it means for a func to be weak)
   - it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic"

estimate)... if someone has a quick way to scan and analyse, say, github
swift sources we may even know that current percentage number of real life
usage.

   - it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

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

the stat suggests that in 90%+ real-life cases [weak self] is used so the "weak func" syntax sugar is worth to consider as an addition to this proposal.

Slightly OT:
Just thought about making all captures weak by default… I know it’s probably to late for such a change, but I wonder if this was considered when closures were designed

Sorry for the delay in replying - I was called up for jury duty!

For recursive closures the compiler would require two changes; if the
variable is a function type then:

  1. It can reference itself, e.g. `let fact: (Int) -> Int = { $0 < 2 ? 1 :
$0 * fact($0 - 1) }` becomes legal. This is not difficult to do because
`fact` is a pointer and therefore of known size.
  2. When a reference to a function type is made and that function isn't
known, the compiler puts a placeholder in (it knows the size - it is a
pointer) and then comes back and fills in the blank latter (just as it
currently does for functions).

These are not show stoppers, it is what the compiler already does for
functions.

Will respond to generics comments in reply to Robert Widmann email.

  -- Howard.

···

On 15 November 2017 at 17:01, Slava Pestov <spestov@apple.com> wrote:

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

  2. Allow closures when assigned to a function type to be:
      2a. Recursive.

Local functions can also be mutually recursive:

func f() {
  func foo() { bar() }
  func bar() { foo() }
}

This would not work with let bindings, which are not visible before the
location where they are defined.

      2b. Annotatable with:
            2bi. @inline

Neither closures nor local functions benefit from being annotated with
@_inlineable, because they can only be referenced from inside their
defining function, and not across module boundaries. So the optimizer can
already inline the function or closure if needed.

            2bii. @escaping
      2c. Generic.

See my other response to this thread.

Slava

I am not proposing a change to the type system at all. Absolutely no change
whatsoever in any form. I don't know how to say this more clearly.

Therefore your example of:

    let f = { x in { y in y } }

Remains illegal and is treated by the compiler exactly like it is currently
treated and like it currently does results in "error: type of expression is
ambiguous without more context".

Where I am proposing a change is that if a closure with generic arguments
is encountered it is transformed into the equivalent struct and the struct
is typed as it currently is (or if there is a better implementation
something equivalent to this), therefore zero change to the type system.

The changes proposed are a transformation into a struct and name mangling,
e.g.:

    let increment: <T>(T) throws -> T where T: Numeric = { $0 + 1 }
    let increment = { <T>(n: T) throws -> T where T: Numeric in n + 1 }
    let increment: <T>(T) throws -> T where T: Numeric = { <T>(n: T) throws
-> T where T: Numeric in n + 1 }

Are all the same and would therefore all become:

    struct _Function1__T1__T1__T1__E__Numeric<T> where T: Numeric { //
Mangle name
        let call: (T) throws -> T = { $0 + 1 }
    }

Which is a trivial transformation; a simple one to one correspondence.

The hard part is actually mangling the name into a canonical form, I
propose:

  1. If the function type has 1 argument its name begins `_Function1_`, 2
arguments; `_Function2_`, etc.
  2. The 1st generic type is called `_T1_`, 2nd; `_T2_`, etc.
  3. A function that doesn't return anything has a return type of `_V_`.
  4. Other types are their normal name pretended with an underscore, i.e.
`Numeric` becomes `_Numeric` in running example.
  5. The function argument types are then listed in order followed by the
return type, i.e. `_T1__T1_` which follows `_Function1_` in example.
  6. Type constraints are converted to the equivalent where clause, e.g.
`let increment: <T: Numeric>(T) throws -> T` is converted to `let
increment: <T>(T) throws -> T where T: Numeric`.
  7. The where clause is converted to the converted names, e.g. `where T:
Numeric` becomes `where _T1_: _Numeric`.
  8. The where clause is sorted so that constraints on T1 are listed first
etc., e.g. `where _T2_: _Numeric, _T1_: _Numeric` becomes `where _T1_:
_Numeric, _T2_: _Numeric`.
  9. Relationships between types are sorted, e.g. `where _T2_.Element ==
_T1_.Element` becomes `where _T1_.Element == _T2_.Element`.
  10. The `where` keyword and spaces are deleted and `:` becomes `_E_`, `.`
becomes `_D_`, and `,` becomes `_C_`, the final part of the running example
is therefore `_T1__E__Numeric`.

Since the name mangling is the tricky bit this would be the main work to
see if the above scheme is robust.

But wouldn't it be great to have generic closures :).

  -- Howard.

···

On 15 November 2017 at 19:11, Robert Widmann <devteam.codafi@gmail.com> wrote:

~Robert Widmann

2017/11/14 22:02、Matthew Johnson via swift-evolution <
swift-evolution@swift.org>のメール:

Sent from my iPhone

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org> wrote:

Having read all the arguments for what to add to local functions it still
strikes me as a poor use of engineering resources to fix them (though I do
agree they have problems). A better use of resources would be:

  1. Deprecate local functions.
  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term
result of better closures which would be much more widely applicable as
well as addressing the issues with local functions.

I believe generic closures would require adding higher rank types to
Swift. That would be pretty cool but I suspect the engineering effort is
at least an order of magnitude greater than the changes discussed in this
thread.

100% correct. Slava raises good points about implementation, I’ll raise
one about semantics:

Without sufficient restrictions on this kind of polymorphism, type
checking will become significantly more difficult for little corresponding
benefit. Enabling the formation of polymorphic types just because you’re
near an arrow means all sorts of fun things now get to happen

let f = { x in { y in y } }

This program is illegal without a type signature, but still *typeable *in
that Swift will try to look for bindings to the tn’s in this signature

f : <T0, T1> (T0) -> (T1) -> T1

This is good - this is the most general unifier for this expression
promised to us by the “Hindley-Milner-like” label we have in the type
checker docs.

Given even rank-2 types, the most general unifier is (ideally) now

f : <T0> (T0) -> (<T1> (T1) -> T1)

Which is significant because despite an obvious isomorphism, the former is
*not* a specialization of the latter. It is a completely separate
polytype that would require additional structural rules to recover the
correct behavior. This can also block inference or generate
counterintuitive unifiers if we’re forced to e.g. unify nested polytypes
against each other.

~Robert Widmann

It also gives a better long term result of not having to maintain local
functions.

  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution < > swift-evolution@swift.org> wrote:

The inference algebra just suggested was enjoyable to read, but is still
a new syntax. Which is interesting and deserving of its own proposal. The
purpose of this proposal is simply to introduce the existing capture syntax
to local functions. Thanks to everyone's feedback pointing out that the
`self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution < >> swift-evolution@swift.org> wrote:

On 14 November 2017 at 21:02, David Hart <david@hartbit.com> wrote:

I’d be very hesitant to introduce this syntax:

   - it’s new syntax, so it comes with a complexity tax (it isn’t
   naturally obvious what it means for a func to be weak)
   - it’s only sugar for the capture of self

it might cover well over 90% of use cases (by my "pessimistic"

estimate)... if someone has a quick way to scan and analyse, say, github
swift sources we may even know that current percentage number of real life
usage.

   - it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

_______________________________________________
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

You can add generic closures with some name mangling and simple transformations, nothing very hard.

The compiler can emit the following for example:

// User writes
let increment: <T: Numeric>(T) -> T = { $0 + 1 }
increment(1) // 2
increment(1.1) // 2.1

// Compiler issues
struct _Generic_Increment<T: Numeric> { // Mangle name
    let increment: (T) -> T = { $0 + 1 }
}
_Generic_Increment<Int>().increment(1) // 2
_Generic_Increment<Double>().increment(1.1) // 2.1

It's plausible that the compiler can do better than the above, but the above would be sufficient and is easy to do.

There are several problems here:

- You’re adding a new syntax for a typed pattern with a generic parameter list, ‘let foo: <T> …’. Presumably the right hand side of the assignment has to be a closure literal. Also such a literal can only be assigned to a let binding and not passed around as a value, because then you need higher rank types.

- What happens if you use increment as a value without binding generic parameters? Would that be an error? Eg, ‘let increment2 = increment’.

- What about where clauses?

- Right now, nested types cannot capture values from outer scopes, so your proposed lowering would need more work in order to be implemented.

I’m not sure what this buys you over local functions. Local functions have the advantage that they use the same syntax as ordinary functions, whether they are generic or not. Upon first encountering a local function, someone who has never seen a local function before will immediately know what it does. You’re proposing adding some special cases to the grammar to make local functions look more like closures. This seems to be a step backwards.

Slava

···

On Nov 14, 2017, at 7:31 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

  -- Howard.

On 15 November 2017 at 14:02, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPhone

On Nov 14, 2017, at 6:56 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Having read all the arguments for what to add to local functions it still strikes me as a poor use of engineering resources to fix them (though I do agree they have problems). A better use of resources would be:

  1. Deprecate local functions.
  2. Allow closures when assigned to a function type to be:
      2a. Recursive.
      2b. Annotatable with:
            2bi. @inline
            2bii. @escaping
      2c. Generic.

That would be a similar engineering effort and give a better short term result of better closures which would be much more widely applicable as well as addressing the issues with local functions.

I believe generic closures would require adding higher rank types to Swift. That would be pretty cool but I suspect the engineering effort is at least an order of magnitude greater than the changes discussed in this thread.

It also gives a better long term result of not having to maintain local functions.
  
  -- Howard.

On 15 November 2017 at 09:08, Alex Lynch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
The inference algebra just suggested was enjoyable to read, but is still a new syntax. Which is interesting and deserving of its own proposal. The purpose of this proposal is simply to introduce the existing capture syntax to local functions. Thanks to everyone's feedback pointing out that the `self` reference analysis is a deeper question than initially realized.

Alex

On Tue, Nov 14, 2017 at 4:36 PM, Mike Kluev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On 14 November 2017 at 21:02, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

I’d be very hesitant to introduce this syntax:

it’s new syntax, so it comes with a complexity tax (it isn’t naturally obvious what it means for a func to be weak)
it’s only sugar for the capture of self
it might cover well over 90% of use cases (by my "pessimistic" estimate)... if someone has a quick way to scan and analyse, say, github swift sources we may even know that current percentage number of real life usage.
it doesn’t transpose well to local closures

the last one - maybe not. follow me:

let closure = { [weak self, bar] in ... }

which today can be written as:

let closure = { [weak self, bar] () -> Int in ... } // full form

or as:

let closure: () -> Int = { [weak self, bar] in ... } // full form

which allows this change:

let closure: [weak self, bar] () -> Int = { ... } // full alt form

or in alternative form:

let closure: weak () -> Int = { [bar] in ... } // short hand form

same can be with functions:

func fn() -> Int { [weak self, bar] in ... } // full form

weak func fn() -> Int { [bar] in ... } // short hand form

the two capture attributes will in practice be "close" to each other:

weak func fn() {
    [bar] in
    ....
}

and in majority of cases there will be only weak self:

weak func fn() {
    ....
}

Mike

_______________________________________________
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

_______________________________________________
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

the stat suggests that in 90%+ real-life cases [weak self] is used so the "weak func" syntax sugar is worth to consider as an addition to this proposal.

Slightly OT:
Just thought about making all captures weak by default… I know it’s probably to late for such a change, but I wonder if this was considered when closures were designed

Remember that only references can be captured weakly, not value types, even if those value types contain reference members… so this might end up being more confusing than necessary.

Slava

···

On Nov 16, 2017, at 2:56 PM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

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