Fwd: Comments/Feature Requests regarding JEP 305: Pattern Matching

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Jul 6 14:22:54 UTC 2017


Hi William,
what you are suggesting is essentially 'flow typing'. Kotlin achieves 
something very similar with 'smart casts' - see this discussion [1].

While I think flow typing is a reasonable alternative to nested 
patterns, I can't help note that your rewritten version of the code I 
gave is more verbose and indirect.

The fact that a pattern can introduce new variable bindings is certainly 
a novel element in Java - but it's not too different from what happen in 
other languages which support pattern matching (most notably Scala and 
C# [3]). As any language feature, it can be abused - and I buy the 
argument that some programs will make use of unnecessary bindings - but 
I think there are also programs which can be written a lot more nicely 
if patterns (esp. nested ones) can introduce binding variables.

Maurizio

[1] - 
http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-March/000006.html
[2] - http://docs.scala-lang.org/tutorials/tour/pattern-matching.html
[3] - https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching


On 06/07/17 15:10, William Shackleford wrote:
> ( The message below is being forwarded because just hitting reply before
> looks like it only went only to Maurizio Cimadamore )
>
>
> ---------- Forwarded message ----------
> From: William Shackleford <wshackle at gmail.com>
> Date: Thu, Jul 6, 2017 at 9:51 AM
> Subject: Re: Comments/Feature Requests regarding JEP 305: Pattern Matching
> To: Maurizio Cimadamore <maurizio.cimadamore at oracle.com>
>
>
>
>
> I like the guards but I would still like to avoid introducing new new
> variable names and keeping the syntax simpler.
>
> It would be nice if any expression of the form (x instanceof SomeType &&
> ((SomeType)x).field ...
>   where field is some field in SomeType but not in the original static class
> for x
>
>   could drop the unnecessary cast
>
> to be (x instanceof SomeType && x.field
>
> Then
>
> case AddNode(NegNode(IntNode(var n1)), IntNode(var n2)) && n1 == n2: ...
>
>
> would be this
>
>
> case AddNode
>          && n.left instanceof NegNode
>          && n.left.n instanceof IntNode
>          && n.right instanceof IntNode
>          && n.left.n.i == n.right.i :
>
>
> I think this makes it much easier to see all of the conditions that have to
> be true to match here.
> The same style could be used even if the classes were more general and the
> fields we needed had nothing to do with
> the constructor arguments.
> It doesn't require that I come up with any new variable names.
>
>
> -- Will
>
>
>
>
>
>
>
>
>
>
>
>
> On Wed, Jul 5, 2017 at 5:03 PM, Maurizio Cimadamore <
> maurizio.cimadamore at oracle.com> wrote:
>
>>
>> On 05/07/17 21:34, William Shackleford wrote:
>>
>> In addition to being more concise:
>>   n is not both used as the positive part of the NegNode and as the input
>> parameter.
>>
>> Note that this is likely to be a bug in the original example. It is not
>> possible for a pattern binding to 'shadow' a method parameter name.
>>
>> It works with classes that have more fields/methods than constructor
>> arguments.
>> It seems to me that is better to consistently use a single syntax style
>> rather than having one for classes
>> that have only one or two fields that happen to match the constructor
>> arguments and another more
>> general style. This is especially true given that it doesn't even seem to
>> make the code more concise.
>>
>> Generally what you say is true - in many cases you will be able to write
>> things even without nested patterns.
>>
>> It is very likely that at the very least we will add some support for
>> unnamed binding (with underscore '_' ) - in the spirit of unused lambda
>> parameters (see JEP 302 [1]).
>>
>> But where I think you reach the end of the road with that approach is when
>> matching arbitrary expressions. Let's say you want to 'simplify' an
>> expression - that is, given an input expression, you want to construct
>> another expression that is simpler than the one in the input, by
>> recognizing things such as:
>>
>> -N + N = 0
>> 0 + N = N
>> 0 * N = 0
>> 1 * N = N
>>
>> To recognize some of those cases, you need to build more complex patterns;
>> for instance, for the first case you need a pattern like this:
>>
>> case AddNode(NegNode(IntNode(var n1)), IntNode(var n2)) && n1 == n2: ...
>>
>> [sidebar: '&&  n1 == n2' is what we call a _guard_ - a binary expression
>> that further controls whether a pattern matches or not]
>>
>> Writing something like the one above without nested patterns would be
>> extremely hard - you could start by checking that the outermost expression
>> is an AddNode, as in your example, but then you would still need 2 dynamic
>> checks for the two nodes, and then a further dynamic check for accessing
>> the guts of the NegNode. In other words, getting at the two int values
>> would be extremely unpleasant and verbose w/o any support for nested
>> patterns.
>>
>> For simpler examples, I'm with you, simpler patterns might be just fine.
>>
>> Maurizio
>>
>> [1] - http://openjdk.java.net/jeps/302
>>



More information about the amber-dev mailing list