Unnamed variables and match-all patterns

John Rose john.r.rose at oracle.com
Thu Sep 8 04:10:02 UTC 2022



On 7 Sep 2022, at 18:35, Guy Steele wrote:

> On Sep 7, 2022, at 1:41 PM, Brian Goetz 
> <brian.goetz at oracle.com<mailto:brian.goetz at oracle.com>> wrote:
> . . .
>
> Where we stumble is on method parameters, because method parameter 
> names serve two masters --
> the implementation (as the declaration of a variable) and the API (as 
> part of the specification of what the method does.)  Among other 
> things, we like to document the semantics of method parameters in 
> Javadoc with the `@param` tag, but doing so requires a name
>
> And a general language-design pattern is that if you discover a single 
> language feature is serving two masters, consider splitting it into 
> two features, one to serve each master (and then perhaps continue to 
> allow the old feature, explaining it in terms of the new, more general 
> features.
>
> In this case, a single feature (method parameter name) provides both a 
> name for the implementation and a name for the API. So, consider 
> having a way to provide two names. Common Lisp has been doing this for 
> its keyword parameters for almost four decades:
>
> (defun foo (&key ((:color c) white) ((:angle a) 0))
>    … c … a …)
>
> (foo :color black :angle 45)
>
> So the names :color and :angle are part of the API, and the names c 
> and a are the variable names that are actually bound for use in the 
> body.
>
> When you write
>
> (defun baz (&key (color white) (angle 0))
>   … color … angle)
>
> it is by definition an abbreviation for
>
> (defun baz (&key ((:color color) white) ((:angle angle) 0))
>   … color … angle)
>
> So you don’t have to write out two names in the common case where 
> you actually do want them to be “the same”.
>
> ————
>
> So in Java we could pick some crazy syntax to allow specifying two 
> names for a method parameter, the API name and the implementation 
> (bound variable) name:
>
> int colorHack(int red=>r, int green=>g, int blue=>b, int 
> fromIndex=>from, int toIndex=>to) {
> // Here the names `r`, `g`, `b`, `from`, and `to` are in scope.
> }
>
> and then if you really want to ignore a parameter:
>
> int colorBlindHack(int red=>_, int green=>_, int blue=>_, int 
> fromIndex=>from, int toIndex=>to) {
> // Here the names `from` and `to` are in scope.
> }
>
> Not sure we want to go in that direction, but we should at least 
> consider it.
>
> —Guy

As it happens, today I also cited Lisp argument syntax practice to 
Brian, on the subject of array patterns.  (As in, one bit of prior art 
for sequence matching is Common Lisp req/opt/key args…)

This is another bit of prior art from the same rather deep wellspring.

There is a proposed syntax which allows a single value to have two 
names, one of which is a binding, and that is the pattern-let syntax.

Perhaps a variation of pattern-let could make sense in parameter 
declarations.  (As many kinds of patterns might eventually be useful in 
parameter position.)  In this case, the binding is inside the pattern, 
such as `String s`, and the let-part is after an equals sign, `let 
String s = expr`.  (Bikeshed still to be painted here.)  Aligning with 
the need for a double declaration, we could say that the `expr` part is 
the formal and external name of the parameter, and the `s` part is the 
local and internal name of the binding.  So:

int colorBlindHack(let int _ = red, let int _ = green, let int b = blue, 
…) …

Huh.  Looks too close to optional arguments for comfort.  And how would 
you combine it with optional arguments?

int colorBlindHack(let int _ = red = 0, let int _ = green = 0, let int b 
= blue, …) …

Oh well, it was a thought.

If we ever do go with keyword-based calling conventions in Java, then 
there will be significant pressure for such double names, as there was 
in Common Lisp.  Until then, the double naming seems to me to be a 
corner-case feature.

Adding immutable structs (value classes) into the language does, in 
fact, increase the need for keyword-based conventions, so that you can 
*update* an immutable instance by combining a pre-existing instance with 
one or more field values to update.  (I like to call such a factory 
method a “reconstructor” because of its similarity to a constructor, 
which disregards any previous state and sets *all* the fields.)  If we 
add reconstructors to the language, there is new pressure for 
keyword-based calling conventions, and after that, there is pressure for 
the “double naming” of parameters.

— John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20220907/5dfe7781/attachment-0001.htm>


More information about the amber-spec-observers mailing list