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

Apart from intuition and confusion, parentheses are used at call sites
and declarations. It seems out of line that they can be removed in types
but only in one degenerate case.

This goes against the Swift core design goal of consistency.

-- E

···

On Apr 18, 2016, at 4:31 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

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.

I think () reads nicer than Void, and has a sort of beauty that () literally looks like nothing, unlike some word. The fact that you can nest it is trippy in a kind of cool way.

Patrick Smith
      
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 Apr 19 2016, at 11:28 pm, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

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

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

I think () reads nicer than Void, and has a sort of beauty that ()
literally looks like nothing, unlike some word. The fact that you can nest
it is trippy in a kind of cool way.

In this case, why do we need Void at all in function type definition, and wider - in language ? And why do we need these ((())) as allowed parameters definition for functions?

Probably it is OK for me to have only () without Void, i.e.:
f: ()->()

But not all of these strange constructions like (((Void)))

Opinions?

···

On 19.04.2016 17:11, Patrick Smith via swift-evolution wrote:

*Patrick Smith*
*
On Apr 19 2016, at 11:28 pm, Vladimir.S via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

+1 can we get rid of void?

···

On Apr 19, 2016, at 7:11 AM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

I think () reads nicer than Void, and has a sort of beauty that () literally looks like nothing, unlike some word.

In this particular case I belive

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

is much more explicit and clear about what is what :

foo(int: Int) returns not Int(that returns then String and then String).

foo(int: Int) return function with (Int) parameter, that return func with (String) parameter that returns single String value.

···

On 20.04.2016 20:53, Chris Lattner via swift-evolution wrote:

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)

No, it becomes:

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

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

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?

Because, as I tried to explain in my original post, parameters *are* a special case. The result type of a function is just a type. The parameter list allows things that types do not: default arguments and variadics.

As a concrete example, surely you aren’t arguing that we should support:

  let x : Int… -> Int

are you?

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?

Uhm, yes, we already do. In:

  let x : (a : Int) -> Float
  let y : (Int) -> Float
  let z : Int -> Float

x and y have different (but compatible) types. y and z have identical types (sugared differently).

-Chris

···

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

I could’ve sworn I saw “getting rid of special-case syntax” as a general goal somewhere. Maybe I’m thinking of something else.

- Dave Sweeris

···

On Apr 15, 2016, at 12:40 AM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

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

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.

I agree that that is odd. In my opinion, it should be accepted to convert from a function type with labels to one without (or visa-versa), but not from a function type with one set of labels to one with another set. This is a different topic though.

-Chris

···

On Apr 15, 2016, at 5:04 PM, David Owens II <david@owensd.io> wrote:

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.

Here is the proposal:

We can discuss this more when it is scheduled for review.

Thanks all,

-Chris

···

On Apr 16, 2016, at 8:48 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 16, 2016, at 10:10 AM, Patrick Gili <gili.patrick.r@gili-labs.com> 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).

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

For the sake of consistency, would you also support the requirement of `-> Void` on functions that return nothing? There are a few different ways to declare function signatures, one of which requires the return type, the other can default one for, in the "degenerate case".

Example:

typealias Callback = () -> Void // return type required
let f: () -> Void = {} // return type required

func g() {} // return type optional
func h() -> Void {} // should this be required?

I think it's clear from this example, that consistency is not always the most important thing.

-David

···

On Apr 19, 2016, at 7:49 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 18, 2016, at 4:31 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

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.

Apart from intuition and confusion, parentheses are used at call sites
and declarations. It seems out of line that they can be removed in types
but only in one degenerate case.

This goes against the Swift core design goal of consistency.

For what it’s worth, I searched my Swift code and didn’t find a single instance where I did *not* use the parens - even for single-argument functions. Until this conversation came up, I don’t recall if it ever even occurred to me that I *could* leave the parentheses out!

l8r
Sean

···

On Apr 19, 2016, at 9:49 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 18, 2016, at 4:31 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

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

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.

Apart from intuition and confusion, parentheses are used at call sites
and declarations. It seems out of line that they can be removed in types
but only in one degenerate case.

