[Pre-proposal] Fix function type grammar


(Anton Zhilin) #1

You can view proposed function type grammar here:
https://gist.github.com/Anton3/9992aa565ff9d230dd4655b1b74a3326

Notion of tuple was removed; instead, parentheses are now merely part of
function type grammar.

An important implication is that types () -> T and ( () ) -> T become
completely different: the first accepts no parameters, and the second
accepts a single parameter of type ().

===copy of gist begins===
function-type → ( function-type-parameters opt ) throws-annotation opt ->
type

function-type-parameters → function-type-parameter , function-type-
parameters

function-type-parameters → function-type-parameter ...opt

function-type-parameter → attributes opt inout opt type

throws-annotation → throws | rethrows


(Chris Lattner) #2

You can view proposed function type grammar here:
https://gist.github.com/Anton3/9992aa565ff9d230dd4655b1b74a3326

Hi Anton,

This looks correct, but what is the proposal “for”? This seems like it is just encoding what SE-0066 was about.

-Chris

···

On Jul 3, 2016, at 7:28 AM, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

Notion of tuple was removed; instead, parentheses are now merely part of
function type grammar.

An important implication is that types () -> T and ( () ) -> T become
completely different: the first accepts no parameters, and the second
accepts a single parameter of type ().

===copy of gist begins===
function-type → ( function-type-parameters opt ) throws-annotation opt ->
type

function-type-parameters → function-type-parameter , function-type-
parameters

function-type-parameters → function-type-parameter ...opt

function-type-parameter → attributes opt inout opt type

throws-annotation → throws | rethrows
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Anton Zhilin) #3

Chris Lattner via swift-evolution <swift-evolution@...> writes:

Hi Anton,

This looks correct, but what is the proposal “for”? This seems like it

is just encoding what SE-0066 was about.

-Chris

Questions about that proposal are often risen on the list.
Some think that we will still be able to supply () argument
to () -> T functions.

To clear that up completely, I suggest adding this grammar change
to SE-0066 or one of the newer proposals. Key idea is that parentheses
are part of function type grammar and have nothing common with tuples
or unit type.


(Chris Lattner) #4

Sure, that makes sense to me. Please submit a PR that expands on SE-0066 when this settles, I don’t think we need another review cycle. Thank you!

-Chris

···

On Jul 3, 2016, at 9:04 AM, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

Chris Lattner via swift-evolution <swift-evolution@...> writes:

Hi Anton,

This looks correct, but what is the proposal “for”? This seems like it

is just encoding what SE-0066 was about.

-Chris

Questions about that proposal are often risen on the list.
Some think that we will still be able to supply () argument
to () -> T functions.

To clear that up completely, I suggest adding this grammar change
to SE-0066 or one of the newer proposals. Key idea is that parentheses
are part of function type grammar and have nothing common with tuples
or unit type.


(Vladimir) #5

Chris Lattner via swift-evolution <swift-evolution@...> writes:

Hi Anton,

This looks correct, but what is the proposal “for”? This seems like it

is just encoding what SE-0066 was about.

-Chris

Questions about that proposal are often risen on the list.
Some think that we will still be able to supply () argument
to () -> T functions.

To clear that up completely, I suggest adding this grammar change
to SE-0066 or one of the newer proposals. Key idea is that parentheses
are part of function type grammar and have nothing common with tuples
or unit type.

OK.. could you clarify, so, after the changes, we will not be able to pass `func f()->()` as parameter where parameter of type `typealias MyFunc<T> = (T) -> Void` is expected, right?

And what about the result type? What does `-> ()` now will mean? still "implicitly returns Void" or "returns nothing"? Or in case you want to return Void you'll need to write `-> Void` ?

And most likely I'm missing something, but I don't see where SE-0066 mentions this aspect (disallow implicit Void argument in function which is defined as '()->()'), as I understand it is only about requirement of parentheses in declaration like Int->Int. Could you point me please?

···

On 03.07.2016 19:04, Anton Zhilin via swift-evolution wrote:

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


(Anton Zhilin) #6

> Questions about that proposal are often risen on the list.
> Some think that we will still be able to supply () argument
> to () -> T functions.
>
> To clear that up completely, I suggest adding this grammar change
> to SE-0066 or one of the newer proposals. Key idea is that parentheses
> are part of function type grammar and have nothing common with tuples
> or unit type.

