Re: [External] : Re: Guards redux

2021-03-12 Thread Gavin Bierman


> On 12 Mar 2021, at 11:02, Remi Forax  wrote:
> 
> - Mail original -
>> De: "Gavin Bierman" 
>> À: "John Rose" 
>> Cc: "amber-spec-experts" 
>> Envoyé: Vendredi 12 Mars 2021 11:11:46
>> Objet: Re: Guards redux
> 
>> Thanks everyone for the discussion. I have updated the JEP:
>> 
>> http://openjdk.java.net/jeps/8213076
>> 
>> It proposes *guarded patterns* of the form `p&&e`, as well as parenthesized
>> patterns, written `(p)`.
> 
> 
> Hi Gavin,
> nice, i find this version more appealing.

Yay!

> In the first example that shows && as a guard, the example uses parenthesis 
> which is my opinion should be removed
>case Triangle t && (t.calculateArea() > 100) -> 
>System.out.println("Large Triangle"); 
> 
> if i read the grammar correctly, those parenthesis around the boolean 
> expression are unnecessary
>case Triangle t && t.calculateArea() > 100 -> 

They are unnecessary, but this example comes before the grammar, so I didn’t 
want anyone to get confused. 

> 
> it will be more inline with the example above in the text that is using 'when'
>case Triangle t when t.calculateArea() > 100 ->
> 
> 
> Otherwise, in the document, the words "->-style" and ":-style" are hard to 
> parse, i think array-style and colon-style are better terms.

I’ll take a look.

> In the section "Dominance of pattern label",
> It's not clear to me if there is a dominance in between expressions,
> by example, can we have the following cases in that order ?
> 
>  case Foo(var a, var b) && a == 3:
>  case Foo(var a, var b) && a == 3 && b  == 4:
> 
> for me the answer is yes, the dominance is computed on patterns only, not on 
> expressions.

I agree. I don’t think trying to calculate dominance between expressions is 
viable. 

Thanks Rémi!
Gavin

Re: [External] : Re: Guards redux

2021-03-10 Thread John Rose
On Mar 10, 2021, at 11:10 AM, Guy Steele  wrote:
> 
> But in principle it does matter for patterns, because while patterns arguably 
> do not involve _evaluation_, they most certainly involve _execution_ of 
> possibly user-written code.  If side effects can occur, the distinction 
> arguably matters, and this is worth recognizing as we debate the design.

I don’t think user-written patterns can reliably exclude
side effects, and I think in some cases they will be useful
(to accumulate some sort of “log” on the side of matching
activity, perhaps to support backtracking).

So let’s say that one way or another we have to specify
ordering of side effects patterns.  (Eww:  What about
class loading side effects for resolved class names?
Do we have to package type names in thunks for
the pattern runtime?  Please, no.)

Given nested patterns P(Q,R), if P fails then there’s no way
to execute Q.  If Q fails there’s no benefit to executing R,
although that would be possible to more closely emulate
unconditional evaluation of function parameters.  Is
there any reason to do this?  I think not.  And then
P(Q & R) also has no reason to execute R if Q fails.

As I said to Remi, importing unconditional evaluation
rules from expressions into patterns makes no sense.

As Brian said, pattern-& is as similar to type-&
to expression-&.



Re: [External] : Re: Guards redux

2021-03-10 Thread Guy Steele


> On Mar 10, 2021, at 12:04 PM, Brian Goetz  wrote:
> 
> 
> 
>> You nail the guard to a pattern, which is equivalent until we have nested 
>> patterns (and "or"/"and" patterns).
> 
> We have nested patterns already in the JEPs on the table.  Where's the 
> problem?
> 
>> I see a lot of advantages of using && to link a guard to a pattern,
>> - the symbol is heavy so there is a clear visual separation
>> - without any supplementary parenthesis, && after the type pattern in an 
>> instanceofis the && between expression, it's almost like you can not have a 
>> guard with an instanceof, in practice, few instanceof will have a guard.
> 
> I agree few instanceof will have a guard, but users are still free to express 
> it that way if they like, and there's nothing wrong with that.  
> 
>> I still think that using a guard inside a nested pattern is ugly but it can 
>> be just that, ugly. Someone may want a short-circuit in a deeply nested 
>> patterns .
> 
> Yes.  This is not unlike other compositions; for any compositional tool, you 
> can overuse it.  (You can arbitrarily compose boolean expressions (or 
> arbitrarily chain method invocations), but sometimes this is taking it too 
> far.)  
> 
>> As i said to Gavin, i'm not at ease with using the symbol '&' in between 
>> patterns.
> 
> I think that this is mostly a "who moved my cheese" reaction; you're used to 
> thinking that & is just for bitwise operations.  But, that's not actually 
> true; we already use & and | on types -- intersection type casts, additional 
> generic type bounds, multi-catch.  This appeals to a notion that & and | are 
> boolean-like combinators on types (even if not exposed in all places they 
> might make sense), but this is a different kind of combination than on 
> integers.  And yet a different kind of combination on patterns.  (In an 
> alternate universe, we might have different symbols for adding ints vs floats 
> vs string concatenation, but + works well enough that overloading the symbols 
> is OK -- because using + in this way appeals to the underlying algebraic 
> monoid structure these types share.)

