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

Joe Groff jgroff at apple.com
Fri Apr 15 16:47:41 CDT 2016


> On Apr 15, 2016, at 11:43 AM, John McCall <rjmccall at apple.com> wrote:
> 
>> On Apr 15, 2016, at 10:41 AM, Joe Groff <jgroff at apple.com> wrote:
>>> On Apr 15, 2016, at 8:29 AM, John McCall via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>>> On Apr 14, 2016, at 10:50 PM, Chris Lattner <clattner at apple.com> wrote:
>>>> On Apr 14, 2016, at 10:40 PM, John McCall <rjmccall at 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.
>> 
>> 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.
> 
> I don't see this syntax as an offshoot of the "functions always have one argument" model.  I agree that that model is dead.
> 
> However, I don't think users require its death to be underlined and written in bold; it only ever surfaced to them in bugs anyway.  But many functions do, nonetheless, have only one argument; and because of another change to the model, where argument labels are becoming part of the function's name and not its type, that argument can be written as just a type.
> 
> So to me, this question is whether we add a weird special-case rule that mandates the use of parentheses because they're required in a bunch of more complex but less common situations.
> 
>> 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.
> 
> This is tautological.

I don't think it is just a tautology. Without encoding it in the grammar, there's an ambiguity between tuples and multiple arguments; () -> T could mean either "takes a single () argument" or "takes no arguments". We could "obviously" disambiguate in favor of the latter interpretation, but then you're introducing special cases in the other direction to keep the U -> T syntax working.

-Joe


More information about the swift-evolution mailing list