Pattern matching for nested List with additional size constraints
Brian Goetz
brian.goetz at oracle.com
Wed Jan 27 20:02:33 UTC 2021
Eventually, yes.
Your example wants to capture a number of conditions:
- the Profile contains a non-null Rules
- the Rules contains a non-null List<Rule>
- The List<Rule> is non-empty
- The first rule in the list is dynamic
Each of these conditions can be captured in a pattern, and the patterns
can be composed. Some of them can be handled by built-in patterns (type
and deconstruction patterns). Let me rebuild your hierarchy a little:
record Profile(Rules rules) { }
record Rules(List<Rule> rulesList) { }
record Rule(DynamicConfig dc, StaticConfig sc) { }
and let's assume that records already have deconstruction patterns. So
we can do the easy parts already with these:
if (p instanceof Profile(Rules(List<Rule> rulesList))
&& rulesList != null && rulesList.length() > 0
&& rulesList.get(0).dc() != null) { ... }
This means:
- If p is a Profile, and non-null, cast to Profile, and extract the
rules, and
- If the rules is a Rules, and it is non-null, cast to a Rules, and
extract the rulesList, and
- do the rest imperatively
Obviously, this only helps a little bit. What we need is a pattern that
matches lists, and then can further match on their elements. We have an
existing varargs list factory List.of(T...); imagine we will have a
varargs pattern that matches Lists and then matches nested patterns to
the list elements, and imagine that's called List.of() also. Then we
can eliminate the next two tests:
if (p instanceof Profile(Rules(List.of(var rule, ...)))
&& rule.dc() != null) {
use(rule.dc());
}
This means:
- If p is a Profile, and non-null, cast to Profile, and extract the
rules, and
- If the rules is a Rules, and it is non-null, cast to a Rules, and
extract the rulesList, and
- If the rulesList is a non-null List, cast to a List, get the length,
and it has a first element, get the first element, and bind the element
to `rule`, and
- do the rest imperatively
If you wanted to move all this into a pattern (say, so it could be used
in a switch), you can move the last condition into a guard:
if (p instanceof Profile(Rules(List.of(var rule, ...) &
false(rule.dc() == null))) {
use(rule.dc());
}
In the future, when you can declare your own patterns, you can do
better, by declaring a pattern in Rule that only matches rules with
dynamic configuration, and yields up the dynamic configuration:
if (p instanceof Profile(Rules(List.of(Rule.dynamic(var dc), ...))) {
use(dc);
}
So yes, we'll get there, but it will take a few iterations.
On 1/25/2021 5:58 PM, Swaranga Sarma wrote:
> Hello, I was going through some code in my work today and came across
> several similar looking cases and was wondering if pattern matching would
> be a more concise and cleaner way to pxress the logic.
>
> Here is a succinct class hierarchy that illustrates the example:
>
> class Profile {
> Rules rules;
> }
> class Rules {
> List<Rule> ruleList;
> }
> class Rule {
> DynamicConfig dynamicConfig;
> StaticConfig staticConfig;
> }
> class DynamicConfig {
> SomeProperty property;
> }
> class StaticConfig {
> SomeOtherProperty property;
> }
>
> With the above classes, we have a method "isDynamicConfigProfile" that
> determines if the Profile is a DynamicConfig profile. A Profile is
> considered dynamic if it contains a Rule with a non-null DynamicConfig
> member; also ALL the Rules of a profile can only contain one type either
> Dynamic or Static so checking just the first element in the ruleList is
> sufficient.
>
> The current code is implemented as:
>
> boolean isDynamicProfile (Profile profile) {
> return profile.rules() != null &&
> profile.rules().ruleList() != null &&
> profile.rules().ruleList().size() > 0 &&
> profile.rules().rulesList().get(0).dynamicConfig() != null;
> }
>
> Is the above method something that could be expressed with a switch and
> pattern matching; assuming these are converted to Record classes? Something
> like:
>
> boolean isDynamicProfile (Profile profile) {
> return switch(profile) {
> case Profile(Rules(Rule(DynamicConfig dc), Rule(var r2)...
> remainingElements)) -> true;
> default-> false;
> }
> }
>
> Is it even a valid usage of patterns? I think even the List interface would
> need to support pattern matching in this case.
>
> Regards
> Swaranga
More information about the amber-dev
mailing list