We all know that `+` is not your best poster child for this argument.

(“foo” + 1) + 2   produces   “foo12”
“foo” + (1 + 2)   produces   “foo3”

which is not my idea of good monoid behavior.  But there is a lot of wiggle 
room in your use of the word “appeals”.  :-)

> The reason that & and | make sense on patterns, and on types, is that, like 
> the more familiar versions on bits, they describe a _boolean algebra_.  
> Boolean algebras have familiar properties such as De Morgan's Laws.  These 
> work for types (when interpreted as value sets) as well as bits, and they 
> work for patterns too.  
> 
> I think where you're getting hung up is that when patterns produce bindings, 
> and other patterns consume those bindings, we have a dataflow dependence 
> which would appear to undermine certain other expected properties of a 
> boolean algebra, such as commutativity.  But, if we view those dataflow 
> dependencies as a separate constraint -- as we *already do* for ints (e.g., 
> `(x=3)&(x|4)`, is invalid when `x` is an DU int, but valid when `x` is DA), 
> this seeming contradiction vanishes, and is seen to be merely a post-hoc 
> well-formedness constraint.  If the WF constraint is satisfied, the expected 
> properties of boolean algebras (associativity, commutativity, absorption, 
> etc) are satisfied too. 

And yet, even if we stipulate all that, it is still the case that in 
expressions, Java uses `&&` to indicate short-circuiting and `&` to indicate no 
reliance on short-circuiting, and this is long-standing, familiar use.  For the 
other applications cited (intersection type casts, additional generic type 
bounds, multi-catch) this distinction does not matter.  But in principle it 
does matter for patterns, because while patterns arguably do not involve 
_evaluation_, they most certainly involve _execution_ of possibly user-written 
code.  If side effects can occur, the distinction arguably matters, and this is 
worth recognizing as we debate the design.

Nevertheless, as I just wrote in an earlier email, I think that the desire to 
maintain this distinction should be outweighed by other considerations (visual 
analogy to type intersection, for which `&` is used but not `&&`; need for 
distinct symbols for pattern conjunction action and guard attachment in order 
to solve parsing problems; desire not to invent an arbitrary new symbol such as 
`&:` or `&&&`).




Re: [External] : Re: Guards redux

2021-03-10 Thread Brian Goetz



You nail the guard to a pattern, which is equivalent until we have 
nested patterns (and "or"/"and" patterns).


We have nested patterns already in the JEPs on the table.  Where's the 
problem?



I see a lot of advantages of using && to link a guard to a pattern,
- the symbol is heavy so there is a clear visual separation
- without any supplementary parenthesis, && after the type pattern in 
an instanceofis the && between expression, it's almost like you can 
not have a guard with an instanceof, in practice, few instanceof will 
have a guard.


I agree few instanceof will have a guard, but users are still free to 
express it that way if they like, and there's nothing wrong with that.


I still think that using a guard inside a nested pattern is ugly but 
it can be just that, ugly. Someone may want a short-circuit in a 
deeply nested patterns .


Yes.  This is not unlike other compositions; for any compositional tool, 
you can overuse it.  (You can arbitrarily compose boolean expressions 
(or arbitrarily chain method invocations), but sometimes this is taking 
it too far.)


As i said to Gavin, i'm not at ease with using the symbol '&' in 
between patterns.


I think that this is mostly a "who moved my cheese" reaction; you're 
used to thinking that & is just for bitwise operations.  But, that's not 
actually true; we already use & and | on types -- intersection type 
casts, additional generic type bounds, multi-catch.  This appeals to a 
notion that & and | are boolean-like combinators on types (even if not 
exposed in all places they might make sense), but this is a different 
kind of combination than on integers.  And yet a different kind of 
combination on patterns.  (In an alternate universe, we might have 
different symbols for adding ints vs floats vs string concatenation, but 
+ works well enough that overloading the symbols is OK -- because using 
+ in this way appeals to the underlying algebraic monoid structure these 
types share.)


