The way Swift does them is the least awkward and most robust I have seen in any language.
> As an example, the colon and the whitespace are sufficient to separate parameters. So is the comma. So we have...both?
Designing a language around what the minimum requirements of a parser is will not get you a good language. Human language is massively redundant, because humans find it more easy to communicate when there is redundancy. Computer code is also communication aimed at humans, and a bit of redundancy does not hurt there, and can often help.
> There is also the issue that, please correct me if I got this wrong, the label that's in the signature becomes the name of the parameter inside the function.
This is incorrect. You can optionally specify both an internal and external name for any argument. Unlabelled arguments are just a special case of this syntax, where you say "external name does not exist, internal name is this".
You got that wrong. You can specify a separate internal name like this:
foo(externalName internalName: Type) { ... }
> you actually need labels in your function declaration even for parameters that are unlabeled. Wut? And because of this, you need another special bit of syntax that says "despite the fact that I am now about to give a label, this is unlabeled"I mean you need to refer to those values inside your function as something and that has to be specified somewhere. How else would you do it?
Also the `_` you're complaining about is just a special case of the syntax I described above. This just means the external parameter name is omitted at the call site. It's quite consistent: if two names are given, one is external and one is internal. If only one is given, that means the external and internal names are the same (which is convenient since this is the common case).
> It also means that a name that is actually purely internal to the function is part of the signature. Wat?
Again, where on earth else would you put it? That's only also half true: the public signature does not include the internal parameter name. For instance I can declare a protocol like this:
protocol P {
func foo(arg: Int)
}
And both of these implementations will conform to it just fine despite the fact that the internal argument names are different: struct A: P {
func foo(arg internalA: Int) { ... }
}
struct B: P {
func foo(arg internalB: Int) { ... }
}
> And sometimes you get partial labels that just kind of sit there.Can you give an example? I'm not quite sure what you're talking about.
Ahh, my bad! But only the "cannot be changed/mapped." part, right?
foo(externalName internalName: Type) { ... }
Doesn't this strike you as odd at all? The part that looks like the label is not the label, it's the name of the variable. And then there's this extra bit in front that doesn't look like the label, doesn't really look like anything TBH, that will turn into the label. If present.I kind of see how they got there, but boy is it inconsistent.
It seems pretty simple to me: everything before the colon is defining the argument name. If you have one label, it means the argument label is the same as the name of the parameter used inside the function. If you have two labels, then the first one is the argument label and the second one is the variable name.
You could also think of it that you’re always specifying the argument label and the variable name, and in the case where they’re identical you have a bit of shorthand to save some typing.
Maybe it seems weird to some people if it’s not familiar, but I got used to it pretty quickly after starting to use Swift, and it felt like a natural extension of the type system and optional handling in terms of the language giving me tools to cross-check things and bake sanity checks into the source code itself.
Probably. ¯\_(ツ)_/¯
> everything before the colon is defining the argument name.
So the space binds more strongly than the colon. That seems..."unusual".
You can in fact provide names for both, and there at least used to be (I think they might have removed this?) some ludicrous special case on the behavior of the first parameter.
Keyword parameters are great. The way they are done in x.f() syntax languages is sub-optimal, and Swift is particularly weird.
> code becomes almost self-documenting
Yes, exactly!
Dan Ingalls explains this wonderfully in his Object Oriented Programming talk. Highly recommended:
https://youtu.be/P2mh92d-T3Y?t=515
The problem is that there is the Smalltalk/Objective-C style keyword syntax or the Pascal/C/C++ etc. function syntax. Both are consistent and complete ways of handling this, though I obviously think the Smalltalk way is better.
But it's either/or. When you jam them together, you get a weird mess of special cases and workarounds.
I would agree that the benefits of labels outweigh the messiness, even for the x.f() + labels case. So if you're coming from the x.f() side of things, I can fully understand and sympathize the view that they are a pure benefit without drawbacks. But once you have keyword messages, you no longer need the x.f() part of the syntax, because the syntax is completely self-sufficient. And then all the extra messiness of integrating the two makes no sense whatsoever.
As an example, the colon and the whitespace are sufficient to separate parameters. So is the comma. So we have...both?
There is also the issue that, please correct me if I got this wrong, the label that's in the signature becomes the name of the parameter inside the function. And as far as I can tell it cannot be changed/mapped. That's a horrible coupling of inside and outside.
Because of this, you actually need labels in your function declaration even for parameters that are unlabeled. Wut? And because of this, you need another special bit of syntax that says "despite the fact that I am now about to give a label, this is unlabeled". It also means that a name that is actually purely internal to the function is part of the signature. Wat?
And sometimes you get partial labels that just kind of sit there. It's really weird when you look at things closely.
I guess an analogy would be like a gasoline engine, a hybrid and a fully electric. Yes, the hybrid seems like an obvious improvement to the pure gasoline engine, if at some cost in complexity. But the pure electric car (let's assume a few more years improvement in battery tech) does away with all that extra complexity.
Hmm not entirely sure that analogy is all that good.