Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This is exciting, can't wait for the LTS release next year... that said, I don't much care for the "case SomeType t when ..." pattern matching syntax, I don't see the benefit of introducing a new keyword over using "if"... or even just "&&". To pinch the example used in[1]:

    case Tuner t && guitar.isInTune() -> ...;
and

    case Tuner t if guitar.isInTune() -> ...;
both seem as clear as

    case Tuner t when guitar.isInTune() -> ...;

...am I misunderstanding the reasoning here? Is it being introduced to keep the grammar definition simpler?

1: https://foojay.io/today/its-java-20-release-day-heres-whats-...



I work on Dart which is also adding pattern matching [1]. When we designed the syntax for guards, we also considered exactly these three choices before ultimately landing on "when" too.

Our main reasoning was:

"&&" is intuitive but it means that you can have a pattern that is immediately followed by an infix operator. That can be problematic if you ever want to make "&&" a valid pattern infix operator. And, in our case, we ended up doing exactly that, so "&&" would have been ambiguous. If you were to write:

    case foo && true:
Then it could be parsed as either a pattern that matches when the value is equal to the constant "foo" and is equal to the constant "true". Or it could be parsed as a pattern that matches when the value is equal to the constant "foo" followed by a pointless guard that always succeeds.

"if" is nice because it's already a reserved word and the semantics are pretty obvious. But in Dart, an if statement always has the condition in parentheses. Those are pointless in a pattern since we already have another explicit delimiter separating the guard from the case body:

    case foo if (condition):
    //                     ^
We could say that the if condition in a guard doesn't need parentheses but if conditions elsewhere do. But that's likely just an annoying footgun where users will write them unnecessarily (but harmelessly at least) in guards and forget them in if statements and get compile errors.

If Dart didn't require parentheses around if conditions, we probably would have used "if" for guard clauses to (like Scala and Rust do).

So we tried "when" and most users and team members seem to like it. Syntax design is a human-centered process so often the right answer is just what feels right to the most people.

[1]: https://github.com/dart-lang/language/blob/master/accepted/f...


Gotta say I'd've taken the if with parentheses myself. Feels like it's reusing something familiar even if they are extraneous at times.


That was my initial pitch too. But after months, almost no one seemed to have warmed up to it. When we changed it to "when", just about everyone seemed to like it better.

Syntax design is weird. Sometimes the only way to tell if I did it right is when no one says anything. People complained when I used "if". No one did after I switched it to "when". <shrug>


It’s always bugged me when syntax selection is done by popular vote. The most frequent vocal complaints tend to be from people who just have to adjust to something new. But if you only ever show a user what they’ve already seen, you inhibit the ability to innovate / try new things.

The flip side is that it also bugs me when language / library designers make weird choices that don’t seem to have a compelling reason (or at least the compelling reason for the difference doesn’t outweigh the cost of being different).

No win situation ultimately except to figure out who has good language tastes and weight their feedback more, but that’s subjective and something people try to avoid, ignoring that they’ve already done this by virtue of limiting who the experts are working on it in the first place.


> if you only ever show a user what they’ve already seen

Familiarity and intuitive structure in a low context language is very important. A language syntax is for humans to comprehend. If a new syntax is under discussion, it's probably around new functionality (or sugar). Where is "encourages innovation" in the list of reasons to use any specific syntax? I would say, far down on the list.


Thank you, that's excellent insight into the thought process for the same feature at about the same time.

You mention about the human-centred nature of syntax design... do you have any instinct for why one route vs another felt right to users? Do you feel like you've developed a better instinct for this over time, or is it still hard to predict what will feel natural to users?


> do you have any instinct for why one route vs another felt right to users?

That's a good question. It is something I spend a lot of time thinking about when I see how users react to a design. In this case, I don't think I have a good answer as to why "when" seemed to go down easier than "if".

> Do you feel like you've developed a better instinct for this over time, or is it still hard to predict what will feel natural to users?

I'd like to believe so, but "if" was my first pick, so I guess not. :)

I think what our team does have now that really helps is better processes to evaluate a design, talk about it, get feedback from users, and incorporate that feedback into the design. It's all pretty informal, but I think we're iteratively able to get designs users seem to like.

But it's always really hard. There are so many trade-offs and users have different preferences and expectations, so finding the right balance is always difficult. I think that's why it's so endlessly fascinating to me: you can never fully "solve" syntax design.


As a big Dart fan I would say it’s actually in no small part to how the core language team works. Really good mix of thoughtfulness and pragmatism.


C# ended up with `when` for guards as well, a couple years ago :)


Very excited to hear this, if true, I will pick up Dart & Flutter again after this is released.


It's very true. If you build the bleeding edge Dart SDK yourself, it's already turned on. It will be enabled in the next upcoming beta release.


The “&&” one is bizarre, it makes it look like the whole thing is a Boolean expression, which it absolutely is not. That gets even weirder because the part right of it actually is a Boolean expression, so on top of very confusing reading you now make it look like there are strange interactions with operator precedence. Using && is one of the worst choices.

The “if” one does not suffer from any such problem and reads okay to me. I guess one argument against it could be that since the whole thing is a distinct grammatical construct, why not just introduce a distinct keyword instead of making an existing keyword depending on context? That’s mostly a question of style though (e.g. I don’t know right now if Java already has an habit of reusing keywords like that).


As another comment mention, they did use && in the 2nd preview, but then switched it, so you're right, it must have been confusing.