The reason that & and | make sense on patterns, and on types, is that, 
like the more familiar versions on bits, they describe a _boolean 
algebra_.  Boolean algebras have familiar properties such as De Morgan's 
Laws.  These work for types (when interpreted as value sets) as well as 
bits, and they work for patterns too.


I think where you're getting hung up is that when patterns produce 
bindings, and other patterns consume those bindings, we have a dataflow 
dependence which would appear to undermine certain other expected 
properties of a boolean algebra, such as commutativity. But, if we view 
those dataflow dependencies as a separate constraint -- as we *already 
do* for ints (e.g., `(x=3)&(x|4)`, is invalid when `x` is an DU int, but 
valid when `x` is DA), this seeming contradiction vanishes, and is seen 
to be merely a post-hoc well-formedness constraint.  If the WF 
constraint is satisfied, the expected properties of boolean algebras 
(associativity, commutativity, absorption, etc) are satisfied too.





Re: [External] : Re: Guards

2021-03-10 Thread Gavin Bierman


On 10 Mar 2021, at 00:55, Guy Steele 
mailto:guy.ste...@oracle.com>> wrote:



On Mar 9, 2021, at 1:47 PM, Brian Goetz 
mailto:brian.go...@oracle.com>> wrote:


Apart from what have said about letting grobble to fully access to the bindings

Except that argument doesn't make sense.  Accessing the bindings is not a 
special behavior of grobble, but a natural consequence of flow scoping.  If I 
have P && g (or P & grobble(g)), then the scoping rules will tell us that the 
true set of P is present in g, and we're done.  Nothing special here.


Well, just to be fair, rules for flow scoping within expressions g && h already 
exist, but rules for P && g and P & Q do not yet exist.  It’s easy to see that 
they probably should exist, and that this can be done in a manner entirely 
analogous to the way flow scoping is already done in expressions, but it has 
been an implicit assumption in some of the past discussion that is worth making 
explicit.  “Consider it done!”  :-)


The draft JEP does try to be reasonably informative on this matter:

A conditional-and pattern p & q introduces the union of the pattern variables 
introduced by the patterns p and q. The scope of any pattern variable 
declaration in p includes the pattern q. (This allows for a pattern such as 
String s & true(s.length() > 1) -- a value matches this pattern if it can be 
cast to a String and that string has a length of two or more characters.)

Gavin


Re: [External] : Re: Guards

2021-03-09 Thread Guy Steele



> On Mar 9, 2021, at 1:47 PM, Brian Goetz  wrote:
> 
> 
>> Apart from what have said about letting grobble to fully access to the 
>> bindings
> 
> Except that argument doesn't make sense.  Accessing the bindings is not a 
> special behavior of grobble, but a natural consequence of flow scoping.  If I 
> have P && g (or P & grobble(g)), then the scoping rules will tell us that the 
> true set of P is present in g, and we're done.  Nothing special here.


Well, just to be fair, rules for flow scoping within expressions g && h already 
exist, but rules for P && g and P & Q do not yet exist.  It’s easy to see that 
they probably should exist, and that this can be done in a manner entirely 
analogous to the way flow scoping is already done in expressions, but it has 
been an implicit assumption in some of the past discussion that is worth making 
explicit.  “Consider it done!”  :-)

—Guy



Re: [External] : Re: Guards

2021-03-09 Thread John Rose
On Mar 9, 2021, at 2:57 PM, fo...@univ-mlv.fr wrote:
> 
> 
> 
> De: "John Rose" 
> À: "Remi Forax" 
> Cc: "Brian Goetz" , "amber-spec-experts" 
> 
> Envoyé: Mardi 9 Mars 2021 23:05:28
> Objet: Re: [External] : Re: Guards
> On Mar 9, 2021, at 1:45 PM, fo...@univ-mlv.fr <mailto:fo...@univ-mlv.fr> 
> wrote:
> 
> I see the pattern + parameters has a partial application, i.e. the parameters 
> other than the target are constants,
> the keys of the map are constant, the java.util.regex.Pattern (or the string) 
> of a metch is a constant, etc
> 
> So yes, a pattern have input parameters other than the target but should they 
> have access to the bindings, i think we are loosing a lot with that model.
> 
> If I read you correctly, you want patterns to be
> as statically scrutable as possible, so that translation
> strategies can boil together as much of the pattern
> as possible before first execution, typically using
> indy or condy to do “advanced” configuration
> and optimization of statement logic.
> 
> Not for the translation strategy, just to be able to rapidly read all the 
> patterns without having to precisely follow the control flow.
> I would like to have the horizontal reading to be as simple as possible so 
> you can grasp the whole pattern matching vertically.
> Another way to see it is to see Pattern as declarations more than expressions.

