[pitch] Eliminate the "T1 -> T2" syntax, require "(T1) -> T2"

Hmm... I don't think this is clearer:

    let fn: (Int) -> (Int) -> Int

I think it's much less readable and really, the () are syntactically redundant: the -> is really what distinguishes this as a function.

Also, this would look like a error now:

    let fn: (Int) -> ()

Did the user mean that it returns nothing, or did they forget the rest of the function signature?

Hi David,

I’m not sure what you’re saying here. The two types above are already valid, and this proposal doesn’t affect that.

-Chris

···

On Apr 15, 2016, at 11:27 AM, David Owens II <david@owensd.io> wrote:

I'd like to see more consistency and less redundancy, including special cases, in the language in general, but this change just seems to make it different in another way, but still not consistent throughout the language constructs.

-David

On Apr 14, 2016, at 9:57 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

+1 to the proposal

If the original rationale is gone, shouldn’t we also get rid of the empty tuple-type and replace it by a full-blown Void instead of Void being a typealis for the empty tuple?

(Int) -> Float
(String) -> Void
() -> Void
() -> Double

It looks more consistent to me.

Not sure about whether I’m a +1 to this; although I use Void everywhere already, I kind of get the rationale behind it being a zero element tuple, as single return types are basically one element tuples, and you can return tuples of any size you like.

Also, as an aside, I kind of liked that all functions took a tuple as their sole argument; I only use variadic parameters where they’re required for literal conformance (and I’ve no idea how else you’d handle that), but I suppose that ship has sailed.

···

On 15 Apr 2016, at 13:11, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

So, `Void->Int` functions would work like this?
let foo = bar(()) // returns Int

···

On Apr 15, 2016, at 3:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

What I think we *should* eliminate, however, is using `Void` to mean "no arguments" in a closure type. `Void -> Int` should mean that the type takes one argument which happens to be an empty tuple. If you want no arguments, write `() -> Int`.

As an alternative, could we require the parens on the return. For example:

(Int) -> (Float)
(String) -> ()
() -> ()
() -> (Double)

This looks cleaner, improves consistency, and simplifies the syntax (i.e., no need to remember when parens are necessary).

-Patrick

···

On Apr 15, 2016, at 1:38 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 15, 2016, at 5:11 AM, David Hart <david@hartbit.com> wrote:

If the original rationale is gone, shouldn’t we also get rid of the empty tuple-type and replace it by a full-blown Void instead of Void being a typealis for the empty tuple?

This could be done, but it would make the language larger and less consistent. It would require introducing a new concept (a first class Void type). Further, at some point we may have the ability to define algorithms over arbitrary width tuples (e.g. perhaps like C++ variadic templates) and that benefits from having the empty tuple as a base case.

-Chris

(Int) -> Float
(String) -> Void
() -> Void
() -> Double

It looks more consistent to me.

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

Given all this, I think it makes sense to go for syntactic
uniformity between parameter list and function types, and just
require parenthesis on the argument list. The types above can be
trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

While it's technically correct, I agree with John's assessment that
this is "fussy". `T -> U` doesn't confuse people

Do we have any data on this (in either direction)?

Personally, it has always seemed obvious that T -> U being a function
type would be quite novel to some people, considering the number of
times I've seen in Haskell texts that (surprise!) you don't need
parentheses to invoke functions. I guess those are invocations and
we're talking about declarations here, but declaration-follows-use is a
kind of principle the language tries to uphold.

But that's just intuition. Data would be very interesting.

···

on Fri Apr 15 2016, Brent Royal-Gordon <swift-evolution@swift.org> wrote:

and doesn't confuse the compiler; removing it would require extra
punctuation for no particular reason. It would also become
inconsistent with the paren-less `{ param in … }` syntax, which I
think is very important for keeping usage sites simple and clean.

What I think we *should* eliminate, however, is using `Void` to mean
"no arguments" in a closure type. `Void -> Int` should mean that the
type takes one argument which happens to be an empty tuple. If you
want no arguments, write `() -> Int`. Similarly, a typedef for a
2-tuple (like `Dictionary.Element`) should be recognized as one tuple
parameter, not two singleton parameters. With that in place, `T -> U`
becomes merely a convenient shorthand for the canonical form, `(T) ->
U`.

