[swift-evolution] [Pitch] Allow trailing argument labels

Vladimir.S svabox at gmail.com
Thu Feb 23 12:25:41 CST 2017


On 23.02.2017 17:35, Haravikk wrote:
>
>> On 23 Feb 2017, at 12:49, Vladimir.S <svabox at gmail.com
>> <mailto:svabox at gmail.com>> wrote:
>>
>> On 23.02.2017 14:17, Haravikk wrote:
>>>
>>>> On 22 Feb 2017, at 21:25, Patrick Pijnappel <patrickpijnappel at gmail.com
>>>> <mailto:patrickpijnappel at gmail.com>
>>>> <mailto:patrickpijnappel at gmail.com>> wrote:
>>>>
>>>> To summarize, there's one ambiguous case we'd need to resolve:
>>>>
>>>> func foo(_ x: Int, reportingOverflow)
>>>> func foo(_ x: Int, _ reportingOverflow: Bool)
>>>>
>>>> let reportingOverflow = true
>>>> foo(5, reportingOverflow) // Ambiguous
>>>>
>>>> One solution is to make trailing argument labels syntactic sugar for a
>>>> trailing void argument.
>>>> That would allow breaking ambiguity by specifying it explicitly:
>>>>
>>>> foo(5, reportingOverflow: ())
>>>>
>>>> A related issue is the call-site ambiguity for the reader (less of a
>>>> problem if Xcode highlighted argument labels).
>>>
>>> Vladimir suggested that an alternative might be to use a leading colon to
>>
>> There is another alternative I can think of, based on feature that was
>> discussed at some point of time the list: anonymous enums, i.e. when you
>> can declare enum inside function declaration, when such enum has almost
>> no meaning outside of the function call.
>>
>> I.e. something like this:
>>
>> func foo(_ x: Int, with: (.reportingOverflow))
>>
>> foo(10, with:.reportingOverflow)
>>
>> I.e. you can have more than one enum case here if you want:
>> func foo(_ x: Int, with: (.reportingOverflow, .otherFlag))
>> // IIRC, such syntax was discussed:
>> // func foo(_ x: Int, with: (.reportingOverflow | .otherFlag))
>>
>> foo(10, with:.otherFlag)
>>
>> But such anonymous enums were considered as bad idea during the
>> discussion, so…
>
> Yeah, I was one of the ones who liked the idea but it never seemed to get
> much traction unfortunately.

[offtopic]
If I remember correctly, *one* of the objections was about the 
syntax(.one|.two|.three), but currently I think this could be solved 
without '|' characters, just using the comma. Like

func foo(arg: (.one,.two,.three), arg2: Int) {}
...
foo(arg: .two, 10)
...
let opt : (.one,.two,.three) = .one
foo(arg: opt, 10)
..
let opt : (.one,.two,.four) = .one
foo(arg: opt, 10) // ERROR: Anonymous enum is not the same. Expected 
(.one,.two,.three), but have (.one,.two,.four)
...
let opt : (.one,.two,.three) = .two
print(type(of:opt)) // AnonymousEnumOneTwoThree
print(type(of:opt)) //or: enum(.one,.two,.three) //or other variant

Sad that this feature was not supported.
[/offtopic]

>
> Part of the problem though with using enums to select methods is that it's
> not immediately obvious what they're doing; if you look at the signature
> for a method you see a type, then have to investigate what it is and find
> it only has one case, which is confusing. Documentation then needs to fill
> in all the gaps to explain that it will only ever have one case (e.g- it's
> not an enum that may be expanded with more options in future), and that's
> it's for selecting methods. A single-case ad-hoc enum could be a bit
> clearer, but it's still more of a workaround.
>
> I think having a proper language feature is still the way to go, as it can
> be more obvious at the function declaration that it's something different,
> since it would be an untyped parameter.
>
> You mentioned another possibility of putting the extra label after the
> function, and I've been thinking about that as well, because the
> interesting thing about that is it could be thought of as a kind of label
> on the return type.
>
> func adding(_ other:Self) -> Self
> func adding(_ other:Self):reportingOverflow -> (Self, Bool)
>
> let resultOnly = a.adding(b)
> let resultReportingOverflow = a.adding(b):reportingOverflow
>
> You did say it looks a bit like an operation on the result, but I suppose
> another way of thinking about it is that until you set (or omit)
> :reportingOverflow then you're actually calling *both* methods with two
> possible results, and by adding that you tell Swift which one you want. It
> could be a very neat thing to use as well within modern auto-complete; type
> out the method at which point you can either hit space to move onto
> something else, hit period to call a method on the result, or hit colon to
> narrow down the result to something more specific.
>
> Ack, I think I'm confusing myself now as to which solution I prefer. Having
> the trailing label *after* the function call does have merits as well.

Weird idea, why not have function name just after arguments block, without 
any separator:

func adding(_ other:Self) -> Self
func adding(_ other:Self)reportingOverflow -> (Self, Bool)

let resultOnly = a.adding(b)
let resultReportingOverflow = a.adding(b)reportingOverflow

Also we should think about referenses to such function:
adding(_:) // ok
addint(_::reportingOverflow) // is it clear that we have 1 argument and 
reportingOverflow is a part of the function name?
or we should use in this case
addint(_:reportingOverflow) //?
addint(_:)reportingOverflow // seems like very clear

But again, I *do* believe such syntax improvements will not be approved by 
core team(and most likely by the community). Is it worth to discuss this?


More information about the swift-evolution mailing list