OK.  So you are saying you are OK with northward dependencies
on non-constant data (names of locals, etc.) but not westward.

(BTW, we all agree that southward and westward dependencies
are harder to cope with.  Note, however, that Java declaration
syntax has a prevailing eastward dependency, from the
initializer.  Just something to keep in mind for later.)

When you say “horizontal reading”, I note that one *does* read
westward dependencies before reading content to the east, but
I think you want the whole line to be readable at once.

Well, that’s fine, but it’s not clear that is a hard constraint
on what we are designing.  A coder can code that way.
Even with guards, the “&&G” part can and sometimes
should be put on its own line, south of the pattern.

I can derive a soft requirement out of your point, and
that is that “it would be nice” if “westward” dependencies
in patterns are hard to hide.  The “&&” operator fulfills
this requirement for guards, since “&&” is relatively
bold in appearance (easy to spot) and is not used for
patterns.

This is also the reason I (very tentatively) suggested
that a unary version of the “&&” syntax might also
be useful for marking in-arguments inside of patterns.
If that suggestion doesn’t fly, maybe we can come up
with some other marker for pattern in-args in general,
or maybe just for “westward in-args in the same pattern”,
that serves the purpose of making them stand out.

(And without committing the newbie error of
Always Making the NEW Feature **Stand OUT**,
with h/t to Neal Gafter.)

Happily, we can solve the general problem of in-arg
marking separately from this design iteration.

— John

Re: [External] : Re: Guards

2021-03-09 Thread forax
> De: "John Rose" 
> À: "Remi Forax" 
> Cc: "Brian Goetz" , "amber-spec-experts"
> 
> Envoyé: Mardi 9 Mars 2021 23:05:28
> Objet: Re: [External] : Re: Guards

> On Mar 9, 2021, at 1:45 PM, [ mailto:fo...@univ-mlv.fr | fo...@univ-mlv.fr ]
> wrote:

>> I see the pattern + parameters has a partial application, i.e. the parameters
>> other than the target are constants,
>> the keys of the map are constant, the java.util.regex.Pattern (or the 
>> string) of
>> a metch is a constant, etc

>> So yes, a pattern have input parameters other than the target but should they
>> have access to the bindings, i think we are loosing a lot with that model.

> If I read you correctly, you want patterns to be
> as statically scrutable as possible, so that translation
> strategies can boil together as much of the pattern
> as possible before first execution, typically using
> indy or condy to do “advanced” configuration
> and optimization of statement logic.

Not for the translation strategy, just to be able to rapidly read all the 
patterns without having to precisely follow the control flow. 
I would like to have the horizontal reading to be as simple as possible so you 
can grasp the whole pattern matching vertically. 
Another way to see it is to see Pattern as declarations more than expressions. 

> Moreover, I think you want patterns to *reject*
> non-constant operands, so that such configurations
> are reliably done before first execution.

> I whole-heartedly agree with the first goal,
> but I think the second would be a bridge too
> far, because various kinds of refactorings
> can shift expressions in and out of the
> “constant” category, and that’s useful.

yes, it's not "constant" for the language. 
It's morally constant, the same way the lambdas in a stream has to be side 
effect free. 

[...] 

> — John

Rémi 


Re: [External] : Re: Guards

2021-03-09 Thread John Rose
On Mar 9, 2021, at 1:45 PM, fo...@univ-mlv.fr wrote:
> 
> I see the pattern + parameters has a partial application, i.e. the parameters 
> other than the target are constants,
> the keys of the map are constant, the java.util.regex.Pattern (or the string) 
> of a metch is a constant, etc
> 
> So yes, a pattern have input parameters other than the target but should they 
> have access to the bindings, i think we are loosing a lot with that model.

If I read you correctly, you want patterns to be
as statically scrutable as possible, so that translation
strategies can boil together as much of the pattern
as possible before first execution, typically using
indy or condy to do “advanced” configuration
and optimization of statement logic.

Moreover, I think you want patterns to *reject*
non-constant operands, so that such configurations
are reliably done before first execution.