FWIW, though, I don't find it "bizarre". While it's not a boolean expression per Java, at least in my mind it serves the same purpose: "in the case that thing x is of type SomeType and ...some other thing about ((SomeType)x) is true...".

I think it's a tough choice, I'm sure they were probably not wanting to add a new keyword, but at the end of the day "when" is so familiar to anyone who's ever written SQL (which I'm guessing is most Java devs) so seems like a good choice.


> While it's not a boolean expression per Java, at least in my mind it serves the same purpose

But if some construct looks the same, but is not the same, and worse, only "somewhat" the same, you get confusing behavior. At least for newcomers, or even just software engineers who just don't care about language grammar that deeply (which I imagine are not only a lot, but also a lot of the Java target audience specifically).

Case in point, the author I was replying to wondered in a followup whether && would/should still act like a shortcut-and operator would, or not.

There is definitely some subjectivity to it, but personally I much prefer if different constructs look clearly different. Any ambiguity is squashed immediately, and in the case of "when" it's still fully clear how it works. I'm also okay with the "if" variant, because while it reuses a keyword, it's clearly a different "if".


The "&&" approach is how you express that same logic in an if statement in Java today.

Given this pattern matching syntax change, you'd write:

    switch(obj) {
        case Tuner t when guitar.isInTune() -> ...;
        ...
    }
For a switch, but for an if statement it's written as:

    if (obj instanceof Tuner t && guitar.isInTune()) {
        ...
    }

Edit: I do wonder, actually, if avoiding "&&" is to allow the "when" case execution to be reordered (e.g. to allow JIT to extract common "when" conditions prior to the switch expression), which would be wrong to do given the short-circuiting rule implications of "&&"


I'm not a Java user, but I really don't love the overloading of `if` in Python (statement, ternary, comprehensions), so introducing a new keyword here seems pretty reasonable to me.

And don't even get me started on `static` in C++.


OK, no static then, but what about if constexpr (...) ? :D


Also `if consteval {...}` in C++23. But really "if" still semantically means the same thing in all of these. Unlike "static", which is all over the place.


And then there's "static constexpr" (which is only used in places where non-static constexprs are illegal). An overloaded keyword that's become so overloaded, it's even used in places where it's completely unnecessary! :-P


I think Rust uses "if" for its match guards too and I don't recall it upsetting anyone. I'm all for keeping things consistent between languages if only to prevent too much bike shedding.


Rust's if never needs parentheses, so their absence in a match guard is unremarkable, whereas in Java that's incongruous one way or the other.


I think the only reason is that they're very different, if you define them:

    type when expression -> block

    if expression -> block
For parsing works better, for programmers is better since they don't confuse both concepts, and in general pattern matching isn't the same as a if condition or a switch.

https://stackoverflow.com/questions/199918/explaining-patter...

I think the difference is when you start pattern matching on tuples and other types that you cannot do a simple `if ident.isinstanceof(type) ->`.

For example in Elixir you can do:

    def ident(param = {:key => true}):
This will only match when the param type is not only `map`, but also contains a key named `:key` and its value is `true`.

In the end though, it's syntax sugar (but everything is if you put it that way classes are syntax sugar).


In 2nd preview, they used &&: https://openjdk.org/jeps/420

At 3rd preview, they switched to when: https://openjdk.org/jeps/427

In that JEP they state:

> Based upon experience and feedback we propose instead to allow when clauses in switch blocks to specify guards to pattern labels

So I assume people thought && was confusing.


In the case of &&, the left hand side of the expression (Tuner t) isn't a boolean expression.

In the case of "if", you're right, the grammar doesn't work, both because the syntax of Java already says that the if condition must be enclosed in parentheses and also because an if block is a statement and you need an expression here.

To make either of those work, you'd have to make the rest of the pattern matching syntax much worse.


The “&&” one is super confusing indeed, but the “if” one is just a question of style. It would be possible to reuse the “if” keyword for different grammar. python does it for its trinary operator, where there is an expression instead of a statement after “then” (e.g. “foo = if bar then 1 else 2”), but if Java does not have the same habit of reusing keywords already (not sure), it might not want to start now for consistency.


Java has two gramatically different forms of "try" in a similar fashion (one with parantheses and one without), I don't think this would be any worse than that.


Agreed. I guess "when" just reads a little bit better (english-wise), then.


This year. Six months from today.


(just on the following up on this)

https://en.wikipedia.org/wiki/Java_version_history

The non-LTS releases are every 6 months and have support for one year.

LTS releases are every 4th release which falls on odd numbered years in September.


> The non-LTS releases are every 6 months and have support for one year.

Not exactly, they are supported for 6 months (well, till the next JDK release) at least the builds on jdk.java.net page. Other vendors might provide different support.

Azul for example supports some releases (13 and 15) for 3.5 or 2.5 years (MTS)


Oh really? Sweet. It’s only relatively recently I’ve been able to use Java 17 everywhere (there were straggler codebases).

And now I’ll get 21 soon? Awesome.


Maybe they got inspired by C#?

var favoriteTask = obj switch

{

  Developer dev when dev.YearOfBirth == 1980 => $"{dev.FirstName} listens to metal",

  Developer dev => $"{dev.FirstName} writes code",

  Manager _ => "Create meetings",

  _ => "Do what objects do",
};


they want it to be as ugly as cpp


Maybe so, but please don't post unsubstantive and/or flamebait comments to Hacker News. We're trying for something different here: https://news.ycombinator.com/newsguidelines.html.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: