[Pitch] Allow trailing argument labels


(Patrick Pijnappel) #1

I'd like to discuss allowing a trailing 'argument label' without an actual
argument:

func adding(_ other: Self, reportingOverflow) -> … // Actual case in SE-104
where this came up
func tableView(_ tableView: UITableView, numberOfSections) -> Int //
Referenced as tableView(_:numberOfSections)

As illustrated above, the way we reference functions extends very naturally
to include these.

This would be very useful for several cases:
• Delegate methods, which currently all start with the same prefix, except
for some odd cases that really actually just needed a trailing argument
label.
• Cases where the function is a more specialized version of one with the
same name, but can't use a flag because the return type is different (e.g.
reportingOverflow), or the extra flag check is just undesirable. The
standard library now uses some workarounds to achieve this (e.g. having a
trailing argument of type void).
• Function names that just work more naturally with some additional words
after the last argument. If we allow trailing argument labels, you can form
any sentence, rounding out the syntax.

Overall, I think this could be the final missing piece to complete Swift's
functions-as-sentences approach.


(Brent Royal-Gordon) #2

I think it would be really weird to support not one, but *two* potentially ambiguous sugar forms.

···

On Feb 22, 2017, at 3:32 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

  foo.example(foo) // What did I mean here?
  let result = foo.example(foo:) // This looks like I might be trying to select a function, rather than call it

--
Brent Royal-Gordon
Architechies


(Ross O'Brien) #3

I'd like to see this, particularly in initialisers. Objective C can have '-
(instanceType) init' and '- (instanceType) initWithQualifier', where Swift
can only have 'init()'.

···

On Wed, Feb 22, 2017 at 10:24 AM, Patrick Pijnappel via swift-evolution < swift-evolution@swift.org> wrote:

I'd like to discuss allowing a trailing 'argument label' without an actual
argument:

func adding(_ other: Self, reportingOverflow) -> … // Actual case in
SE-104 where this came up
func tableView(_ tableView: UITableView, numberOfSections) -> Int //
Referenced as tableView(_:numberOfSections)

As illustrated above, the way we reference functions extends very
naturally to include these.

This would be very useful for several cases:
• Delegate methods, which currently all start with the same prefix, except
for some odd cases that really actually just needed a trailing argument
label.
• Cases where the function is a more specialized version of one with the
same name, but can't use a flag because the return type is different (e.g.
reportingOverflow), or the extra flag check is just undesirable. The
standard library now uses some workarounds to achieve this (e.g. having a
trailing argument of type void).
• Function names that just work more naturally with some additional words
after the last argument. If we allow trailing argument labels, you can form
any sentence, rounding out the syntax.

Overall, I think this could be the final missing piece to complete Swift's
functions-as-sentences approach.

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


(Haravikk) #4

I'm a +1 for this.

I think the best way to define it though would be to use Void arguments, and simply eliminate the need to add :() to call them if they are trailing. We should however retain the ability to add the colon for disambiguation.

Some examples to illustrate:

  struct Foo { func adding(_ other:Foo, reportingOverflow:Void) { … } }
  var a = Foo(), b = Foo()

  a.adding(b, reportingOverflow) // Trailing Void argument doesn't require a value, so :() can be omitted

  let reportingOverflow = "I don't know why I defined this"
  a.adding(b, reportingOverflow) // This is now ambiguous thanks to my stupidly named variable
  a.adding(b, reportingOverflow:) // However, this isn't, thanks to the colon clarifying that it's a label

It's possible the feature doesn't have to be restricted to only trailing arguments; the key is the ambiguity due to variable names and/or function selection. For example:

  struct Foo { func example(foo:Void) -> String { … }}
  var foo = Foo()

  foo.example(foo) // What did I mean here?
  let result = foo.example(foo:) // This looks like I might be trying to select a function, rather than call it

So it's possible it could be allowed for any function that has at least one non-Void argument?

I think to really seal the deal it would be nice if Xcode would highlight argument labels differently, as that would make it clearer to user's what something is at a glance, but that's a separate issue.

