New pattern matching doc
Remi Forax
forax at univ-mlv.fr
Fri Jan 8 09:56:49 UTC 2021
For me, the introduction of pattern matching in Java comes from the fact that there is currently no proper way to do data encapsulation.
We have a strawman equivalent of pattern matching, use a cascade of ''if ... else" with getters/accessors.
Switching on patterns is a better way to write a cascade of if ... else, case methods are a better way to write getters/accessors.
Now some examples, again the syntax is not important, what's important is the coupling between a pattern and a case method.
The first one shows how to use a case method corresponding to what is called in the document a deconstructor that is thread-safe,
unlike if getters are used and it doesn't mirror a constructor, that why the term "deconstructor" is not something we should keep IMO.
public final class HonorBoard {
private String firstName;
private String lastName;
private final Object lock = new Object();
public void set(String firstName, String lastName) {
Objects.requireNonNull(firstName);
Objects.requireNonNull(lastName);
synchonized(lock) {
this.firstName = firstName;
this.lastName = lastName;
}
}
public case HonorBoard(String firstName, String lastName) {
// firstName and lastName are bindings here not argument
// TODO: find a better syntax
synchonized(lock) {
if (this.firstName == null && this.lastName == null) {
return no-match;
}
return match(this.firstName, this.lastName);
// here the mapping is done between this.firstName and the first binding
// and this.lastName and the second binding
}
}
}
It can be used that way
if (o instanceof HonorBoard(var firstName, var lastName)) {
...
}
Here is another example that propose a way to declare that several case methods are total using the keyword exclusive
(if one case method is marked exclusive, all case methods must be marked exclusive).
public final class MyNumber {
private final double value;
private MyNumber(double value, Void __) {
this.value = value;
}
public MyNumber(double value) {
this(value, null);
if (Double.isNaN(value)) {
throw new IllegalArgumentException("NaN is not a number");
}
}
public static final MyNumber NaN = new MyNumber(Double.NaN, null);
public exclusive case MyNumber(double value) {
if (Double.isNaN(value)) { // need to access to the instance field here
return no-match;
}
return match(value);
}
public exclusive case NaN() { // can the same name as a field
if (Double.isNaN(value)) { // need to access to the instance field here
return match;
} else {
return no-match;
}
}
}
It can be used that way
switch(myNumber) {
case MyNumber(var value) -> ...
case MyNumber.NaN() -> ...
}
Here a default is not required because the case methods are declared "exclusive".
We also need to discuss if a case method should declare itself as total, i.e can not return no-match or this is not necessary ?
Rémi
> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Mercredi 6 Janvier 2021 21:52:19
> Objet: New pattern matching doc
> I have pushed
> [
> https://github.com/openjdk/amber-docs/blob/master/site/design-notes/pattern-match-object-model.md
> |
> https://github.com/openjdk/amber-docs/blob/master/site/design-notes/pattern-match-object-model.md
> ]
> to the amber-docs repo, which outlines the direction for how patterns fit into
> the object model.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20210108/38edca3e/attachment.htm>
More information about the amber-spec-experts
mailing list