Some thoughts on Member Patterns as parser developer

Olexandr Rotan rotanolexandr842 at gmail.com
Fri Apr 26 19:00:02 UTC 2024


I read through some messages about member patterns design and accumulated
some thoughts to share.

It happened so that all of my recent projects were linked to parsing some
data:equations, java statements etc., so I have been on close terms with
switch statements during tokenization and syntax tree construction.

It is common practice in parser development to build either type
hierarchies. For older solutions, it is common to just informally "imply"
that one type of tokens is a subtype of another and use some field like
"kind" as a discriminator. The thing in common in both approaches, is that
one "state" of token or ex[ression could be not mutually exclusive to
another. Consider following:

Token
| - KeywordToken
| | - ExtendsToken
| | - SuperToken
| | ....
| - LiteralToken
| | - NumberToken
| | - StringToken
...
Also, we have some factory that receives String and returns token:
class Tokens {
         Token parse(String s) { .. }
         static case pattern parseKeyword(String s) { .. } // hope I
understood syntax correctly
         static case pattern parseLiteral(String s) { .. }
         static case pattern parseNumberLiteral(String s) { .. }
}

Now, somewhere in the processing pipeline, I decided to use member pattern
matching:
switch (str) {
          case Tokens.parseLiteral(String literalStr) -> ...
          case Tokens.parseKeyword(String kwdStr) -> ...
          case null -> ...
}

At this point, all possible states are already exhausted. However, If i got
everything correctly, this won't compile, as the compiler still thinks
parseNumberLiteral is not exhausted, while effectively it is.

I think such situations could become pretty common. One solution I can
think of is to add an option to specify a supercase like  static case
pattern parseNumberLiteral(String s) extends parseLiteral { .. }.

This might seem weird, but, in fact, things like this have been here since
the first day of type pattern matching. case String effectively extends
case CharSequence and case Object, so I think enabling something like this
for custom cases would be reasonable.

Also, some cases could accept null as valid value. For example, modifying
Tokens class like so:
class Tokens {
         Token parse(String s) { .. }
         static case pattern parseKeyword(String s) { .. } // hope I
understood syntax correctly
         static case pattern parseLiteral(String s) { .. }
         static case pattern parseNumberLiteral(String s) { .. }
         static case pattern nullOrEmpty(String s) { ... }
}

Now, if we match Tokens.nullOrEmpty(String s), null is also exhausted.
Maybe there could be syntax like  static case pattern nullOrEmpty(String s)
covers null { ... } or something like this.

Moreover, null is a special value, so, if we assume there is a
nonNull(Object obj) pattern in Objects class, switch like this:
switch (someVar) {
           case Objects.nonNull(Object notNull) -> ...
           case null -> ...
}

is also exhaustive for any type.

That's my concern about this proposal. I really love this feature, I think
it could introduce a completely new way of writing code in Java. However,
to do so, I think something like this should be present to make pattern
matching as smart and flexible as possible.

Best regards
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240426/fad0ffd2/attachment-0001.htm>


More information about the amber-dev mailing list