AW: Compact deconstruction patterns

Matthias Perktold tias251 at gmail.com
Wed Mar 4 08:18:33 UTC 2020


Thank you all for entering into this discussion.

> > This has come up a few times.  There are several reasons to prefer the current approach, most of which stem from the prime directive, “reading code is more important than writing code.”  The argument for the compact version is really “I can do less typing”, which is a relatively weak motivation when the typing we are saving is the three characters v-a-r.

> For me, this argument doesn't sound convincing. The problem is exactly with reading: you have to read all these noise var's, this makes lines longer for no big reason, your eyes need to make more horizontal movements. The deconstruction (especially the nested one) might include many fields, so it's not just four characters (var + space), but four times the number of pattern variables (16 in the example supplied by Matthias). Also, don't forget about visually impaired (not totally blind) people who set very big editor font having much fewer symbols fitting the screen horizontally.

I think the same way.
Yes, you would type less characters, but you would also save reading them.
Because once you understand that this is a pattern, `var` doesn't add any information, and neither does having it multiple times.

>
> These are variable _declarations_, and variable declarations should 
> look like declarations.  `int x` and `var x` look like declarations; 
> `x` looks like a use of an existing variable.  (You might point out 
> that we do a similar thing in lambdas, where we use an unadorned name, 
> but the -> token is is a very, very strong indication that these are 
> formals.  I don’t think that justification is in play here.

Indeed, that's the question here.
I'd say a switch expression is also a strong indication, as it spans multiple lines, with each pattern at the beginning of a new line, right after `case`.
Patterns used with `instanceof` are probably harder to spot, especially when combined with other expressions using `&&` or `||`.

On another note, I see other languages like Haskell or Scala do allow deconstruction patterns without indications like var.
That's not to say Java has to do the same, but it shows that this approach can work quite well.
At least I never heard that it's hard to tell whether a symbol is referring to an existing variable or declaring a new one.

Again, a deeply nested `instanceof` might make things harder in Java.
On the other hand, declaring new variables in such a place is probably a bad idea per se, whether you use var or not.
Compare
  if (someFlag && p instanceof Point(var x, var y) && anotherFlag) { ... }
With
  if (someFlag && p instanceof Point(x, y) && anotherFlag) { ... }

Here, I would prefer the version with var, but neither is really satisfactory.

> Note too that in lambdas you can say `(var x) -> …` now, and if we had `var` in 
> the language when we did lambdas, we might well have not even 
> supported the more compact `(x,y) -> …` form at the time.  So rather 
> than this being a precedent to emulate, we might choose to view it as 
> a historical inconvenience.)

My proposal is exactly to allow the same kinds of declarations in deconstruction patterns as in lambda parameters.
This way, you would not only save typing and reading, but also increase consistency of the syntax.

It's interesting that you now seem to favor `(var x) -> ...` over `x -> ...`.
Honestly, I would never write a lambda with var, and probably remove the var if I would see one in my codebase.
I always thought the reason that you can now use var in lambdas is again consistency, as well as being able to put annotations on lambda parameters without explicitly providing their type.
Other than that, var is pretty useless here, so I'm glad we didn't have var at that time. ��

> Further, down the road, we intend to have patterns that can actually take input arguments, such as `regex(“a*b*” …)`.  (Please, no syntax bike shedding on this now.)  This creates the possibility where the `x` in `Foo.bar(x)` could either be an input parameter, or a constant pattern, or a fresh binding variable — this is asking a lot of readers.
> In the end, it comes down to: there is a benefit to being explicit (easier to spot declarations), and an additional cost to being implicit (potential for ambiguities down the road.)  The benefit for being implicit is saving the typing of three characters.  This seems a pretty easy decision.

This is interesting, thanks for sharing.
With this in mind, I can better understand your point of view.
Maybe the best strategy is to require at least var for the moment and pick up the discussion once there is a clear understanding which kind of patterns are going to be supported in the future.

Thanks,
Matthias



More information about the amber-dev mailing list