I mean, it's not that big a deal; if you remove it, everyone will type
extra parentheses and live with it. But recognize that doing so would
improve the language, not the end-user experience.

--
Dave

+1

I am against introducing more parentheses because the resulting code is much more unreadable IMO (those additional parentheses will typically appear in argument lists, which means that the additional parentheses will be nested in the parentheses of the argument list). As someone else said, the arrow already clearly marks this as a function type and clearly separates argument from result type. Adding parentheses is just adding punctuation noise.

-Thorsten

···

Am 15.04.2016 um 22:23 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org>:

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

While it's technically correct, I agree with John's assessment that this is "fussy". `T -> U` doesn't confuse people and doesn't confuse the compiler; removing it would require extra punctuation for no particular reason. It would also become inconsistent with the paren-less `{ param in … }` syntax, which I think is very important for keeping usage sites simple and clean.

What I think we *should* eliminate, however, is using `Void` to mean "no arguments" in a closure type. `Void -> Int` should mean that the type takes one argument which happens to be an empty tuple. If you want no arguments, write `() -> Int`. Similarly, a typedef for a 2-tuple (like `Dictionary.Element`) should be recognized as one tuple parameter, not two singleton parameters. With that in place, `T -> U` becomes merely a convenient shorthand for the canonical form, `(T) -> U`.

I mean, it's not that big a deal; if you remove it, everyone will type extra parentheses and live with it. But recognize that doing so would improve the language, not the end-user experience.

--
Brent Royal-Gordon
Architechies

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