Just some thoughts; I do prefer this to using single case enums just to create a different method signature. Labels are definitely the right way to do this. The main thing for me is that I think we should keep the requirement to specify the type in the function declaration as Void, just for clarity.

···

On 22 Feb 2017, at 10:24, Patrick Pijnappel via swift-evolution <swift-evolution@swift.org> wrote:

I'd like to discuss allowing a trailing 'argument label' without an actual argument:

func adding(_ other: Self, reportingOverflow) -> … // Actual case in SE-104 where this came up
func tableView(_ tableView: UITableView, numberOfSections) -> Int // Referenced as tableView(_:numberOfSections)

As illustrated above, the way we reference functions extends very naturally to include these.

This would be very useful for several cases:
• Delegate methods, which currently all start with the same prefix, except for some odd cases that really actually just needed a trailing argument label.
• Cases where the function is a more specialized version of one with the same name, but can't use a flag because the return type is different (e.g. reportingOverflow), or the extra flag check is just undesirable. The standard library now uses some workarounds to achieve this (e.g. having a trailing argument of type void).
• Function names that just work more naturally with some additional words after the last argument. If we allow trailing argument labels, you can form any sentence, rounding out the syntax.

Overall, I think this could be the final missing piece to complete Swift's functions-as-sentences approach.


(Haravikk) #5

Those aren't examples I think should be supported, I was thinking out loud. The point I was trying to make is that it's not the trailing nature that's a requirement, but that the real requirement for this feature to work is that there's at least one other, non-Void argument.

On another note, one other alternative I did think of for declaration is that perhaps it might be better still to use an attribute to specify a label-only "argument". Think of it like an attribute on the type, except that it specifies that there is no type:

  func adding(_ other:Self, reportingOverflow:@labelonly) { … }

The attribute makes it absolutely clear that this is just a label and not an actual, functional argument (there won't be a reportingOverflow local variable), and that it can be passed without a value when calling this method. It'll still need the trailing colon for possible disambiguation of variables though.

···

On 22 Feb 2017, at 11:48, Brent Royal-Gordon <brent@architechies.com> wrote:

On Feb 22, 2017, at 3:32 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

  foo.example(foo) // What did I mean here?
  let result = foo.example(foo:) // This looks like I might be trying to select a function, rather than call it

I think it would be really weird to support not one, but *two* potentially ambiguous sugar forms.


(Derrick Ho) #6

I've read the pitch, but it isn't clear what the ask is or what benefit it
would give.

···

On Wed, Feb 22, 2017 at 8:05 AM Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

On 22 Feb 2017, at 11:48, Brent Royal-Gordon <brent@architechies.com> > wrote:

On Feb 22, 2017, at 3:32 AM, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

foo.example(foo) // What did I mean here?
let result = foo.example(foo:) // This looks like I might be trying to
select a function, rather than call it

I think it would be really weird to support not one, but *two* potentially
ambiguous sugar forms.

Those aren't examples I think should be supported, I was thinking out
loud. The point I was trying to make is that it's not the trailing nature
that's a requirement, but that the real requirement for this feature to
work is that there's at least one other, non-Void argument.

On another note, one other alternative I did think of for declaration is
that perhaps it might be better still to use an attribute to specify a
label-only "argument". Think of it like an attribute on the type, except
that it specifies that there is no type:

func adding(_ other:Self, reportingOverflow:@labelonly) { … }

The attribute makes it absolutely clear that this is just a label and not
an actual, functional argument (there won't be a reportingOverflow local
variable), and that it can be passed without a value when calling this
method. It'll still need the trailing colon for possible disambiguation of
variables though.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Haravikk) #7

The purpose of the feature is to enable selection of identically named methods with similar signatures. This came up in the protocol-oriented integers debate on the ability to have arithmetic methods with and without overflow. Like so:

  protocol IntegerArithmetic {
    func adding(_ other:Self) -> Self
    func adding(_ other:Self, reportingOverflow) -> (Self, Bool)
  }

  var a = 2, b = 3
  let resultWithoutOverflow = a.adding(b)
  let resultWithOverflow = a.adding(b, reportingOverflow)

