Named parameters - why hidden first?/proposal interest


(David Owens II) #1

Ok, this is something that's bugged me since Swift was released. It was almost fixed it back in the 1.x days (I think that was when it changed to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first parameters for non-init functions, and in some cases, suggest putting the name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I understand that it's not feasible to implicitly convert all the ObjC interfaces to move the parameter name into the first position (though they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There seems to be a perfectly good spot for the first parameter name of a function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug Gregor's Naming Functions with Arguments Labels proposal. The default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

Am I just missing the really compelling rationale for this?

Thanks,
David


(Michael Wells) #2

I’m in 100% agreement here. In this case, the Swift API Design Guideline seems to be aligned more with Objective C and it doesn’t feel at all Swift-y.

-mw

···

On Jan 21, 2016, at 9:23 AM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

Ok, this is something that's bugged me since Swift was released. It was almost fixed it back in the 1.x days (I think that was when it changed to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first parameters for non-init functions, and in some cases, suggest putting the name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I understand that it's not feasible to implicitly convert all the ObjC interfaces to move the parameter name into the first position (though they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There seems to be a perfectly good spot for the first parameter name of a function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug Gregor's Naming Functions with Arguments Labels proposal. The default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

Am I just missing the really compelling rationale for this?

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


(Tony Parker) #3

Hi David,

This is obviously a topic which gets a lot of discussion, and I doubt I’ll be able to thoroughly convince anyone with an email or two on the topic… but I would like to share one of the reasons behind the decision to avoid labeling the first argument.

We surveyed the entire surface area of the iOS and OS X SDKs, looking to see how many arguments typical methods had. We found that the vast majority of methods actually have just one argument. If we went with a rule that first arguments should be named, then methods like:

sayMessage(“hello”)

would be this instead:

say(message: “hello”)

which isn’t really much of an improvement, in my mind.

Furthermore, when methods have more than one argument, we found that the additional arguments are most often modifiers or minor adjustments to the first argument. Or, put another way: when there are multiple arguments, the first argument is almost always far more important to the meaning of the method. Your example below follows this pattern as well: the primary purpose of the function is to say a message. The number of times it is said is a secondary modifier to the central purpose.

These factors led us to the conclusion that the label of the first argument is (in the vast majority of cases) really part of the method and not equal in importance to the remaining labels.

- Tony

···

On Jan 21, 2016, at 9:23 AM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

Ok, this is something that's bugged me since Swift was released. It was almost fixed it back in the 1.x days (I think that was when it changed to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first parameters for non-init functions, and in some cases, suggest putting the name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I understand that it's not feasible to implicitly convert all the ObjC interfaces to move the parameter name into the first position (though they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There seems to be a perfectly good spot for the first parameter name of a function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug Gregor's Naming Functions with Arguments Labels proposal. The default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

Am I just missing the really compelling rationale for this?

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


(Dave Abrahams) #4

Ok, this is something that's bugged me since Swift was released. It
was almost fixed it back in the 1.x days (I think that was when it
changed to be a bit more consistent between top-level funcs and
members funcs).

The question is this, why do we still implicitly have unnamed first
parameters for non-init functions, and in some cases, suggest putting
the name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Hi David; thanks for asking. This is very much related to the upcoming
API Design Guidelines review
(https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md),
so we may have an opportunity to discuss it in more depth. For now, I'm
going to give you my personal opinion below.

Let me be clear, I completely understand why the _ is supported, and I
understand that it's not feasible to implicitly convert all the ObjC
interfaces to move the parameter name into the first position (though
they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs?
There seems to be a perfectly good spot for the first parameter name
of a function: the first parameter slot.

First of all, I've found the convention to work quite well for the
standard library. IMO well-designed APIs typically don't have many
parameters, and methods that take a single parameter are in fact
extremely common. In these cases, the parameter often functions
grammatically as the direct object of the statement being made in the
call, adding a label doesn't help readability. It's

    x.remove(y)

vs

    x.remove(containedThing: y)

or

    x.removeContainedThing(y)

It's my strong belief that it's usually impossible to improve on
"x.remove(y)". The less-common case where x contains a bunch of
different kinds of things and removing each kind is semantically
different—e.g. UIViews contain subviews and gestureRecognizers—is a
notable exception.

Of the methods and functions with multiple parameters, many of them have
one primary parameter that functions as a direct object, and a few other
parameters—often with defaults—used to "tune" the overall behavior of
the method. So in these cases, having no label is appropriate as well
(c.f. print).

The seemingly poor choice of this shows up in other places too, like
Doug Gregor's Naming Functions with Arguments Labels proposal. The
default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

I don't see why that's a problem; it's a side effect of most methods not
having an initial label, while some do.

The other unfortunate thing about this, is that this is another
instance where "init" behaves differently then the rest of Swift. I
think it would be great to unify this.

Am I just missing the really compelling rationale for this?

Aside from single-argument, type-conversion initializers (on which by
convention we are dropping the initial label), initializeations tend to
be different from methods and function calls. There's no way for the
first argument to function as a direct object of a phrase, so they are
more functional/declarative than method calls.

I do have a few disagreements with the API guidelines in this area, but
I'm going to leave that discussion for the review.

Hope this helps,
Dave

···

on Thu Jan 21 2016, David Owens II via swift-evolution <swift-evolution-m3FHrko0VLzYtjvyW6yDsg-AT-public.gmane.org> wrote:


(Adriano Ferreira) #5

I totally understand that beautiful & elegant code might be very subjective. However, having a different way of treating the first parameter is rather confusing. Feels weird, inconsistent, and introduces complexity.

I’d rather have all arguments with explicit labels by default. Simple and clean. And, as mentioned already, if one wants to override that behaviour, just use `_`.

Best,

— A

···

On Jan 21, 2016, at 12:23 PM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

Ok, this is something that's bugged me since Swift was released. It was almost fixed it back in the 1.x days (I think that was when it changed to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first parameters for non-init functions, and in some cases, suggest putting the name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I understand that it's not feasible to implicitly convert all the ObjC interfaces to move the parameter name into the first position (though they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There seems to be a perfectly good spot for the first parameter name of a function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug Gregor's Naming Functions with Arguments Labels proposal. The default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

Am I just missing the really compelling rationale for this?

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


(Tino) #6

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

It's definitely confusing that labels receive special treatment in init, and I'm quite sure method declarations would look different without the "Objective-C-legacy".

Imho named arguments with default values are a great feature, which I loved since I've seen it the first time R (which would be very hard to use without default values…).
R, as my reference, is quite flexible with parameters:
You can leave out all labels, and only rely on the order of the values, you can assign values in whatever order you like — and, up to a certain degree, you can mix:
myFunc(firstParameterWithoutLabel, secondParameterWithoutLabel, fourthLabel = 8, thirdLabel = 0.5)

I don't think Swift needs that much flexibility, but imho the compiler could be less strict and leave it to the user weather parameters are identified via label or position.

say("message", times: 4)
is a good default and should be offered by autocompletion, but

say(message: "Hello", times: 4)

and even

say("Hello", 4)

could be allowed as well (as long as there is no clash with a second say-function).

Labels are "just" an aid for programmers, but for the program itself, they have not much more meaning than a comment:
Higher-order functions already ignore labels completely and rely on positions only.

So, instead of complicated rules enforced by the compiler, I would prefer a simple system backed by conventions that discourage programmers to fall back to C-style calls where you have to count parameters to decipher their meaning.

Tino


(David Owens II) #7

Hi David,

This is obviously a topic which gets a lot of discussion, and I doubt I’ll be able to thoroughly convince anyone with an email or two on the topic… but I would like to share one of the reasons behind the decision to avoid labeling the first argument.

We surveyed the entire surface area of the iOS and OS X SDKs, looking to see how many arguments typical methods had. We found that the vast majority of methods actually have just one argument. If we went with a rule that first arguments should be named, then methods like:

sayMessage(“hello”)

would be this instead:

say(message: “hello”)

which isn’t really much of an improvement, in my mind.

Interesting. I would have drawn the opposite conclusion. The vast majority of ObjC APIs have the name of the first parameter in the first section of the selector name. This implies, to me, that the name of the first parameter is very important, and because of the syntactical limitation, the name of the action and the name of the first parameter needed to be joined together.

This leads to APIs like this (from UITableView):

func registerNib(_ nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String)
func registerClass(_ aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String)

Instead of APIs like:

func register(nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String)
func register(aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String)

I don’t think I’m being overly selective in my example, but it seems like overloads make this even more desirable to move the name within the parameter list.

Furthermore, when methods have more than one argument, we found that the additional arguments are most often modifiers or minor adjustments to the first argument. Or, put another way: when there are multiple arguments, the first argument is almost always far more important to the meaning of the method. Your example below follows this pattern as well: the primary purpose of the function is to say a message. The number of times it is said is a secondary modifier to the central purpose.

I get what you’re saying, we just disagree on the importance of the first parameter’s significance to the function’s purpose. =) I think the primary purpose is “say” and there there is the data for that purpose. Currently, the only data for say is “message:times”, but it’s not hard to see other use cases. I guess my argument is that I think overloads serve that grouping better than different function names that have the same purpose and act on different data. Swift makes it annoying to do that today, so I end up doing neither and just rely on the type system to handle the first parameter difference, which is less than ideal, but it’s the lazy solution.

Thanks for chiming in,
-David

···

On Jan 21, 2016, at 11:25 AM, Tony Parker <anthony.parker@apple.com> wrote:


(Dave Abrahams) #8

No, but

    say("hello")

is a big improvement, which IMO perfectly illustrates why we want the
default as it is.

That said, as the API Guidelines review is to start imminently, I'd like
to ask people to hold off discussing this topic further until we start
the review, so we can gather all the related commentary in one place.

Thanks!

···

on Thu Jan 21 2016, Tony Parker via swift-evolution <swift-evolution-m3FHrko0VLzYtjvyW6yDsg-AT-public.gmane.org> wrote:

We surveyed the entire surface area of the iOS and OS X SDKs, looking
to see how many arguments typical methods had. We found that the vast
majority of methods actually have just one argument. If we went with a
rule that first arguments should be named, then methods like:

sayMessage(“hello”)

would be this instead:

say(message: “hello”)

which isn’t really much of an improvement, in my mind.


(Charles Constant) #9

+1 (assuming the OP means making naming consistent)

This is one of the ugliest aspects of Swift. There has to be some other way
to ensure compatibility with Obj-C. This is particularly cruel to
beginners, who won't understand why they can't write arguments the same way
everywhere. It's also additional complexity for anyone reading a function.

My personal preference is that **all** arguments, not just regardless of
position, but also regardless of their being in an init/method, have
explicit labels by default. If one wants to override that with "_", one can
do so, but it ought to work the same way everywhere.

···

On Thu, Jan 21, 2016 at 11:25 AM, Tony Parker via swift-evolution < swift-evolution@swift.org> wrote:

Hi David,

This is obviously a topic which gets a lot of discussion, and I doubt I’ll
be able to thoroughly convince anyone with an email or two on the topic…
but I would like to share one of the reasons behind the decision to avoid
labeling the first argument.

We surveyed the entire surface area of the iOS and OS X SDKs, looking to
see how many arguments typical methods had. We found that the vast majority
of methods actually have just one argument. If we went with a rule that
first arguments should be named, then methods like:

sayMessage(“hello”)

would be this instead:

say(message: “hello”)

which isn’t really much of an improvement, in my mind.

Furthermore, when methods have more than one argument, we found that the
additional arguments are most often modifiers or minor adjustments to the
first argument. Or, put another way: when there are multiple arguments, the
first argument is almost always far more important to the meaning of the
method. Your example below follows this pattern as well: the primary
purpose of the function is to say a message. The number of times it is said
is a secondary modifier to the central purpose.

These factors led us to the conclusion that the label of the first
argument is (in the vast majority of cases) really *part of* the method
and not equal in importance to the remaining labels.

- Tony

On Jan 21, 2016, at 9:23 AM, David Owens II via swift-evolution < > swift-evolution@swift.org> wrote:

Ok, this is something that's bugged me since Swift was released. It was
*almost* fixed it back in the 1.x days (I think that was when it changed
to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first
parameters for non-init functions, and in some cases, suggest putting the
name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I
understand that it's not feasible to implicitly convert all the ObjC
interfaces to move the parameter name into the first position (though they
could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There
seems to be a perfectly good spot for the first parameter name of a
function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug
Gregor's *Naming Functions with Arguments Labels* proposal. The default
for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance
where "init" behaves differently then the rest of Swift. I think it would
be great to unify this.

Am I just missing the really compelling rationale for this?

Thanks,
David
_______________________________________________
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


(Sean Heber) #10

I’m of two minds about this. I initially really disliked this convention and thought it would be more Swifty to get rid of the implicitly unnamed first parameter and do things as David suggests, but lately I have found the naming convention useful for forcing me to keep functions simpler and smaller because the addition of a second parameter that must be named feels so out of place at the call site by comparison and I’d rather not have it there if I can avoid it. Of course there is no reason such discipline could not be applied without this convention, it’s just that, at the moment, I’ve come to embrace the design as a tool for producing better code. I don’t know if that was the original intent behind it or not, though.

l8r
Sean

···

On Jan 21, 2016, at 12:11 PM, Michael Wells via swift-evolution <swift-evolution@swift.org> wrote:

I’m in 100% agreement here. In this case, the Swift API Design Guideline seems to be aligned more with Objective C and it doesn’t feel at all Swift-y.

-mw

On Jan 21, 2016, at 9:23 AM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

Ok, this is something that's bugged me since Swift was released. It was almost fixed it back in the 1.x days (I think that was when it changed to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first parameters for non-init functions, and in some cases, suggest putting the name of the first parameter in the name of the function?

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I understand that it's not feasible to implicitly convert all the ObjC interfaces to move the parameter name into the first position (though they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There seems to be a perfectly good spot for the first parameter name of a function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug Gregor's Naming Functions with Arguments Labels proposal. The default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

Am I just missing the really compelling rationale for this?

Thanks,
David
_______________________________________________
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


#11

See below

I’m in 100% agreement here. In this case, the Swift API Design Guideline seems to be aligned more with Objective C and it doesn’t feel at all Swift-y.

-mw

Ok, this is something that's bugged me since Swift was released. It was almost fixed it back in the 1.x days (I think that was when it changed to be a bit more consistent between top-level funcs and members funcs).

The question is this, why do we still implicitly have unnamed first parameters for non-init functions, and in some cases, suggest putting the name of the first parameter in the name of the function?

As you said in some cases. So in most cases you want to have an implicit unnamed first parameter.

- Maximilian

···

Am 21.01.2016 um 19:11 schrieb Michael Wells via swift-evolution <swift-evolution@swift.org>:

On Jan 21, 2016, at 9:23 AM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

    func say(message: String, times: Int) { ... } // or
    func sayMessage(message: String, times: Int) { ... }

    say("hello world", times: 5) // or
    sayMessage("hello world", times: 5)

    // vs.

    say(message: "hello world", times: 5)

Let me be clear, I completely understand why the _ is supported, and I understand that it's not feasible to implicitly convert all the ObjC interfaces to move the parameter name into the first position (though they could be annotated to do this...).

However, why are we continuing that tradition with _new_ Swift APIs? There seems to be a perfectly good spot for the first parameter name of a function: the first parameter slot.

The seemingly poor choice of this shows up in other places too, like Doug Gregor's Naming Functions with Arguments Labels proposal. The default for that is to always have the _ in the first name slot.

    say(_:times:)
    sayMessage(_:times:)

    // vs.

    say(message:times:)

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

Am I just missing the really compelling rationale for this?

Thanks,
David
_______________________________________________
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


(Rob Mayoff) #12

UIView.insertSubview(_:,belowSubview:) and
UIView.insertSubview(_:,aboveSubview:) beg to differ. As do
UIView.convertPoint(_:,toView:) and UIView.convertPoint(_:,fromView:). Need
more examples? Take a look at UITableViewDelegate.

···

On Fri, Jan 22, 2016 at 8:26 AM, Tino Heth via swift-evolution < swift-evolution@swift.org> wrote:

Labels are "just" an aid for programmers, but for the program itself, they
have not much more meaning than a comment:


(Jordan Rose) #13

Agreed. I'm quite happy that Swift labels are effectively part of the method name and therefore consistently applied. Long parameter lists are easy to get lost in.

Jordan

···

On Jan 22, 2016, at 7:49, Rob Mayoff via swift-evolution <swift-evolution@swift.org> wrote:

On Fri, Jan 22, 2016 at 8:26 AM, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Labels are "just" an aid for programmers, but for the program itself, they have not much more meaning than a comment:

UIView.insertSubview(_:,belowSubview:) and UIView.insertSubview(_:,aboveSubview:) beg to differ. As do UIView.convertPoint(_:,toView:) and UIView.convertPoint(_:,fromView:). Need more examples? Take a look at UITableViewDelegate.


(Douglas Gregor) #14

The other unfortunate thing about this, is that this is another instance where "init" behaves differently then the rest of Swift. I think it would be great to unify this.

It's definitely confusing that labels receive special treatment in init, and I'm quite sure method declarations would look different without the "Objective-C-legacy”.

We believe fairly strongly that Swift’s design here reflects the appropriate defaults for clear, expressive APIs and code. The API Design Guidelines line up with the default behavior of Swift for a reason. Repeating the “Objective-C legacy” trope strongly implies that you’re not considering the rationale behind Swift’s design, and weakens your arguments considerably.

Imho named arguments with default values are a great feature, which I loved since I've seen it the first time R (which would be very hard to use without default values…).
R, as my reference, is quite flexible with parameters:
You can leave out all labels, and only rely on the order of the values, you can assign values in whatever order you like — and, up to a certain degree, you can mix:
myFunc(firstParameterWithoutLabel, secondParameterWithoutLabel, fourthLabel = 8, thirdLabel = 0.5)

I don't think Swift needs that much flexibility, but imho the compiler could be less strict and leave it to the user weather parameters are identified via label or position.

say("message", times: 4)
is a good default and should be offered by autocompletion, but

say(message: "Hello", times: 4)

The message is the direct object of the verb “say”, so the first argument being the message is implied. Clarity is not improved by having the “message:” argument label.

and even

say("Hello", 4)

could be allowed as well (as long as there is no clash with a second say-function).

This is less clear than your initial example. There is absolutely nothing to indicate, at the call site, that “4” is a repeat count.

Labels are "just" an aid for programmers, but for the program itself, they have not much more meaning than a comment:

That is incorrect. The argument labels are a fundamental part of the name of a Swift function (or initializer, or subscript).

Higher-order functions already ignore labels completely and rely on positions only.

That’s mostly correct; our model around argument labels with function types is fuzzy and needs work.

So, instead of complicated rules enforced by the compiler, I would prefer a simple system backed by conventions that discourage programmers to fall back to C-style calls where you have to count parameters to decipher their meaning.

So… you want a plethora of conventions that differ from one project to the next, rather than a set of default language rules backed by the API Design Guidelines? I admit that one will often do a double-take when first encountering the rules for which arguments have labels by default, but I’d rather learn that once than have widely differing approaches to when argument labels are provided vs. dropped.

  - Doug

···

On Jan 22, 2016, at 6:26 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:


(Tino) #15

UIView.insertSubview(_:,belowSubview:) and UIView.insertSubview(_:,aboveSubview:) beg to differ. As do UIView.convertPoint(_:,toView:) and UIView.convertPoint(_:,fromView:). Need more examples? Take a look at UITableViewDelegate.

Agreed. I'm quite happy that Swift labels are effectively part of the method name and therefore consistently applied. Long parameter lists are easy to get lost in.

That's exactly my opinion: Labels help us — the computer doesn't care weather a function has a meaningful name or is called as "f231(4, true)"
Especially because of the benefit of labels, it's imho not necessary that the compiler enforces their use… but I think it's actually annoying to be forced to skip labels:

func printPowWithBase(base: Double, exponent: Double) {
  print(pow(base, exponent))
}
printPowWithBase(2, exponent: 3)

Easy to understand, works as expected — but would it hurt if

printPowWithBase(base: 2, exponent: 3)

would be accepted as well? Sure, "base:" is redundant, but who cares? And, as others already mentioned: For init, the first label is required…

Additionally, there is a hidden(?) feature in Swift that's imho quite cool:
The ability to call a function with a tuple containing the arguments
let args = (4.0, exponent: 4.0)
printPowWithBase(args)

In this case, you end up with a first parameter without any indication of its role.

Tino


(Charles Srstka) #16

How about making it so that methods with just one argument have no label on the argument by default, but methods with two or more arguments have labels on all arguments? This would prevent what you describe above, while eliminating the ugliness of one parameter being treated differently from all the rest in the same method.

Charles

···

On Jan 21, 2016, at 1:25 PM, Tony Parker via swift-evolution <swift-evolution@swift.org> wrote:

We surveyed the entire surface area of the iOS and OS X SDKs, looking to see how many arguments typical methods had. We found that the vast majority of methods actually have just one argument. If we went with a rule that first arguments should be named, then methods like:

sayMessage(“hello”)

would be this instead:

say(message: “hello”)

which isn’t really much of an improvement, in my mind.


(Tino) #17

We believe fairly strongly that Swift’s design here reflects the appropriate defaults for clear, expressive APIs and code. The API Design Guidelines line up with the default behavior of Swift for a reason. Repeating the “Objective-C legacy” trope strongly implies that you’re not considering the rationale behind Swift’s design, and weakens your arguments considerably.

I'm not saying the influence of Objective-C is bad (therefore, I used the quotation marks), but imho it's pointless to deny that it exists.

say(message: "Hello", times: 4)

The message is the direct object of the verb “say”, so the first argument being the message is implied. Clarity is not improved by having the “message:” argument label.

I wouldn't force anyone to use that label — and I think this topic was not started because of a lack of clarity, but an excess of different rules.

say("Hello", 4)

This is less clear than your initial example. There is absolutely nothing to indicate, at the call site, that “4” is a repeat count.

Here as well: The use of a label should not be discouraged — but you can't fight against users who (for whatever reason) want to use calls that are hard to understand.

Labels are "just" an aid for programmers, but for the program itself, they have not much more meaning than a comment:

That is incorrect. The argument labels are a fundamental part of the name of a Swift function (or initializer, or subscript).

I guess that sentence failed in expressing my thoughts:
Of course, labels have influence on method/selector resolution — but their raison d'être is to help programmers to write calls that are easy to understand: Many languages have no labels for parameters, and afair, there has been at least one bridge (Cocoa for Java?) that had to get rid of them.

Higher-order functions already ignore labels completely and rely on positions only.

That’s mostly correct; our model around argument labels with function types is fuzzy and needs work.

Taking a statement from another thread:

Right now, you'll still need to use labels in the call. However, this is an area where we'd like to revisit things a bit: having labels in function types seems to cause more trouble than it provides benefits, and I'd like to see up address that directly.

So you say that there are situations where labels are bad, right? So it would be necessary to define rules on how to get rid of them as well...

So, instead of complicated rules enforced by the compiler, I would prefer a simple system backed by conventions that discourage programmers to fall back to C-style calls where you have to count parameters to decipher their meaning.

So… you want a plethora of conventions that differ from one project to the next,

No. I don't think there would be an urge to establish a different set of conventions for each project/team.

rather than a set of default language rules backed by the API Design Guidelines? I admit that one will often do a double-take when first encountering the rules for which arguments have labels by default, but I’d rather learn that once than have widely differing approaches to when argument labels are provided vs. dropped.

I think you are underestimating the importance of conventions — in the area of code comprehensibility, they are far more powerful than anything that can be enforced by a compiler.

There has been another discussion about something that's optional and should become mandatory (self). I'm glad that proposal was rejected, as I think it's not that hard to define a set of guidelines when to use "self." and when to skip it, but it shouldn't be the job of the compiler to enforce rules whose only justification is to make source more accessible to human readers.
Imho labels are very similar in this aspect, with the difference that right now, there is a quite complicated scheme embedded in the compiler. Moving that responsibility to the party that actually is affected by the choice (we as developers) would make the language simpler and more elegant.

Tino


(Thorsten Seitz) #18

Yes, I think Swifts external parameter labels are a really well done part of the language and a great advantage over languages without labeled parameters and over those who do have labeled parameters but where the labels are simply the parameter names which does not allow the same expressiveness in a method call as I’m used to from Smalltalk (or Objective-C). I’m really glad Swift has these.

-Thorsten

···

Am 22.01.2016 um 20:46 schrieb Jordan Rose via swift-evolution <swift-evolution@swift.org>:

On Jan 22, 2016, at 7:49, Rob Mayoff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Fri, Jan 22, 2016 at 8:26 AM, Tino Heth via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Labels are "just" an aid for programmers, but for the program itself, they have not much more meaning than a comment:

UIView.insertSubview(_:,belowSubview:) and UIView.insertSubview(_:,aboveSubview:) beg to differ. As do UIView.convertPoint(_:,toView:) and UIView.convertPoint(_:,fromView:). Need more examples? Take a look at UITableViewDelegate.

Agreed. I'm quite happy that Swift labels are effectively part of the method name and therefore consistently applied. Long parameter lists are easy to get lost in.

Jordan

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


(Charles Constant) #19

say("hello")

is a big improvement, which IMO perfectly illustrates why we want the
default as it is.

Maybe so, but there just has to be some way to do this that doesn't bake
the design into the entirety of the Swift language. Is there some way Apple
could implement this that only affects Swift imports/exports with Obj-C?
Maybe there's not, but if there is, that seems like a better option.

If Obj-C had never existed, would any sane person ever have suggested that
Swift treat the first parameter differently than the rest? It kinda makes
sense with Obj-C syntax, but it stands out like a sore thumb in Swift.

I think little quirks like this are seriously damaging to the language.
Because of the massive scope of Swift, "death by a thousand paper cuts" is
a real thing.


(Chris Lattner) #20

The others’ are right, this is best discussed holistically as part of the forthcoming renamification threads.

That said, the example you picked is exactly illustrative of why the current default works well. One of the principles of the naming guidelines is “omit needless words”: https://swift.org/documentation/api-design-guidelines.html and it is a specific anti-goal of the new naming approach to “simply repeat type information” in an argument name.

This approach will lead to these APIs actually being imported as:

  func register(nib: UINib?, ...
  func register(aClass: AnyClass?, …

These are much better at point of use, and dovetails perfectly with our current keyword argument behavior.

-Chris

···

On Jan 21, 2016, at 12:07 PM, David Owens II via swift-evolution <swift-evolution@swift.org> wrote:

which isn’t really much of an improvement, in my mind.

Interesting. I would have drawn the opposite conclusion. The vast majority of ObjC APIs have the name of the first parameter in the first section of the selector name. This implies, to me, that the name of the first parameter is very important, and because of the syntactical limitation, the name of the action and the name of the first parameter needed to be joined together.

This leads to APIs like this (from UITableView):

func registerNib(_ nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String)
func registerClass(_ aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String)

Instead of APIs like:

func register(nib: UINib?, forHeaderFooterViewReuseIdentifier identifier: String)
func register(aClass: AnyClass?, forHeaderFooterViewReuseIdentifier identifier: String)

I don’t think I’m being overly selective in my example, but it seems like overloads make this even more desirable to move the name within the parameter list.