I whole-heartedly agree with the first goal,
but I think the second would be a bridge too
far, because various kinds of refactorings
can shift expressions in and out of the
“constant” category, and that’s useful.

I think we can trust users to use constants
in places where they are advantageous.

You may well ask, “but what is the language
support for reliably folding constants at
javac translation time?”  And the answer
is “nothing yet”.  But I think that is a job
for Brian’s constant-folding mechanisms,
building on top of his ConstantDesc work.
Until that point, we can live with non-constant
expressions.  I would say, before that point,
it would be foolish to add indy support for
constant in-args, just for and only for patterns.

— John



Re: [External] : Re: Guards

2021-03-09 Thread Brian Goetz




There are two kinds of input args, one is the implicit target, the others are 
other arguments.
It's not obvious to me that the parameters other than the target have to have 
access to the bindings.


You keep saying "access to the bindings" as if that is a special thing.  
Bindings are ordinary local variables.  Code has "access" to the 
bindings when the bindings are in scope.  There's nothing magic here.





Re: [External] : Re: Guards

2021-03-09 Thread forax
- Mail original -
> De: "John Rose" 
> À: "Brian Goetz" 
> Cc: "Remi Forax" , "amber-spec-experts" 
> 
> Envoyé: Mardi 9 Mars 2021 19:56:42
> Objet: Re: [External] : Re: Guards

> On Mar 9, 2021, at 10:47 AM, Brian Goetz  wrote:
>> 
>> 
>>> Apart from what have said about letting grobble to fully access to the 
>>> bindings
>> 
>> Except that argument doesn't make sense.  Accessing the bindings is not a
>> special behavior of grobble, but a natural consequence of flow scoping.  If I
>> have P && g (or P & grobble(g)), then the scoping rules will tell us that the
>> true set of P is present in g, and we're done.  Nothing special here.
> 
> Piling on:
> 
> If patterns ever have in-args (in addition to out-args,
> and they will!), then flow-scoping, regularly applied,
> will allow those in-args to access previously bound
> out-args to the left, within the same compound pattern,
> whether in an instanceof pattern or a case label pattern.

I agree that patterns have input args.

There are two kinds of input args, one is the implicit target, the others are 
other arguments.
It's not obvious to me that the parameters other than the target have to have 
access to the bindings.

I see the pattern + parameters has a partial application, i.e. the parameters 
other than the target are constants,
the keys of the map are constant, the java.util.regex.Pattern (or the string) 
of a metch is a constant, etc

So yes, a pattern have input parameters other than the target but should they 
have access to the bindings, i think we are loosing a lot with that model.

> 
> And, guards (whether built-in && as I claim they
> should be) or a privileged use of in-args on a standard
> method, will naturally have access to those same
> leftward out-arg bindings.
> 
> I think it’s a great model.  The reason we are agonizing
> here is kind of artificial, because in-args in patterns
> are a 99.99% probable future, of which guards are
> the first manifestation.
> 
> — John

Rémi


Re: [External] : Re: Guards

2021-03-09 Thread John Rose
On Mar 9, 2021, at 10:47 AM, Brian Goetz  wrote:
> 
> 
>> Apart from what have said about letting grobble to fully access to the 
>> bindings
> 
> Except that argument doesn't make sense.  Accessing the bindings is not a 
> special behavior of grobble, but a natural consequence of flow scoping.  If I 
> have P && g (or P & grobble(g)), then the scoping rules will tell us that the 
> true set of P is present in g, and we're done.  Nothing special here.

Piling on:

If patterns ever have in-args (in addition to out-args,
and they will!), then flow-scoping, regularly applied,
will allow those in-args to access previously bound
out-args to the left, within the same compound pattern,
whether in an instanceof pattern or a case label pattern.

And, guards (whether built-in && as I claim they
should be) or a privileged use of in-args on a standard
method, will naturally have access to those same
leftward out-arg bindings.

I think it’s a great model.  The reason we are agonizing
here is kind of artificial, because in-args in patterns
are a 99.99% probable future, of which guards are
the first manifestation.

— John

Re: [External] : Re: Guards

2021-03-09 Thread Brian Goetz



Apart from what have said about letting grobble to fully access to the 
bindings


Except that argument doesn't make sense.  Accessing the bindings is not 
a special behavior of grobble, but a natural consequence of flow 
scoping.  If I have P && g (or P & grobble(g)), then the scoping rules 
will tell us that the true set of P is present in g, and we're done.  
Nothing special here.