Here we have two different methods, one reporting overflow and one without, using the label to enable selection, rather than having to have an addingWithOverflow() method or similar.

Currently the alternative is to do something like:

  enum ReportingOverflow { case .reportingOverflow }
  protocol IntegerArithmetic {
    func adding(_ other:Self) -> Self
    func adding(_ other:Self, _) -> (Self, Bool)
  }

  var a = 2, b = 3
  let resultWithoutOverflow = a.adding(b)
  let resultWithOverflow = a.adding(b, .reportingOverflow)

Basically the ability to use the label for method selection is an alternative to either defining an enum as above, or having to use a different method name.

···

On 22 Feb 2017, at 13:19, Derrick Ho <wh1pch81n@gmail.com> wrote:

I've read the pitch, but it isn't clear what the ask is or what benefit it would give.


(Vladimir) #8

I've read the pitch, but it isn't clear what the ask is or what benefit
it would give.

The purpose of the feature is to enable selection of identically named
methods with similar signatures. This came up in the protocol-oriented
integers debate on the ability to have arithmetic methods with and without
overflow. Like so:

protocol IntegerArithmetic {
func adding(_ other:Self) -> Self
func adding(_ other:Self, reportingOverflow) -> (Self, Bool)
}

var a = 2, b = 3
let resultWithoutOverflow = a.adding(b)
let resultWithOverflow = a.adding(b, reportingOverflow)

Isn't this very confusing about what 'reportingOverflow' *is*? IMO it looks like reportingOverflow is a variable/property defined in some place and has some value. While "a.adding(b, .reportingOverflow)" is obvious about what .reportingOverflow is, just like separate addingWithReportingOverflow method.

Do I understand correctly, that the proposed solution is some kind of sugar to not have separate method named like 'addingWithReportingOverflow' ?

In any case IMO such argument label should have special syntax on caller site.. don't know, probably:

let resultWithOverflow = a.adding(b, :reportingOverflow)

probably with the same declaration:
func adding(_ other:Self, :reportingOverflow) -> (Self, Bool)

if we keep semicolon *after* such trailing label, then we have the problem :
let x = foo(reportingOverflow:)

was foo called with trailing label 'reportingOverflow' or x is assigned to function foo with one 'real' argument?

···

On 22.02.2017 17:22, Haravikk via swift-evolution wrote:

On 22 Feb 2017, at 13:19, Derrick Ho <wh1pch81n@gmail.com >> <mailto:wh1pch81n@gmail.com>> wrote:

Here we have two different methods, one reporting overflow and one without,
using the label to enable selection, rather than having to have an
addingWithOverflow() method or similar.

Currently the alternative is to do something like:

enum ReportingOverflow { case .reportingOverflow }
protocol IntegerArithmetic {
func adding(_ other:Self) -> Self
func adding(_ other:Self, _) -> (Self, Bool)
}

var a = 2, b = 3
let resultWithoutOverflow = a.adding(b)
let resultWithOverflow = a.adding(b, .reportingOverflow)

Basically the ability to use the label for method selection is an
alternative to either defining an enum as above, or having to use a
different method name.

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


(Haravikk) #9

Do I understand correctly, that the proposed solution is some kind of sugar to not have separate method named like 'addingWithReportingOverflow' ?

Basically yes; the discussion came up briefly during protocol oriented integers where this is quite common, especially with added methods for handling double-width operations and such as well.

In any case IMO such argument label should have special syntax on caller site.. don't know, probably:

let resultWithOverflow = a.adding(b, :reportingOverflow)

probably with the same declaration:
func adding(_ other:Self, :reportingOverflow) -> (Self, Bool)

