[patterns] Destructuring without matching?
Remi Forax
forax at univ-mlv.fr
Fri Jul 7 19:59:51 UTC 2017
Hi Tagir,
----- Mail original -----
> De: "Tagir Valeev" <amaembo at gmail.com>
> À: amber-dev at openjdk.java.net
> Envoyé: Vendredi 7 Juillet 2017 17:21:28
> Objet: [patterns] Destructuring without matching?
> Hello!
>
> Sometimes it's reasonable to deconstruct the object of known type. A
> classical example is Map.Entry. E.g. currently I can write:
>
> // Map<String, Integer> wordCounts
> wordCounts.entrySet().stream()
> .filter(e -> e.getValue() > 10)
> .map(e -> e.getKey()+": "+e.getValue())
> .forEach(System.out::println);
>
> It's desired to refer by concrete name to key and value like this:
>
> wordCounts.entrySet().stream()
> .filter((_, count) -> count > 10)
> .map((word, count) -> word+": "+count)
> .forEach(System.out::println);
>
> Of course such syntax is not possible. Reading pattern matching proposal I
> thought whether it could solve this somehow. I see these alternatives:
>
> wordCounts.entrySet().stream()
> .filter(e -> e matches Entry(_, count) && count > 10)
> .map(e -> e matches Entry(word, count) ? word+": "+count : null)
> .forEach(System.out::println);
>
> Or
>
> wordCounts.entrySet().stream()
> .filter(e -> exprswitch(e) {case Entry(_, count) -> count > 10; default
> -> false;})
> .map(e -> exprswitch(e) {case Entry(word, count) -> word+": "+count;
> default -> null;})
> .forEach(System.out::println);
>
> In the latter case default branch is redundant as we know that e is always
> an Entry. Probably compiler could figure out this as well and do not
> require default branch? In this case exprswitch will have only one branch
> and looks too verbose.
yes, the compiler can figure that you do not need a default branch.
But for what you want you do not need to match/switch on things, you just want destructuration.
I think it's better to have a new operator, let call it 'let' that does the same destructuration that the pattern matching does,
wordCounts.entrySet().stream()
.filter(e -> let (_, count) = e; count > 10)
.map(e -> let(word, count) = e; word+": "+count)
.forEach(System.out::println);
and given that we already have a way to support string interpolation in the JDK (StringConcatFactory),
you can even add String interpolation in the mix,
wordCounts.entrySet().stream()
.filter(e -> let (_, count) = e; count > 10)
.map(e -> let (word, count) = e; ''$(word): $(count)'')
.forEach(System.out::println);
(you need a way to said that a String is interpolated, i've chosen '' (quotequote) which is close to " and currently invalid)
and with values types (thus tuples), you can write it that way,
wordCounts.entrySet().stream()
.map(e -> let (word, count) = e; (word, count))
.filter((_, count) -> count > 10)
.map((word, count) -> ''$(word): $(count)'')
.forEach(System.out::println);
regards,
Rémi
> Tagir Valeev.
More information about the amber-dev
mailing list