Sure, that makes sense to me. Please submit a PR that expands on SE-0066
when this settles, I don’t think we need another review cycle. Thank you!

-Chris

As SE-0110 is now accepted, you may want to take a look at the pull
request: https://github.com/apple/swift-evolution/pull/415


(Anton Zhilin) #7

Vladimir.S via swift-evolution <swift-evolution@...> writes:

OK.. could you clarify, so, after the changes, we will not be able to

pass

`func f()->()` as parameter where parameter of type `typealias

MyFunc<T> =

(T) -> Void` is expected, right?

Right. But the change is not as dramatic as you suppose.
Consider this example:

func async<T>(with: T, do: (T) -> Void)

async(with: (), do: { ... })

With this change, it will become:

async(with: (), do: { _ in ... })

This is what will change in practise. With enough luck, even the first
version will typecheck.

And what about the result type? What does `-> ()` now will mean? still
"implicitly returns Void" or "returns nothing"? Or in case you want to
return Void you'll need to write `-> Void` ?

Parameter part will become a list of types; result will still be a
single type, including unit type and closure types. So no changes on
this part.

And most likely I'm missing something, but I don't see where SE-0066
mentions this aspect (disallow implicit Void argument in function

which is

defined as '()->()'), as I understand it is only about requirement of
parentheses in declaration like Int->Int. Could you point me please?

Citation:

Allowing this sugar introduces ambiguities in the language that require
special rules to disambiguate. For example:

() -> Int // Takes zero arguments, or one zero-argument parameter?

This syntactic sugar reduces consistency with other parts of the
language, since declarations always require parentheses, and calls
requires parentheses as well.

Finally, while it is straight-forward to remove this in Swift 3 (given
the other migration that will be necessary to move Swift 2 code to Swift
3), removing this after Swift 3 will be much harder since we won't want
to break code then. It is now or never.


(Vladimir) #8

Vladimir.S via swift-evolution <swift-evolution@...> writes:

OK.. could you clarify, so, after the changes, we will not be able to

pass

`func f()->()` as parameter where parameter of type `typealias

MyFunc<T> =

(T) -> Void` is expected, right?

Right. But the change is not as dramatic as you suppose.
Consider this example:

func async<T>(with: T, do: (T) -> Void)

async(with: (), do: { ... })

With this change, it will become:

async(with: (), do: { _ in ... })

This is what will change in practise. With enough luck, even the first
version will typecheck.

If we are separating () and (()) in function call/declaration, then if SE-0110 will be accepted, I believe first should not be allowed for argument defined as (T)->Void.
As I understand, in case you have a code that relies on current syntax/behavior and uses functions(not closures), you'll need a lot of wrappers like `{_ in funcThatWasUsedAsIs()}`

And what about the result type? What does `-> ()` now will mean? still
"implicitly returns Void" or "returns nothing"? Or in case you want to
return Void you'll need to write `-> Void` ?

Parameter part will become a list of types; result will still be a
single type, including unit type and closure types. So no changes on
this part.

Got it. OK, so when reading '()->()' we should now read 'emtpy list of parameters(0 parameters) to Void'. And only `(())->()` as '1 explicit Void argument to Void'.

Btw, in case of 'func f(())->() {}', will call without explicit Void parameter be allowed? I.e. `f()` or only `f(())`?

And most likely I'm missing something, but I don't see where SE-0066
mentions this aspect (disallow implicit Void argument in function

which is

defined as '()->()'), as I understand it is only about requirement of
parentheses in declaration like Int->Int. Could you point me please?

Citation:

Allowing this sugar introduces ambiguities in the language that require
special rules to disambiguate. For example:

() -> Int // Takes zero arguments, or one zero-argument parameter?

Hm.. I do understand exactly this example as ambiguity *in case* we are not require parentheses. But not after.

I.e. in case we can have `Int->Int` it is not clear if in `()->()` there is a zero parameters or explicit `Void` parameter.
After we decided to require parentheses, `()->()` clearly means empty list of parameters.
*But*, I feel like implicit Void parameter for function with empty list of parameters - is an implementation detail which is currently used and changing this will produce much more problems for current code than "Just require parentheses on function types" as stated in the proposal in "Proposed solution and Impact on existing code".

