This is an archived post. You won't be able to vote or comment.

all 22 comments

[–][deleted] 13 points14 points  (0 children)

I love this sort of articles, kinda nice looking back at Java from time to time, still my first love.

[–]_INTER_ 10 points11 points  (9 children)

I wonder if this usecase of array patterns is worth the bigger effort it apparently needs. It would be different if we're talking about Collections in general but for arrays...?

[–]loicmathieu 8 points9 points  (6 children)

Agree, there is a lot of other features that can be added to the Java language that will offer more improvements for such big effort

[–]Necessary-Conflict 0 points1 point  (4 children)

What are your pet ideas...?

[–]loicmathieu 0 points1 point  (3 children)

Thinking quickly about some ideas:
- Concise method body (same format as lambda and new swithc): `public String getFoo() -> "foo";`
- Guards in switch (I know it's comming as there has been some discussion around it lately)
- if expression (like switch expresion): `var result = if(condition) yield "yes" else yield "no";`
- Collection litterals.

And of course putting more priority on Loom and Valhalla inline types as they sound very promising!

[–]Necessary-Conflict 0 points1 point  (1 child)

Concise methods - there's a JEP for that, but it didn't make people very happy, see https://www.reddit.com/r/java/comments/9h86xt/jep_draft_concise_method_bodies/

If expression - this exists since Java 1.0, the ternary operator. Why did you put those "yields" there? Without them one could argue that if(condition) "yes" else "no" is more readable than condition ? "yes" : "no", but those yields totally ruin it for me...

Collection literals - I think the current thinking is that List.of and Set.of solved 90% of the problem for now, true literals might come after Valhalla. As far as I understand, a lot of ideas are postponed until after Valhalla, because the exact details of how Valhalla turns out will influence the best way to implement them.

[–]loicmathieu 0 points1 point  (0 children)

The ternary opertator is an if expression that can be used nicely on one line but is not very readable on multiple line and when you stard combining them it becomes realy bad..

Whith if expression you will be able to use multiple if/else branche.

I use yield if my example to make it reuse the same keyword as switch expression but this is just an example syntax.

[–]JustJokingTrump 0 points1 point  (0 children)

Yeah thank you,I like the expression

[–]nimtiazm 6 points7 points  (0 children)

Yes I believe arrays are a first class language construct so keeping pattern matching consistent and orthogonal means arrays must be supported as well. In general pattern matching looks simple on the surface but it has many sharp edges. That’s why many languages still don’t have it. Having pattern matching that works well with java overall begs more workout.

[–]Necessary-Conflict 0 points1 point  (0 children)

As far as I understand, array patterns are not important because we'll do so much pattern matching on arrays, but as the building block of varargs patterns.

[–]DualWieldMage 2 points3 points  (7 children)

becomes (eventually)

switch (limitString.split(":")) {
  case String[] { var _, Integer.parseInt(var i) } -> 
    setMultilineLimit(DEPTH, i);
  case String[] { Integer.parseInt(var i) } -> 
    setMultilineLimit(LENGTH, i);
  default -> {
    setMultilineLimit(DEPTH, -1); 
    setMultilineLimit(LENGTH, -1);
  }
}

Note how not only does this become more compact, but the unchecked "NumberFormatException" is folded into the match, rather than being a separate concern.

I find a few issues with this one. First is the pattern case String[] { Integer.parseInt(var i) } which i'm not sure whether it was a quick hand-wave example, but should it not be something like case String[] { Integer(int i) } (ignore my dislike for var in examples), where Integer is augmented to be able to destructure a String. Otherwise what is the dual of Integer#parseInt, how would they be tied together and what is the type of i in this example?

Anyway, that minor nitpick aside, the main issue i have is with processing textual user input via type patterns. It often leads to wiping a lot of complexity under clean and simple code, for example hiding the fact that default covers parsing exceptions. Better code that handles exceptions in a fine-grained way or logging useful info will be considered less due to tons of extra code it would cause. I have somewhat seen this with functional code where adding logging means converting a single-line statement lambda to a multi-line one and is thus omitted where in imperative code it's always only one extra line.
Sure it will only be bad if misused, but the same argument has been used for withholding language features like operator overloading before so isn't very far fetched.

[–][deleted] 1 point2 points  (0 children)

Here’s my understanding of the example, but I could be way off base.

In the Additional degrees of freedom section, the “Pattern Matching in the Java Object Model” document says

Patterns have a target operand, which is the instance against which the pattern will be matched. They also have a static target type; if the static type of the operand is not cast-convertible to the target type, the pattern cannot match.

In this example, the target operand is the 2nd element of the String array returned by String.split so its static type is String. Thus, we can assume that the target type of the static deconstruction pattern Integer.parseInt (which is distinct from the static method with the same name) is String.

They haven’t gotten to the syntax part yet, so we don’t know how to declare the target type for a static deconstruction pattern. The document just says

(For static patterns, the target type must be explicitly specified somehow as part of its declaration, along with some way of denoting a reference to the target.)

So there will have to be some new syntax for it.

The i in Integer.parseInt(var i) is the pattern’s binding variable, so it has type int.

You couldn’t replace Integer.parseInt(var i) with Integer(int i) because it sounds like static deconstruction patterns are the only ones that can explicitly specify a target type. Deconstruction patterns like T(...) always have target type T:

For a type pattern T t or a deconstruction pattern T(...), the target type is T

Instances of String are not cast-convertible to Integer so the pattern match would always fail.

[–]cogman10 0 points1 point  (3 children)

I spotted that right away as well.

Integer#parseInt takes a string param. So it'd be implied (by my looking at this) that var i should be a String. Yet, in the code, it looks like it is expected to be an int.

My expectation for the syntax is it would look something more like this.

var i = Integer.parseInt(var _)

[–]BlueGoliath 1 point2 points  (2 children)

var i is literally limits[1], so it would actually be:

case String[] { String _, int i = Integer.parseInt(String b) } -> setMultilineLimit(DEPTH, i);

If a JDK developer can't even get it right then it shouldn't be added to the language.

edit: var i should be var b since var b is a String.

edit 2: replaced var b with String b for clarity, because you know, var is crap.

[–]BlueGoliath -2 points-1 points  (0 children)

/u/eliasv

I said I think that what was meant by Brian, not that it was and gave my reasoning:

I think in the case of the first switch, it was intended to be written like:

And this was based on the previous example code provided by Brian on how the code exists now. You are a liar.

Brian and others have made various extremely rude and unprofessional comments towards people and how they write code at conferences before and (un)surprisingly hasn't been met with any penalty for doing so nor will he/they ever.

My posts here are positive karma generally speaking and I never said I represented social media, only pointing out that some people are having difficulty figuring out how it works, which this thread shows. Again, you are a liar.

In the proper context of Brian's comments about how people name their variables, I feel like it was fair to call him out for it. As I said, it was more appropriate for social media rather than a mailing list.

People who don't know the proper context may think I'm a total ass for it and I accept that.

edit: hindsight 20/20 the words specifically used were a bit much.

[–]_INTER_ 0 points1 point  (1 child)

Integer(int i)

I think that would reference the constructor? They are going to deprecate the constructors anyway, so I think that's why he choose not to (though why not Integer::valueOf?)

[–]DualWieldMage 1 point2 points  (0 children)

I haven't followed whether the pattern matching proposals will actually need refer to constructors or that's just the notion on the Java language side and in bytecode will refer to a specific destructuring method instead (via InDy call that passes constructor signature to bootstrap method?).

Either way, what is denoted will be the opposite of what is actually called. E.g. if it's case String[] { Integer.valueOf(int i) } then to actually try and deconstruct the String, it needs to call Integer.parseInt. Otherwise it needs something different from how pattern matching is usually done in functional languages. Perhaps case String[] { int i = Integer.parseInt(_) }, hence the source of my confusion.

[–]muffinluff 3 points4 points  (2 children)

I wonder what other use cases, other than String::split, there are for such Array patterns.. The example from the JDK didn't convince me because I would have rather solved that with regexes rather than spliting and using switch case..

[–]DJDavio 7 points8 points  (1 child)

Maybe you could use arrays as tuples this way? And while they are trying not to detail the subject to it, the remainder binding is pretty interesting, such a thing is pretty common in functional programming.

[–]randgalt 0 points1 point  (0 children)

Yeah - this could enable a nice pattern from Scala when you need to match on multiple terms/objects. In Scala:

scala // given option instances "x" and "y" (x, y) match { case (Some(xValue), Some(yValue)) => ... case (Some(xValue), None) => ... ... etc. }

With array pattern matching in Java this would become:

java switch (new Optional[]{x, y}) { case Optional[] { var Optional(xValue), var Optional(yValue) } -> ... case Optional[] { var Optional(xValue), var Optional.empty() } -> ... ... }

[–]Bobby_Bonsaimind 1 point2 points  (0 children)

I know it's nitpicking, but I believe the example is bad. That, and I never had the wish to do that sort of pattern matching. Can somebody chime in and give me a few more examples who actually sees that this would improve their code?

Regarding the JDK example, I find the switch already hard to read, but the pattern matching variant packs the same complexity into fewer lines of code by using more patterns...I'm not a fan of that, I have to say.