This goes against the Swift core design goal of consistency.

-- E

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

I’d place the ability to omit parenthesises for single args in the same category as being able to omit `self` when accessing properties. They are small conveniences that make a large difference to an entire codebase.

···

On 19 Apr 2016, at 15:49, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Apart from intuition and confusion, parentheses are used at call sites
and declarations. It seems out of line that they can be removed in types
but only in one degenerate case.

This goes against the Swift core design goal of consistency.

-- E

Parameters also support different API vs internal parameter labels as well.

-Chris

···

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

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

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?

Because, as I tried to explain in my original post, parameters *are* a special case. The result type of a function is just a type. The parameter list allows things that types do not: default arguments and variadics.

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?

Because, as I tried to explain in my original post, parameters *are* a special case. The result type of a function is just a type. The parameter list allows things that types do not: default arguments and variadics.

Default arguments are not allowed in the type grammar. Nor are different internal vs. external labels.

As a concrete example, surely you aren’t arguing that we should support:

  let x : Int… -> Int

are you?

No, but that's because the ... is a reference to the rest of the tuple and doesn't read correctly outside of one.

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?

Uhm, yes, we already do. In:

  let x : (a : Int) -> Float
  let y : (Int) -> Float
  let z : Int -> Float

x and y have different (but compatible) types. y and z have identical types (sugared differently).

When I said "function type", I was referring to this production in the type grammar, not the type signature component of function declarations. I'm not sure how I could've been clearer on that without actually using the names of grammatical productions.

My point was that allowing a function type to be written as "(Int) -> Float" is already inconsistent with function declarations, because that is not legal function declaration syntax; you would have to write "(_ : Int) -> Float".

The current language composes naturally here, and your proposal feels like an odd extra rule.

John.

···

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

I’d place the ability to omit parenthesises for single args in the same category
as being able to omit `self` when accessing properties. They are small
conveniences that make a large difference to an entire codebase.

Care to back that up with some measurements? Take one of your projects
and find the instances of “[^) ] *->”

How many places in the code are affected, and how much worse is the result?

···

on Tue Apr 19 2016, Alan Skipp <swift-evolution@swift.org> wrote:

    On 19 Apr 2016, at 15:49, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote:

    Apart from intuition and confusion, parentheses are used at call sites
    and declarations. It seems out of line that they can be removed in types
    but only in one degenerate case.

    This goes against the Swift core design goal of consistency.

    -- E

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

--
Dave

> I’d place the ability to omit parenthesises for single args in the same
category
> as being able to omit `self` when accessing properties. They are small
> conveniences that make a large difference to an entire codebase.

Care to back that up with some measurements? Take one of your projects
and find the instances of “[^) ] *->”

How many places in the code are affected, and how much worse is the result?

Here's one data point: including a small handful of false positives, I
found 74 results in a project with 33 Swift files.

"How much worse" is hard to answer. It certainly wouldn't be the worst
thing in the world to add parens, but I'm not particularly compelled by the
pro-() arguments in this thread.

Jacob

···

On Tue, Apr 19, 2016 at 3:29 PM, Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

on Tue Apr 19 2016, Alan Skipp <swift-evolution@swift.org> wrote:

> On 19 Apr 2016, at 15:49, Erica Sadun via swift-evolution > > <swift-evolution@swift.org> wrote:
>
> Apart from intuition and confusion, parentheses are used at call
sites
> and declarations. It seems out of line that they can be removed in
types
> but only in one degenerate case.
>
> This goes against the Swift core design goal of consistency.
>
> -- E
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
Dave

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