I really feel like I've missed something or don't understand :slight_smile: and this is why only I is warring about this change(disallowing Void parameter for func with empty argument list in declaration)

···

On 03.07.2016 22:56, Anton Zhilin via swift-evolution wrote:

This syntactic sugar reduces consistency with other parts of the
language, since declarations always require parentheses, and calls
requires parentheses as well.

Finally, while it is straight-forward to remove this in Swift 3 (given
the other migration that will be necessary to move Swift 2 code to Swift
3), removing this after Swift 3 will be much harder since we won't want
to break code then. It is now or never.

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


(Vladimir) #9

    > Questions about that proposal are often risen on the list.
    > Some think that we will still be able to supply () argument
    > to () -> T functions.
    >
    > To clear that up completely, I suggest adding this grammar change
    > to SE-0066 or one of the newer proposals. Key idea is that parentheses
    > are part of function type grammar and have nothing common with tuples
    > or unit type.

    Sure, that makes sense to me. Please submit a PR that expands on
    SE-0066 when this settles, I don’t think we need another review cycle.
    Thank you!

    -Chris

As SE-0110 is now accepted, you may want to take a look at the pull
request: https://github.com/apple/swift-evolution/pull/415

1. I still believe that sending () to function declared as 'func foo()' should be discussed separately from both(SE-0066,SE-0110), as was not mentioned explicitly in proposals and can have more impact on current source code than expected in proposals. But it seems no body else care of this, so OK, probably I'm not right, I give up. Let's change this.

2. But *do* believe the SE-0066 proposal should be updated in "Impact on existing code" part to show how code that relies on the feature of sending Void aka () to empty-parameter list function should be changed and how "The migrator will automatically add parentheses to existing code when moving from Swift 2 to Swift 3" in this case. Because right now this section in proposal is just not true.

···

On 07.07.2016 17:29, Anton Zhilin via swift-evolution wrote:

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


(Anton Zhilin) #10

Vladimir.S via swift-evolution <swift-evolution@...> writes:

> Consider this example:
>
> func async<T>(with: T, do: (T) -> Void)
>
> async(with: (), do: { ... })
>
> With this change, it will become:
>
> async(with: (), do: { _ in ... })
>
> This is what will change in practise. With enough luck, even the
> first version will typecheck.

If we are separating () and (()) in function call/declaration, then if
SE-0110 will be accepted, I believe first should not be allowed for
argument defined as (T)->Void.
As I understand, in case you have a code that relies on current
syntax/behavior and uses functions(not closures), you'll need a lot of
wrappers like `{_ in funcThatWasUsedAsIs()}`

Right.
By "luck" I mean if determining closure argument count
from context will finally work as expected. In this case,
closure in the first version will implicitly take 1 parameter,
because 'async' requires it to do so.

Anyway, we will have to write at least {funcThatWasUsedAsIs()}.

Btw, in case of 'func f(())->() {}', will call without explicit Void
parameter be allowed? I.e. `f()` or only `f(())`?

Only `f(())`. By the way, you need a label at function declaration.

*But*, I feel like implicit Void parameter for function with empty
list of parameters - is an implementation detail which is currently
used and changing this will produce much more problems for current
code than "Just require parentheses on function types" as stated in
the proposal in "Proposed solution and Impact on existing code".

Right, there is some impact on existing code that was omitted
in the proposal. And it wasn't considered during review. Awkward.

We could add implicit convertion
() -> T to (U) -> T
I feel that is one constructive way out.

···

On 03.07.2016 22:56, Anton Zhilin via swift-evolution wrote:


(Vladimir) #11

Vladimir.S via swift-evolution <swift-evolution@...> writes:

Consider this example:

func async<T>(with: T, do: (T) -> Void)

async(with: (), do: { ... })

With this change, it will become:

async(with: (), do: { _ in ... })

This is what will change in practise. With enough luck, even the
first version will typecheck.

If we are separating () and (()) in function call/declaration, then if
SE-0110 will be accepted, I believe first should not be allowed for
argument defined as (T)->Void.
As I understand, in case you have a code that relies on current
syntax/behavior and uses functions(not closures), you'll need a lot of
wrappers like `{_ in funcThatWasUsedAsIs()}`

Right.
By "luck" I mean if determining closure argument count
from context will finally work as expected. In this case,
closure in the first version will implicitly take 1 parameter,
because 'async' requires it to do so.

Anyway, we will have to write at least {funcThatWasUsedAsIs()}.

I see. Yes, IMO in this case `{funcThatWasUsedAsIs()}` will be much better.

Btw, in case of 'func f(())->() {}', will call without explicit Void
parameter be allowed? I.e. `f()` or only `f(())`?

Only `f(())`. By the way, you need a label at function declaration.

Oh, yes, of course: 'func f(_:())->() {}'. OK.

*But*, I feel like implicit Void parameter for function with empty
list of parameters - is an implementation detail which is currently
used and changing this will produce much more problems for current
code than "Just require parentheses on function types" as stated in
the proposal in "Proposed solution and Impact on existing code".

Right, there is some impact on existing code that was omitted
in the proposal. And it wasn't considered during review. Awkward.

Probably because some(many?) people (like me) did not understand that this proposal is much bigger than "Just require parentheses on function types", because IMHO the major idea of this proposal was disallow `Int->Int` syntax but not to disallow void parameter for zero parameter functions.

I hope community will provide opinions regarding this issue and about the decision regarding the void parameter to argument-less functions, and if that decision is really expected and was clearly mentioned in the proposal.

Personally I think we need to implement the proposal in all areas except this one and raise new proposal to make all things clear regarding argument-less functions.

We could add implicit convertion
() -> T to (U) -> T
I feel that is one constructive way out.

Could you clarify the suggestion with some details?
Do you suggest, that we can pass ()->T where (U)->T is required?

···

On 04.07.2016 0:36, Anton Zhilin via swift-evolution wrote:

On 03.07.2016 22:56, Anton Zhilin via swift-evolution wrote:

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


(Anton Zhilin) #12

Right, there is some impact on existing code that was omitted

in the proposal. And it wasn't considered during review. Awkward.

Probably because some(many?) people (like me) did not understand that this
proposal is much bigger than "Just require parentheses on function types",
because IMHO the major idea of this proposal was disallow `Int->Int` syntax
but not to disallow void parameter for zero parameter functions.

I hope community will provide opinions regarding this issue and about the
decision regarding the void parameter to argument-less functions, and if
that decision is really expected and was clearly mentioned in the proposal.

Personally I think we need to implement the proposal in all areas except
this one and raise new proposal to make all things clear regarding
argument-less functions.

Formally, we should. But I wonder how often the feature being removed was
used. I personally don't feel like it's that important. As Chris suggested,
it may be enough to clarify it in SE-0066.

We could add implicit convertion

() -> T to (U) -> T
I feel that is one constructive way out.

Could you clarify the suggestion with some details?
Do you suggest, that we can pass ()->T where (U)->T is required?

Yes. By the way, Austin Zheng seems to disagree with this.

···

2016-07-04 1:18 GMT+03:00 Vladimir.S <svabox@gmail.com>:


(Austin Zheng) #13

It's a very weak 'disagree' :). I'm mostly hoping more people will add
feedback and indicate whether they think that conversion is useful to them
or not.

Austin

···

On Sun, Jul 3, 2016 at 5:12 PM, Anton Zhilin via swift-evolution < swift-evolution@swift.org> wrote:

2016-07-04 1:18 GMT+03:00 Vladimir.S <svabox@gmail.com>:

Right, there is some impact on existing code that was omitted

in the proposal. And it wasn't considered during review. Awkward.

Probably because some(many?) people (like me) did not understand that
this proposal is much bigger than "Just require parentheses on function
types", because IMHO the major idea of this proposal was disallow
`Int->Int` syntax but not to disallow void parameter for zero parameter
functions.

I hope community will provide opinions regarding this issue and about the
decision regarding the void parameter to argument-less functions, and if
that decision is really expected and was clearly mentioned in the proposal.

Personally I think we need to implement the proposal in all areas except
this one and raise new proposal to make all things clear regarding
argument-less functions.

Formally, we should. But I wonder how often the feature being removed was
used. I personally don't feel like it's that important. As Chris suggested,
it may be enough to clarify it in SE-0066.

We could add implicit convertion

() -> T to (U) -> T
I feel that is one constructive way out.

Could you clarify the suggestion with some details?
Do you suggest, that we can pass ()->T where (U)->T is required?

Yes. By the way, Austin Zheng seems to disagree with this.

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