Noooooo :(

I understand and appreciate the rationale, uniformity between declaration and use site being a good thing, but IMHO the proposal just brings unnecessary noise, far outweighing the small benefit of having the symmetry.

1. What I’m worried the most is the “parentheses blindness”. In higher-order functions, or just when I take a simple callback closure, there are just a lot of parentheses (add to that generics, and there’s a lot of angled brackets too). And it just becomes hard to instantly decipher. To me, `func blah(f: Int -> Float) -> String` is easier to read that `func blah(f: (Int) -> Float) -> String`. Or just notice how noisy `(f: () -> ())` is. This is why I like the convention of using `Void` for void-returning functions. There’s less noise in `(f: () -> Void)`, and even better in `(f: Int -> Void)`. I don’t have to mentally match parentheses, because whenever possible, there’s just one set of parens around the main function declaration. When punctuation like parentheses is used sparingly, it carries a lot of weight. Requiring parentheses around T in T -> U doesn’t seem to have a significant reason aside from style/taste.

2. I’m not convinced at all that `(Foo) -> Bar` is immediately more obvious to people. I don’t have data to back it up, but my intuition is that `Foo -> Bar` is simple and understandable. “A function from Foo to Bar”, I’m thinking. I don’t have to mentally parse the vacuous parentheses, just to conclude that there’s, in fact, just one parameter. And when there is more than one parameter, the parentheses in `(Foo, Bar) -> Baz` instantly carry more weight.

3. Swift has been really good at removing unnecessary punctuation. Parentheses in if statements, semicolons, shortcut forms of closures, etc. This is a good thing. As I said before, using punctuation only when it matters makes it stand out, and in places where it doesn’t, by removing it we’re increasing the signal-to-noise ratio. To me, parentheses in `(Foo) -> Bar` don’t matter. I can see why one could argue for them, or prefer them, but it seems like a merely stylistic choice. Let’s keep them where it matters, and leave this to personal preference.

Thanks for posting this Radek. I agree with everything you said.

···

Sent from my iPad

On Apr 19, 2016, at 2:46 AM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

Best,
— Radek

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

-1

The parenthesis don't add anything, in my opinion. I could live with the
change, I simply don't see much benefit.

···

On Tue, Apr 19, 2016 at 8:45 AM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPad

> On Apr 19, 2016, at 2:46 AM, Radosław Pietruszewski via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Noooooo :(
>
> I understand and appreciate the rationale, uniformity between
declaration and use site being a good thing, but IMHO the proposal just
brings unnecessary noise, far outweighing the small benefit of having the
symmetry.
>
> 1. What I’m worried the most is the “parentheses blindness”. In
higher-order functions, or just when I take a simple callback closure,
there are just a lot of parentheses (add to that generics, and there’s a
lot of angled brackets too). And it just becomes hard to instantly
decipher. To me, `func blah(f: Int -> Float) -> String` is easier to read
that `func blah(f: (Int) -> Float) -> String`. Or just notice how noisy
`(f: () -> ())` is. This is why I like the convention of using `Void` for
void-returning functions. There’s less noise in `(f: () -> Void)`, and even
better in `(f: Int -> Void)`. I don’t have to mentally match parentheses,
because whenever possible, there’s just one set of parens around the main
function declaration. When punctuation like parentheses is used sparingly,
it carries a lot of weight. Requiring parentheses around T in T -> U
doesn’t seem to have a significant reason aside from style/taste.
>
> 2. I’m not convinced at all that `(Foo) -> Bar` is immediately more
obvious to people. I don’t have data to back it up, but my intuition is
that `Foo -> Bar` is simple and understandable. “A function from Foo to
Bar”, I’m thinking. I don’t have to mentally parse the vacuous parentheses,
just to conclude that there’s, in fact, just one parameter. And when there
is more than one parameter, the parentheses in `(Foo, Bar) -> Baz`
instantly carry more weight.
>
> 3. Swift has been really good at removing unnecessary punctuation.
Parentheses in if statements, semicolons, shortcut forms of closures, etc.
This is a good thing. As I said before, using punctuation only when it
matters makes it stand out, and in places where it doesn’t, by removing it
we’re increasing the signal-to-noise ratio. To me, parentheses in `(Foo) ->
Bar` don’t matter. I can see why one could argue for them, or prefer them,
but it seems like a merely stylistic choice. Let’s keep them where it
matters, and leave this to personal preference.

Thanks for posting this Radek. I agree with everything you said.

>
> Best,
> — Radek
>
>> On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> We currently accept function type syntax without parentheses, like:
>>
>> Int -> Float
>> String -> ()
>>
>> etc. The original rationale aligned with the fact that we wanted to
treat all functions as taking a single parameter (which was often of tuple
type) and producing a tuple value (which was sometimes a tuple, in the case
of void and multiple return values). However, we’ve long since moved on
from that early design point: there are a number of things that you can
only do in a parameter list now (varargs, default args, etc), implicit
tuple splat has been removed, and the compiler has long ago stopped
modeling function parameters this way. Beyond that, it eliminates one
potential style war.
>>
>> Given all this, I think it makes sense to go for syntactic uniformity
between parameter list and function types, and just require parenthesis on
the argument list. The types above can be trivially written as:
>>
>> (Int) -> Float
>> (String) -> ()
>>
>> Thoughts?
>>
>> -Chris
>> _______________________________________________
>> 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

+1 to everything Radek said

-Thorsten

···

Am 19.04.2016 um 09:46 schrieb Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org>:

Noooooo :(

I understand and appreciate the rationale, uniformity between declaration and use site being a good thing, but IMHO the proposal just brings unnecessary noise, far outweighing the small benefit of having the symmetry.

1. What I’m worried the most is the “parentheses blindness”. In higher-order functions, or just when I take a simple callback closure, there are just a lot of parentheses (add to that generics, and there’s a lot of angled brackets too). And it just becomes hard to instantly decipher. To me, `func blah(f: Int -> Float) -> String` is easier to read that `func blah(f: (Int) -> Float) -> String`. Or just notice how noisy `(f: () -> ())` is. This is why I like the convention of using `Void` for void-returning functions. There’s less noise in `(f: () -> Void)`, and even better in `(f: Int -> Void)`. I don’t have to mentally match parentheses, because whenever possible, there’s just one set of parens around the main function declaration. When punctuation like parentheses is used sparingly, it carries a lot of weight. Requiring parentheses around T in T -> U doesn’t seem to have a significant reason aside from style/taste.

2. I’m not convinced at all that `(Foo) -> Bar` is immediately more obvious to people. I don’t have data to back it up, but my intuition is that `Foo -> Bar` is simple and understandable. “A function from Foo to Bar”, I’m thinking. I don’t have to mentally parse the vacuous parentheses, just to conclude that there’s, in fact, just one parameter. And when there is more than one parameter, the parentheses in `(Foo, Bar) -> Baz` instantly carry more weight.

3. Swift has been really good at removing unnecessary punctuation. Parentheses in if statements, semicolons, shortcut forms of closures, etc. This is a good thing. As I said before, using punctuation only when it matters makes it stand out, and in places where it doesn’t, by removing it we’re increasing the signal-to-noise ratio. To me, parentheses in `(Foo) -> Bar` don’t matter. I can see why one could argue for them, or prefer them, but it seems like a merely stylistic choice. Let’s keep them where it matters, and leave this to personal preference.

Best,
— Radek

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

Completely agree with Radek. I avoid unnecessary punctuation whenever possible, which increases legibility IMHO; so this pernickety proposal makes me sad : (

···

On 19 Apr 2016, at 08:46, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

Noooooo :(

I understand and appreciate the rationale, uniformity between declaration and use site being a good thing, but IMHO the proposal just brings unnecessary noise, far outweighing the small benefit of having the symmetry.

1. What I’m worried the most is the “parentheses blindness”. In higher-order functions, or just when I take a simple callback closure, there are just a lot of parentheses (add to that generics, and there’s a lot of angled brackets too). And it just becomes hard to instantly decipher. To me, `func blah(f: Int -> Float) -> String` is easier to read that `func blah(f: (Int) -> Float) -> String`. Or just notice how noisy `(f: () -> ())` is. This is why I like the convention of using `Void` for void-returning functions. There’s less noise in `(f: () -> Void)`, and even better in `(f: Int -> Void)`. I don’t have to mentally match parentheses, because whenever possible, there’s just one set of parens around the main function declaration. When punctuation like parentheses is used sparingly, it carries a lot of weight. Requiring parentheses around T in T -> U doesn’t seem to have a significant reason aside from style/taste.

2. I’m not convinced at all that `(Foo) -> Bar` is immediately more obvious to people. I don’t have data to back it up, but my intuition is that `Foo -> Bar` is simple and understandable. “A function from Foo to Bar”, I’m thinking. I don’t have to mentally parse the vacuous parentheses, just to conclude that there’s, in fact, just one parameter. And when there is more than one parameter, the parentheses in `(Foo, Bar) -> Baz` instantly carry more weight.

3. Swift has been really good at removing unnecessary punctuation. Parentheses in if statements, semicolons, shortcut forms of closures, etc. This is a good thing. As I said before, using punctuation only when it matters makes it stand out, and in places where it doesn’t, by removing it we’re increasing the signal-to-noise ratio. To me, parentheses in `(Foo) -> Bar` don’t matter. I can see why one could argue for them, or prefer them, but it seems like a merely stylistic choice. Let’s keep them where it matters, and leave this to personal preference.

Best,
— Radek

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

Although I personally have no strong opinion on this proposal yet,
it is clear for me that something is wrong with function type sintax&Void&().

Right now we have such situation, when all the next code is OK, can be compiled and run, but each fX has the same meaning:

typealias f1 = () -> ()
typealias f2 = () -> Void
typealias f3 = () -> (Void)
typealias f4 = () -> (())
typealias f5 = () -> ((((((()))))))

typealias f6 = Void -> ()
typealias f7 = Void -> Void
typealias f8 = Void -> (Void)
typealias f9 = Void -> (())
typealias f10 = Void -> ((((((()))))))

typealias f11 = (Void) -> ()
typealias f12 = ((((((())))))) -> Void
typealias f13 = (()) -> ((Void))
typealias f14 = ((())) -> (())
typealias f15 = ((Void)) -> ((((((()))))))

func f() -> Void {

}

let fv1 : f1 = f
let fv2 : f2 = f
let fv3 : f3 = f
let fv4 : f4 = f
let fv5 : f5 = f
let fv6 : f6 = f
let fv7 : f7 = f
let fv8 : f8 = f
let fv9 : f9 = f
let fv10 : f10 = f
let fv11 : f11 = f
let fv12 : f12 = f
let fv13 : f13 = f
let fv14 : f14 = f
let fv15 : f15 = f

Don't you think something is wrong with this?
Let's discuss ?

Personally I probably prefer to replace "()" with Void as a result of function, and probably replace Void with "()" as parameters part. And don't allow empty-tuple-in-tuple at least for function type declaration + don't allow Void-in-tuple. I.e. in this case we'll have only this as alowed declaration:

typealias ftype = () -> Void

IMO the only clear, explicit, often used variant.

···

On 19.04.2016 10:46, Radosław Pietruszewski via swift-evolution wrote:

Noooooo :(

I understand and appreciate the rationale, uniformity between declaration and use site being a good thing, but IMHO the proposal just brings unnecessary noise, far outweighing the small benefit of having the symmetry.

1. What I’m worried the most is the “parentheses blindness”. In higher-order functions, or just when I take a simple callback closure, there are just a lot of parentheses (add to that generics, and there’s a lot of angled brackets too). And it just becomes hard to instantly decipher. To me, `func blah(f: Int -> Float) -> String` is easier to read that `func blah(f: (Int) -> Float) -> String`. Or just notice how noisy `(f: () -> ())` is. This is why I like the convention of using `Void` for void-returning functions. There’s less noise in `(f: () -> Void)`, and even better in `(f: Int -> Void)`. I don’t have to mentally match parentheses, because whenever possible, there’s just one set of parens around the main function declaration. When punctuation like parentheses is used sparingly, it carries a lot of weight. Requiring parentheses around T in T -> U doesn’t seem to have a significant reason aside from style/taste.

2. I’m not convinced at all that `(Foo) -> Bar` is immediately more obvious to people. I don’t have data to back it up, but my intuition is that `Foo -> Bar` is simple and understandable. “A function from Foo to Bar”, I’m thinking. I don’t have to mentally parse the vacuous parentheses, just to conclude that there’s, in fact, just one parameter. And when there is more than one parameter, the parentheses in `(Foo, Bar) -> Baz` instantly carry more weight.

3. Swift has been really good at removing unnecessary punctuation. Parentheses in if statements, semicolons, shortcut forms of closures, etc. This is a good thing. As I said before, using punctuation only when it matters makes it stand out, and in places where it doesn’t, by removing it we’re increasing the signal-to-noise ratio. To me, parentheses in `(Foo) -> Bar` don’t matter. I can see why one could argue for them, or prefer them, but it seems like a merely stylistic choice. Let’s keep them where it matters, and leave this to personal preference.

Best,
— Radek

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

No, it becomes:

func foo(int: Int) -> (Int) -> (String) -> String

-Chris

···

On Apr 20, 2016, at 8:46 AM, BJ Homer <bjhomer@gmail.com> wrote:

How would this proposal affect curried functions? Would this:

func foo(int: Int) -> Int -> String -> String

become this?

func foo(int: Int) -> (((Int) -> String) -> String)

To the best of my understanding, either:

func foo(i: Int) -> (j: Int) -> (s: String) -> String { ... }
let x = foo // let x: (Int) -> (j: Int) -> (s: String) -> String
let a = x(2); let b = a(j: 3); let c = b(s: "glob"); print(c)

or

func blort(i: Int) -> (Int) -> (String) -> String
let z = blort // let z: (Int) -> (Int) -> (String) -> String
let aa = z(2); let bb = aa(3); let cc = bb("glob"); print(cc)

would still work (although x(2) would become x(i: 2) because of the new first label rules) vs the following which currently works but would not after adoption:

func bar(i: Int) -> Int -> String -> String { ... }
let y = bar // let y: (Int) -> Int -> String -> String

-- E, who is often wrong

···

On Apr 20, 2016, at 9:46 AM, BJ Homer via swift-evolution <swift-evolution@swift.org> wrote:

How would this proposal affect curried functions? Would this:

func foo(int: Int) -> Int -> String -> String

become this?

func foo(int: Int) -> (((Int) -> String) -> String)

As I understand, that transformation is an accurate representation of the actual return type of “foo”, but it’s certainly going to raise some complaints among the functional Swift community if required.

-BJ

Yes, I already did:

It isn’t currently scheduled, but when it comes up, we can have more discussion about it.

-Chris

···

On Apr 22, 2016, at 4:05 PM, Vladimir.S <svabox@gmail.com> wrote:

After some discussions, I support this proposal and think this will make Swift more consistent and clear about where is parameters and where is result type. Especially this important in code like:
Int -> String -> Void -> Float
which IMO should be
(Int) -> (String) -> (Void) -> Float
as Int/String/Void are parameters, Float is result type.

But IMO not just "require parenthesis on the argument list", but also disallow parenthesis in result type in meaning of tuple of single argument(as we discussed in this thread with @Anton), disallow placing () in (), disallow Void in () in result - to prevent all these ((((())))) (((Void))) etc in parameters and in result type.

@Chris, would you form a proposal for this subject?

We currently accept function type syntax without parentheses, like:

To me, the unparenthesized style suggests that the input and output are peers, which feels more natural for the sort of value-to-value transform/predicate where this most commonly occurs. Parenthesizing the input feels fussier, which contributes to a sense that the argument is just one component to producing the result.
The parentheses are grammatically unnecessary in most cases (by frequency of use in higher-use programming, not by feature count).

I agree with your point that many simple higher order programming examples (e.g. map, filter, etc) take a single argument. That said, I don’t agree that this means that we should syntactically privilege this special case.

"Special case" is a loaded phrase. Why is it a special case as a parameter if it isn't a special case as a result?

In many places in the Swift grammar we aim for consistency, even if it means a bit more punctuation in specific cases.

This is not greatly in evidence. We have a lot of special-case syntax.

Our grammar generally allows grammatically-unnecessary parentheses to be omitted (except the C-style for loop, until we killed it) — I guess you could count function call syntax, but we had strong reasons there that don't seem to apply here. We notably chose to deviate from C statement grammar specifically to allow unnecessary parentheses to be omitted. This would feel weirdly inconsistent with that.

We allow parens to be omitted from control flow expressions, where they are redundant with paren exprs. I don’t see how that translates to our type grammar.

The grammatical and semantic purpose of parentheses is identical in both grammars.

I guess the flip side is that call and declaration syntax both require parentheses (unless the only argument is a trailing closure), but again, we had strong justifications for that: declarations would always be ambiguous without parens, and calls would have serious problems (and the style-wars factor would be much larger, especially now with mandatory keyword arguments by default).

Right, but regardless of *why* we always require parens on Decls and ApplyExprs, we really do (and that isn’t going to change). Being consistent between func decls and function types is quite important IMO.

So we should require function argument labels in function types?

John.

···

On Apr 14, 2016, at 10:28 PM, Chris Lattner <clattner@apple.com> wrote:
On Apr 14, 2016, at 10:21 PM, John McCall <rjmccall@apple.com> wrote:

On Apr 14, 2016, at 9:57 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

So, `Void->Int` functions would work like this?
let foo = bar(()) // returns Int

Yes.

···

--
Brent Royal-Gordon
Architechies

At the core, I guess it’s just a dislike of the different behaviors for function declarations in the system in general. Your propose just exposes a weirdness with empty parameter lists and the typealias for void: ().

It’s a bit odd that the () mean different things depending on the side of the “->” they are on. The left side is an empty parameter list, the right side is a void type.

Now, I get your argument is to get rid of the difference between:

    let f: Int -> ()
    let g: (Int, Int) -> ()

I guess I’m more of the opinion of David Hart, this change should also remove the typealias for () being void.

    let f: (Int) -> Void
    let g: (Int, Int) -> Void

Overall, I think the change is ok, but doesn’t really add any significant clarity to function declarations. I feel like there are already a lot of weirdness in general around them.

See:

typealias Functor = (to: Int, from: Int) -> Int
let g: (hi: Int, bye: Int) -> Int = { $0 - $1 }

func sum(x: Int, y: Int) -> Int {
    return x + y
}

func mult(x: Int, y: Int) -> Int {
    return x * y
}

func f(n: Int, _ m: Int, _ c: Functor) -> Int {
    return c(to: n, from: m)
}

f(1, 2, sum) // output: 3
f(1, 2, mult) // output: 2
f(1, 2, g) // output: -1

It’s weird to me that we can essentially erase the parameter names and fallback to just the type signatures, but that can be a talk for another day.

-David

···

On Apr 15, 2016, at 1:07 PM, Chris Lattner <clattner@apple.com> wrote:

On Apr 15, 2016, at 11:27 AM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

Hmm... I don't think this is clearer:

    let fn: (Int) -> (Int) -> Int

I think it's much less readable and really, the () are syntactically redundant: the -> is really what distinguishes this as a function.

Also, this would look like a error now:

    let fn: (Int) -> ()

Did the user mean that it returns nothing, or did they forget the rest of the function signature?

Hi David,

I’m not sure what you’re saying here. The two types above are already valid, and this proposal doesn’t affect that.

-Chris

I’m not sure it’s “cleaner” per se, but I agree with the rest. My earlier +1 may have been premature…

- Dave Sweeris

···

On Apr 16, 2016, at 12:10 PM, Patrick Gili via swift-evolution <swift-evolution@swift.org> wrote:

As an alternative, could we require the parens on the return. For example:

(Int) -> (Float)
(String) -> ()
() -> ()
() -> (Double)

This looks cleaner, improves consistency, and simplifies the syntax (i.e., no need to remember when parens are necessary).

-Patrick

As an alternative, could we require the parens on the return. For example:

(Int) -> (Float)
(String) -> ()
() -> ()
() -> (Double)

This looks cleaner, improves consistency, and simplifies the syntax (i.e., no need to remember when parens are necessary).

-1 from me. And the rationale that I provided for this pitch doesn’t support it: unlike arguments, return types really are just types, they don’t align with other syntactic productions that have magic argument behavior.

I’ll write up a formal proposal for more discussion.

-Chris

···

On Apr 16, 2016, at 10:10 AM, Patrick Gili <gili.patrick.r@gili-labs.com> wrote:

-Patrick

On Apr 15, 2016, at 1:38 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 15, 2016, at 5:11 AM, David Hart <david@hartbit.com> wrote:

If the original rationale is gone, shouldn’t we also get rid of the empty tuple-type and replace it by a full-blown Void instead of Void being a typealis for the empty tuple?

This could be done, but it would make the language larger and less consistent. It would require introducing a new concept (a first class Void type). Further, at some point we may have the ability to define algorithms over arbitrary width tuples (e.g. perhaps like C++ variadic templates) and that benefits from having the empty tuple as a base case.

-Chris

(Int) -> Float
(String) -> Void
() -> Void
() -> Double

It looks more consistent to me.

On 15 Apr 2016, at 06:57, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

Int -> Float
String -> ()

etc. The original rationale aligned with the fact that we wanted to treat all functions as taking a single parameter (which was often of tuple type) and producing a tuple value (which was sometimes a tuple, in the case of void and multiple return values). However, we’ve long since moved on from that early design point: there are a number of things that you can only do in a parameter list now (varargs, default args, etc), implicit tuple splat has been removed, and the compiler has long ago stopped modeling function parameters this way. Beyond that, it eliminates one potential style war.

Given all this, I think it makes sense to go for syntactic uniformity between parameter list and function types, and just require parenthesis on the argument list. The types above can be trivially written as:

(Int) -> Float
(String) -> ()

Thoughts?

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

And, FWIW, the standard library higher-order functions are all declared
with parens around the argument list, because it is a more recognizable
form.

···

on Thu Apr 14 2016, Chris Lattner <swift-evolution@swift.org> wrote:

On Apr 14, 2016, at 10:21 PM, John McCall <rjmccall@apple.com> wrote:

On Apr 14, 2016, at 9:57 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

We currently accept function type syntax without parentheses, like:

To me, the unparenthesized style suggests that the input and output
are peers, which feels more natural for the sort of value-to-value
transform/predicate where this most commonly occurs. Parenthesizing
the input feels fussier, which contributes to a sense that the
argument is just one component to producing the result.
The parentheses are grammatically unnecessary in most cases (by frequency of use in higher-use programming, not by feature count).

I agree with your point that many simple higher order programming
examples (e.g. map, filter, etc) take a single argument. That said, I
don’t agree that this means that we should syntactically privilege
this special case. In many places in the Swift grammar we aim for
consistency, even if it means a bit more punctuation in specific
cases.

--
Dave