Huh, that could be a great alternative! It would solve the ambiguity issues completely and allow for even single argument cases (if someone wanted to use those).
Any preferences on how to specify these arguments? e.g- just declare them void, attribute or something else?

Also apologies to Patrick, I seem to be leading his discussion, I really should get some work done! :smile:

···

On 22 Feb 2017, at 15:38, Vladimir.S <svabox@gmail.com <mailto:svabox@gmail.com>> wrote:


(Haravikk) #10

Do I understand correctly, that the proposed solution is some kind of sugar to not have separate method named like 'addingWithReportingOverflow' ?

Basically yes; the discussion came up briefly during protocol oriented integers where this is quite common, especially with added methods for handling double-width operations and such as well.

In any case IMO such argument label should have special syntax on caller site.. don't know, probably:

let resultWithOverflow = a.adding(b, :reportingOverflow)

probably with the same declaration:
func adding(_ other:Self, :reportingOverflow) -> (Self, Bool)

Huh, that could be a great alternative! It would solve the ambiguity issues completely and allow for even single argument cases (if someone wanted to use those).
Any preferences on how to specify these arguments? e.g- just declare them void, attribute or something else?

Also apologies to Patrick, I seem to be leading his discussion, I really should get some work done! :smile:

···

On 22 Feb 2017, at 15:38, Vladimir.S <svabox@gmail.com> wrote:


(Niels Andriesse) #11

+1

I've encountered this issue myself on several occasions, and I think you'd
always be able to create a function signature that reads like a proper
sentence if this is implemented.

···

On Wed, Feb 22, 2017 at 9:24 PM, Patrick Pijnappel via swift-evolution < swift-evolution@swift.org> wrote:

I'd like to discuss allowing a trailing 'argument label' without an actual
argument:

func adding(_ other: Self, reportingOverflow) -> … // Actual case in
SE-104 where this came up
func tableView(_ tableView: UITableView, numberOfSections) -> Int //
Referenced as tableView(_:numberOfSections)

As illustrated above, the way we reference functions extends very
naturally to include these.

This would be very useful for several cases:
• Delegate methods, which currently all start with the same prefix, except
for some odd cases that really actually just needed a trailing argument
label.
• Cases where the function is a more specialized version of one with the
same name, but can't use a flag because the return type is different (e.g.
reportingOverflow), or the extra flag check is just undesirable. The
standard library now uses some workarounds to achieve this (e.g. having a
trailing argument of type void).
• Function names that just work more naturally with some additional words
after the last argument. If we allow trailing argument labels, you can form
any sentence, rounding out the syntax.

Overall, I think this could be the final missing piece to complete Swift's
functions-as-sentences approach.

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


(Vladimir) #12

Do I understand correctly, that the proposed solution is some kind of
sugar to not have separate method named like 'addingWithReportingOverflow' ?

Basically yes; the discussion came up briefly during protocol oriented
integers where this is quite common, especially with added methods for
handling double-width operations and such as well.

In any case IMO such argument label should have special syntax on caller
site.. don't know, probably:

let resultWithOverflow = a.adding(b, :reportingOverflow)

probably with the same declaration:
func adding(_ other:Self, :reportingOverflow) -> (Self, Bool)

Huh, that could be a great alternative! It would solve the ambiguity issues
completely and allow for even single argument cases (if someone wanted to
use those).
Any preferences on how to specify these arguments? e.g- just declare them
void, attribute or something else?

Sorry, not sure I understand the question. I think about such feature as Swift's syntax extension, when :reportingOverflow treated as .. a part of method name, as it is actually not an argument. And we shouldn't even be able to "touch" 'reportingOverflow' inside the func as it is not an argument but a part of function name.

Another alternative I can think of is such:
let resultWithOverflow = a.adding(b):reportingOverflow
func adding(_ other:Self):reportingOverflow -> (Self, Bool)
but in this case ':' looks in caller site like some operation on adding() result.

And actually I'm not sure that feature(actually the sugar) worth the added complexity.

···

On 22.02.2017 22:47, Haravikk wrote:

On 22 Feb 2017, at 15:38, Vladimir.S <svabox@gmail.com >> <mailto:svabox@gmail.com>> wrote:

Also apologies to Patrick, I seem to be leading his discussion, I really
should get some work done! :smile:


(Patrick Pijnappel) #13

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

···

On Thu, Feb 23, 2017 at 6:47 AM, Haravikk via swift-evolution < swift-evolution@swift.org> wrote:

On 22 Feb 2017, at 15:38, Vladimir.S <svabox@gmail.com> wrote:
Do I understand correctly, that the proposed solution is some kind of
sugar to not have separate method named like 'addingWithReportingOverflow' ?

Basically yes; the discussion came up briefly during protocol oriented
integers where this is quite common, especially with added methods for
handling double-width operations and such as well.

In any case IMO such argument label should have special syntax on caller
site.. don't know, probably:

let resultWithOverflow = a.adding(b, :reportingOverflow)

probably with the same declaration:
func adding(_ other:Self, :reportingOverflow) -> (Self, Bool)

Huh, that could be a great alternative! It would solve the ambiguity
issues completely and allow for even single argument cases (if someone
wanted to use those).
Any preferences on how to specify these arguments? e.g- just declare them
void, attribute or something else?

Also apologies to Patrick, I seem to be leading his discussion, I really
should get some work done! :smile:

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


(Derrick Ho) #14

-1 to this proposal.

While it is true that adding the argument labels helps you "read" it
better, you end up with an inverted binary operator. I'll call it a
sandwich.

Argument labels should be used to name an argument so the fact that there
is no argument provided means that this is not a good use case.

I prefer the work around where you accept a void argument.

func something(_ n: Int, strange: Void) { ... }

Then we people look at the definition they can see that it expects a void!

They can call it like this

something(8, strange: ())

in conclusion, I do not support the original pitch. Argument labels should
be used for arguments.

···

On Wed, Feb 22, 2017 at 9:22 AM Haravikk <swift-evolution@haravikk.me> wrote:

On 22 Feb 2017, at 13:19, Derrick Ho <wh1pch81n@gmail.com> wrote:

I've read the pitch, but it isn't clear what the ask is or what benefit it
would give.

The purpose of the feature is to enable selection of identically named
methods with similar signatures. This came up in the protocol-oriented
integers debate on the ability to have arithmetic methods with and without
overflow. Like so:

protocol IntegerArithmetic {
func adding(_ other:Self) -> Self
func adding(_ other:Self, reportingOverflow) -> (Self, Bool)
}

var a = 2, b = 3
let resultWithoutOverflow = a.adding(b)
let resultWithOverflow = a.adding(b, reportingOverflow)

Here we have two different methods, one reporting overflow and one
without, using the label to enable selection, rather than having to have an
addingWithOverflow() method or similar.

Currently the alternative is to do something like:

enum ReportingOverflow { case .reportingOverflow }
protocol IntegerArithmetic {
func adding(_ other:Self) -> Self
func adding(_ other:Self, _) -> (Self, Bool)
}

var a = 2, b = 3
let resultWithoutOverflow = a.adding(b)
let resultWithOverflow = a.adding(b, .reportingOverflow)

Basically the ability to use the label for method selection is an
alternative to either defining an enum as above, or having to use a
different method name.


(Haravikk) #15

Vladimir suggested that an alternative might be to use a leading colon to indicate that the label is for selecting a function only, which would solve the ambiguity issues. Of course this means it's much the same as using the single enum case trick, but at least this way it'd still be a proper language feature rather than a workaround, and no extra types are declared just to support it.

So you'd have something like:

  func foo(_ x:Int, :reportingOverflow) { … }
  func foo(_ x:Int, _ reportingOverflow:Bool) { … }

  let reportingOverflow = true
  foo(5, reportingOverflow) // Calls the second declaration of foo using the boolean argument
  foo(5, :reportingOverflow) // Calls the first declaration of foo