Would this also affect the syntax for naming closure arguments? For example, would this (taken from "The Swift Programming Language (Swift 2.2)”):
  reversed = names.sort( { s1, s2 in return s1 > s2 } )
have to be written like this:
  reversed = names.sort( { (s1, s2) in return s1 > s2 } )
or is that a different syntax?

As a developer focused on _writing_ and _reading_ code like this, I don’t see the real benefits of this change. It only feels natural to me that I would be able to omit the parentheses when there is only one type, but that I would need them to group multiple arguments or to label arguments.

That said, I don’t feel strongly about it and the work of transitioning our code would be minimal. If this change provides other engineering benefits that aren’t noticeable on the surface, then I’m positive to the change for those reasons.

- David

···

On 19 Apr 2016, at 16:59, Sean Heber via swift-evolution <swift-evolution@swift.org> wrote:

For what it’s worth, I searched my Swift code and didn’t find a single instance where I did *not* use the parens - even for single-argument functions. Until this conversation came up, I don’t recall if it ever even occurred to me that I *could* leave the parentheses out!

l8r
Sean

On Apr 19, 2016, at 9:49 AM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 18, 2016, at 4:31 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

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

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.

Apart from intuition and confusion, parentheses are used at call sites
and declarations. It seems out of line that they can be removed in types
but only in one degenerate case.

This goes against the Swift core design goal of consistency.

-- E

_______________________________________________
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

Well said!

-Thorsten

···

Am 19.04.2016 um 18:01 schrieb Alan Skipp via swift-evolution <swift-evolution@swift.org>:

I’d place the ability to omit parenthesises for single args in the same category as being able to omit `self` when accessing properties. They are small conveniences that make a large difference to an entire codebase.

On 19 Apr 2016, at 15:49, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Apart from intuition and confusion, parentheses are used at call sites
and declarations. It seems out of line that they can be removed in types
but only in one degenerate case.

This goes against the Swift core design goal of consistency.

-- E

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

A quick grep showed about 50 cases of using T1 -> T2 in my current project. Not a huge amount, but not tiny either. It wouldn’t be a completely dreadful change to make, just irritating having to add superfluous syntactical appendages to pacify the computer.

···

On 20 Apr 2016, at 00:28, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, Apr 19, 2016 at 3:29 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

on Tue Apr 19 2016, Alan Skipp <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> I’d place the ability to omit parenthesises for single args in the same category
> as being able to omit `self` when accessing properties. They are small
> conveniences that make a large difference to an entire codebase.

Care to back that up with some measurements? Take one of your projects
and find the instances of “[^) ] *->”

How many places in the code are affected, and how much worse is the result?

Here's one data point: including a small handful of false positives, I found 74 results in a project with 33 Swift files.

"How much worse" is hard to answer. It certainly wouldn't be the worst thing in the world to add parens, but I'm not particularly compelled by the pro-() arguments in this thread.

Jacob

I feel like the current language no longer represents our reality, though (or at least, our current ideal vision for reality). We've pretty thoroughly broken the "functions have one argument" model. Changing the type grammar to reflect this seems good to me. I would think of it as changing the function type grammar to:

  function-type ::= '(' (type (',' type)*)? ')' '->' type

which, since the argument list can containing 0, 1, or many individual arguments, makes the parens more grammatically necessary.

-Joe

···

On Apr 15, 2016, at 8:29 AM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

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

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?

Because, as I tried to explain in my original post, parameters *are* a special case. The result type of a function is just a type. The parameter list allows things that types do not: default arguments and variadics.

Default arguments are not allowed in the type grammar. Nor are different internal vs. external labels.

As a concrete example, surely you aren’t arguing that we should support:

  let x : Int… -> Int

are you?

No, but that's because the ... is a reference to the rest of the tuple and doesn't read correctly outside of one.

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?

Uhm, yes, we already do. In:

  let x : (a : Int) -> Float
  let y : (Int) -> Float
  let z : Int -> Float

x and y have different (but compatible) types. y and z have identical types (sugared differently).

When I said "function type", I was referring to this production in the type grammar, not the type signature component of function declarations. I'm not sure how I could've been clearer on that without actually using the names of grammatical productions.

My point was that allowing a function type to be written as "(Int) -> Float" is already inconsistent with function declarations, because that is not legal function declaration syntax; you would have to write "(_ : Int) -> Float".

The current language composes naturally here, and your proposal feels like an odd extra rule.