I would expect that the compiler would understand that my intent is to keep the default parameter for _ first ("Hello") and that I'm passing "World" as _ second and print Hello, World.
It is not a “bug” because it is the intended design: call-site arguments are assigned greedily to the next function parameter with a matching label. Here are a couple of older threads about the topic:
It would technically be possible to change the design. There exists an algorithm that can match “as greedily as possible” while allowing defaulted parameters to be skipped if necessary. The “obvious” ways to do so take O(mn) time, where m is the number of arguments at the call-site and n is the number of parameters in a candidate function. I have heard that a quasilinear algorithm exists as well.
This is related to the longest common subsequence problem. I can’t remember the name of the exact problem off the top of my head. It is essentially a test for “is A (the call-site argument labels) a subsequence of B (the declaration-site argument labels), which contains subsequence C (the non-defaulted labels), plus some fiddly stuff about trailing closures.
It’s a bit more tricky than that though, because the positioning of C within A must be “compatible” with the positioning of C within B.
Related: there is an API design guideline of 'Prefer to locate parameters with defaults toward the end' with one of the justifications being that it produces a stable initial pattern of use.
I’m aware of the guideline, but there are always motivating exceptions. For instance, expressing a REST call with the verb (http method) coming first (and defaulting to ”GET”) where external argument labels are superfluous:
I think that example proves the opposite point. A user can far too easily reverse the method and path arguments and the compiler cannot catch the mistake; it would only be detected at runtime. Thus, the labels aren't actually superfluous.
Even if you replaced the stringly-typed HTTP method argument with an enum, and if you really want to keep the HTTP method first, I don't think adding a from: label to the path argument is onerous at all; it reads more fluently as a result.
I see your point. At first it seemed to me like the compiler should be able to infer what to do, but just because it could (if the greedy strategy was foregone) doesn’t mean that it should [insert Jeff Goldblum meme here].
Thanks everyone for sharing your insights and helping me arrive at the same conclusion. Consider this closed!
Perhaps we should introduce a compile-time warning for the situation where two consecutive function parameters have the same label and the first one has a default value while the second does not.
That default value will never be used at any call-site, so a warning at the declaration seems reasonable.