It's still a little subtle, but the single-case enum that this feature would replace has the exact same problem. So long as the label is sufficiently descriptive it shouldn't be a very likely target for a naming collision.

I think the leading colon alternative is probably the one I'd favour, as a plain argument label probably isn't clear enough, so having an indicator is better overall. It means that as a feature it won't have any advantages over the single-case enum, except that you don't have to declare an unnecessary extra type (which needs to be documented somehow), so I think it's still worth having to make this capability part of the function signature proper.

···

On 22 Feb 2017, at 21:25, Patrick Pijnappel <patrickpijnappel@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) #16

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

···

On 23.02.2017 14:17, Haravikk wrote:

On 22 Feb 2017, at 21:25, Patrick Pijnappel <patrickpijnappel@gmail.com >> <mailto:patrickpijnappel@gmail.com>> wrote:

indicate that the label is for selecting a function only, which would solve
the ambiguity issues. Of course this means it's much the same as using the
single enum case trick, but at least this way it'd still be a proper
language feature rather than a workaround, and no extra types are declared
just to support it.

So you'd have something like:

func foo(_ x:Int, :reportingOverflow) { … }
func foo(_ x:Int, _ reportingOverflow:Bool) { … }

let reportingOverflow = true
foo(5, reportingOverflow) // Calls the second declaration of foo using the
boolean argument
foo(5, :reportingOverflow) // Calls the first declaration of foo

It's still a little subtle, but the single-case enum that this feature
would replace has the exact same problem. So long as the label is
sufficiently descriptive it shouldn't be a very likely target for a naming
collision.

I think the leading colon alternative is probably the one I'd favour, as a
plain argument label probably isn't clear enough, so having an indicator is
better overall. It means that as a feature it won't have any advantages
over the single-case enum, except that you don't have to declare an
unnecessary extra type (which needs to be documented somehow), so I think
it's still worth having to make this capability part of the function
signature proper.


(Haravikk) #17

Yeah, I was one of the ones who liked the idea but it never seemed to get much traction unfortunately.

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.

···

On 23 Feb 2017, at 12:49, Vladimir.S <svabox@gmail.com> wrote:

On 23.02.2017 14:17, Haravikk wrote:

On 22 Feb 2017, at 21:25, Patrick Pijnappel <patrickpijnappel@gmail.com >>> <mailto:patrickpijnappel@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…


(Vladimir) #18

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(_:slight_smile: // 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?

···

On 23.02.2017 17:35, Haravikk wrote:

On 23 Feb 2017, at 12:49, Vladimir.S <svabox@gmail.com >> <mailto:svabox@gmail.com>> wrote:
On 23.02.2017 14:17, Haravikk wrote:

On 22 Feb 2017, at 21:25, Patrick Pijnappel <patrickpijnappel@gmail.com >>>> <mailto:patrickpijnappel@gmail.com> >>>> <mailto:patrickpijnappel@gmail.com>> wrote:


(Haravikk) #19

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

Interesting, but personally I think it's less clear than with the colon separating it further.

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?

I think if there's going to be a proposal then it helps to have hashed out some of the syntax at least, but yeah, I suppose the key point is whether the feature is significant enough to warrant support. Personally I'm heavily in favour, as I dislike verbose naming and really like the idea of grouped functions being identically named. After all, in the case of protocol oriented integers the adding examples are both an addition operation, all that really differs is the type of result you want from it.

The question I suppose might partly come down to naming convention though; do people like the convention of using a "selector" to narrow the method, versus differently (but otherwise very similarly) named methods. I like how clean just having functions named "adding" is, with the option to narrow to a specific one other than the default, but others may prefer more verbose method names, in which case the feature isn't really needed, if that's the majority view.

I just like that if a group of methods all have the same name it is absolutely clear that they are closely related. The trade-off perhaps however is that narrowing down the choice comes later, whereas using the method name means narrowing down of auto-correct happens right away.

···

On 23 Feb 2017, at 18:25, Vladimir.S <svabox@gmail.com> wrote: