Re: Patterns and nulls

2018-03-15 Thread Guy Steele

> On Mar 15, 2018, at 9:59 PM, John Rose  wrote:
> . . .
> (Think of somebody adding Yule or Duodecember to enum Month.)

Febtober!



Re: Patterns and nulls

2018-03-15 Thread John Rose
On Mar 15, 2018, at 5:01 PM, Brian Goetz  wrote:
> 
> For the exhaustiveness-lovers, they can manually enumerate all the cases 
> (enums, sealed type members), and have a throwing default which will detect 
> unexpected targets that would be impossible at compile time.  (At some point, 
> maybe we'll help them by adding support for "default: unreachable", which 
> would provide not only runtime detection but would enlist the compiler's flow 
> analysis as well.)

I'm one of those exhaustiveness lovers, because I'm afraid of accidental 
fallout,
which is what happens in today's switches when a surprise value comes through.
I'm happy that expression switches will exclude fallout robustly.

I'm also content that I can insert a throw in my statement switch to robustly
exclude fallout, and happy that this throw is likely to be a simple notation,
probably "default: throw;".

Here are some more details about this:

This use case implies a peculiar thing about the "throwing default":
The compiler *may* be able to prove that the inserted throw is unreachable.
It must not complain about it, however, since I have a legitimate
need to mark my switch as protected against future accidents.
In fact, javac treats enum switches with such open-mindedness.

In the case of enums, the future accident would be a novel enum
value coming through, after a separate recompilation introduced it.
(Think of somebody adding Yule or Duodecember to enum Month.)
As an exhaustiveness lover, I use a "throwing default" to button
up my switch against such future novelties.

The use case also implies that the throw statement must not be
just any old thing (throw new AssertionError("oops")), but should
align with the language's internal story of how to deal with
these problems in expression switches.  The notation should
also be shorter than a normal throw expression, or programmers
will find it hard to write and read, and be tempted to leave it out
even when it would make the code more robust.

Also, it has to be a throw of some sort, because it cannot allow
execution to continue after it, lest the compiler complain about
fallout from an enclosing method body or a path by which a
blank local is left unassigned.  I.e., the notation needs a special
pass from the reachability police.

This leads us to the following syntax, or one like it:

switch ((ColorChannel)c) {
case R: return red();
case G: return green();
case B: return blue();
default: throw;  //not reached, no fallout ever
}

This would be a the refactoring of the corresponding
expression switch:

return switch ((ColorChannel)c) {
case R-> red();
case G-> green();
case B-> blue();
//optional, can omit:  default: throw;
};

There's a trick where Java programmers can lean on DA
rules to protect against fallout.  Here's a third refactoring
of those switches which uses this trick:

int result;
switch ((ColorChannel)c) {
case R: result = red(); break;
case G: result = green(); break;
case B: result = blue(); break;
default: throw;  //not reached, no fallout ever
}
return result;

(A very subtle bug can arise if result has an initializer,
say "result=null", or if it is an object field, and there
is no default.  Then fallout is probably unexpected, and
the user could be in trouble if a novel enum shows up in
the future.  Most coders want to avoid such traps if they
can, and the language should help.  That's another reason
for a concise "default: throw" notation.  The DA tricks
and the tracking of live code paths, don't always diagnose
unexpected fallout.)

The compiler can and should choose the same error path
for all these switches, one which will diagnose the problem
adequately, and lead to suitable remedies like recompilation.

The user should not be expected to compose an adequate
exception message for responding to this corner case.
(Analogy:  What if we required every division statement
to be accompanied by an exception message to use
when a zero divisor occurred?)

As a shortcut, programmers often use another trick, which
inserts "default:" before the case label of one of the enum
values.  This relieves the programmer of concocting an
exception expression, and is probably the easy way out
that we take most often, but it is not always a robust
answer.  If Yule shows up, he'll be treated just like
December, or whatever random month the programmer
stuck the default label on to placate the reachability
police.  It would be better if the throw were easy to
write and read; Yule would be welcomed in with the
appropriate diagnostic rather than a silent miscalculation.

Of course many switches are not exhaustive, and users
*expect* fallout to happen.  Leaving out the "default" selects
this behavior (except for null, but then there's "case null:break").

If the switch looks exhaustive, there might be some doubt about
whether the programmer intended exhaustiveness.  In such situations
a compiler warning might be helpful, and an IDE intention would
certainly be helpful.  The 

Re: break seen as a C archaism

2018-03-15 Thread Guy Steele
Well, actually, Brian, I now realize that I had my tongue in only _one_ of my 
cheeks.  Sleep on it and then see what you think.

> On Mar 15, 2018, at 6:38 PM, Brian Goetz  wrote:
> 
> At this point, the Colonel from Monty Python breaks in, and shuts us down for 
> being too silly
> 
> On 3/15/2018 6:37 PM, Remi Forax wrote:
>> 
>> 
>> De: "John Rose"  
>> À: "Guy Steele"  
>> Cc: "amber-spec-experts"  
>> 
>> Envoyé: Jeudi 15 Mars 2018 23:06:51
>> Objet: Re: break seen as a C archaism
>> On Mar 15, 2018, at 2:44 PM, Guy Steele > > wrote:
>> 
>> 
>>  break return x;
>> 
>> Then everybody is happy:
>> (1) Cannot be confused with the old `break` syntax.
>> (2) Clearly exits a `switch` like `break` does.
>> (3) Clearly returns a value like `return` does.
>> (4) Better encourages exclusive use of `->` (because using `->` rather than 
>> `: break return` saves even more characters than using `->` rather than `: 
>> break`).
>> (5) In the year 2364, this can be further generalized to allow `continue 
>> return x;`.
>> (6) Those who want new language features to really jump out will surely be 
>> satisfied.
>> 
>> Not bad.  It also doesn't weaken "plain return" in the
>> way I was worried about.
>> 
>> I would have numbered that last point (-1), though.
>> 
>> — John
>> 
>> i think, we're missing a 'do' just to be sure,
>>   do break return x;
>> 
>> Rémi
>> 
> 



Re: break seen as a C archaism

2018-03-15 Thread Brian Goetz
At this point, the Colonel from Monty Python breaks in, and shuts us 
down for being too silly


On 3/15/2018 6:37 PM, Remi Forax wrote:





*De: *"John Rose" 
*À: *"Guy Steele" 
*Cc: *"amber-spec-experts" 
*Envoyé: *Jeudi 15 Mars 2018 23:06:51
*Objet: *Re: break seen as a C archaism

On Mar 15, 2018, at 2:44 PM, Guy Steele > wrote:


break return x;

Then everybody is happy:
(1) Cannot be confused with the old `break` syntax.
(2) Clearly exits a `switch` like `break` does.
(3) Clearly returns a value like `return` does.
(4) Better encourages exclusive use of `->` (because using
`->` rather than `: break return` saves even more characters
than using `->` rather than `: break`).
(5) In the year 2364, this can be further generalized to allow
`continue return x;`.
(6) Those who want new language features to really jump out
will surely be satisfied.


Not bad.  It also doesn't weaken "plain return" in the
way I was worried about.

I would have numbered that last point (-1), though.

— John


i think, we're missing a 'do' just to be sure,
  do break return x;

Rémi





Re: break seen as a C archaism

2018-03-15 Thread Remi Forax
> De: "John Rose" 
> À: "Guy Steele" 
> Cc: "amber-spec-experts" 
> Envoyé: Jeudi 15 Mars 2018 23:06:51
> Objet: Re: break seen as a C archaism

> On Mar 15, 2018, at 2:44 PM, Guy Steele < [ mailto:guy.ste...@oracle.com |
> guy.ste...@oracle.com ] > wrote:

>> break return x;

>> Then everybody is happy:
>> (1) Cannot be confused with the old `break` syntax.
>> (2) Clearly exits a `switch` like `break` does.
>> (3) Clearly returns a value like `return` does.
>> (4) Better encourages exclusive use of `->` (because using `->` rather than 
>> `:
>> break return` saves even more characters than using `->` rather than `:
>> break`).
>> (5) In the year 2364, this can be further generalized to allow `continue 
>> return
>> x;`.
>> (6) Those who want new language features to really jump out will surely be
>> satisfied.

> Not bad. It also doesn't weaken "plain return" in the
> way I was worried about.

> I would have numbered that last point (-1), though.

> — John

i think, we're missing a 'do' just to be sure, 
do break return x; 

Rémi 


Re: break seen as a C archaism

2018-03-15 Thread Guy Steele
Okay, Maurizio, you got me thinking.  As long as we are convinced that we are 
actually going to use an explicit value-returning statement within a switch 
expression quite infrequently in real code, why don’t we get the best of both 
worlds by spelling it this way:

break return x;

Then everybody is happy:
(1) Cannot be confused with the old `break` syntax.
(2) Clearly exits a `switch` like `break` does.
(3) Clearly returns a value like `return` does.
(4) Better encourages exclusive use of `->` (because using `->` rather than `: 
break return` saves even more characters than using `->` rather than `: break`).
(5) In the year 2364, this can be further generalized to allow `continue return 
x;`.
(6) Those who want new language features to really jump out will surely be 
satisfied.

—Guy

> On Mar 15, 2018, at 5:13 PM, Maurizio Cimadamore 
>  wrote:
> 
> So, from a language design perspective, 'return x' is wrong - but, as you 
> point out, we already committed the original sin of having 'return == local 
> return' for lambdas, so I'm not too convinced that we couldn't use the same 
> story again here. E.g. when you say 'return', what you really mean is 
> 'returning from the innermost context'. This could be a method (as usual), or 
> a nested expression e.g. a lambda or a switch expression.
> 
> Kevin has a point in that using return is mildly worrisome when it comes to 
> refactoring; but we had exactly the same problem with lambdas when we were 
> considering migrating code using internal iteration (for loop) to code using 
> external iteration (Stream forEach) - again, there the refactoring could not 
> be 100% smooth - if the body of your loop had some abnormally completing 
> branches, then there was no way to translate that into an external iteration 
> idiom - at least not mechanically (e.g. 'return x' already meant something 
> different inside old-style for loop bodies).
> 
> So, seems to me that we end up with the same bag of pros and cons? E.g. more 
> familiar to the user (return  is something that they know and love), 
> but more smelly from a design point of view (in a way that forecloses using 
> 'return' to mean non-local return, but I wonder - has that ship already 
> sailed?)
> 
> Maurizio



Re: break seen as a C archaism

2018-03-15 Thread John Rose
On Mar 15, 2018, at 2:13 PM, Maurizio Cimadamore 
 wrote:
> 
> So, from a language design perspective, 'return x' is wrong - but, as you 
> point out, we already committed the original sin of having 'return == local 
> return' for lambdas, so I'm not too convinced that we couldn't use the same 
> story again here. E.g. when you say 'return', what you really mean is 
> 'returning from the innermost context'. This could be a method (as usual), or 
> a nested expression e.g. a lambda or a switch expression.
> 
> 
We have method bodies and lambda bodies on one hand,
and we have switches and loops on the other.

We use return to escape from the former, and break to
escape from the latter.

Note that return may or may not take an expression,
while break never does, at present.

So far so good.  Now we stir in expression switches.
Which side of the fence do they belong on?

It seems to me that your position needs to argue
that e-switches belong with methods and lambdas,
because only return can take an expression.
If you can pull this off, then break doesn't need
to take an expression.

Likewise, my position need to argue that giving "break" an
expression is reasonable.  I don't need to argue
that expression switches are similar to legacy
switches.  (But I'm trying to spike the argument
that it's hard to unify e-switches and s-switches,
so let's just fork the language with a new switch-like
feature for expressions.)

But there are two reasons why e-switch doesn't
belong with method body and lambda body,
a shallow but strong one, and a deep one.

Shallow but strong:  e-switches are obviously switches.

Deep:  Lambda bodies and method bodies execute
in their own stack frames.  Any up-level references
must be to final locals (or fields).  Lambda bodies
and methods can execute at most one "return",
which tears down their frame.  Expressions,
including expression switches, execute in the
frame of the containing lambda body or method
and can read *and write* local variables.
Expressions are inherently local to a frame
and can imperatively side effect it.

A "return" which in some contexts keeps the
stack frame and jumps somewhere is a weaker
return than today's return.  (Weaker meaning
less can be concluded by observing it in code.)

So I can't group e-switch cases with lambda bodies.
I know some have performed this feat to their own
satisfaction, but it's hard for me, in a way that
seems deeper than just learning curve.

By now we recognize that adding an expression
to "break" is no big deal; it's a new overloading.
I agree that it is open to the accusation that it's not
thrifty, that "return" already does that job.
But it seems to me the shallow and deep points
above answer the accusation.

For me, the cost of making "break" do a new
trick is paid for by the benefit of not inventing
a new switch-like expression (like ?: for if/else),
and not having to weaken "return".

— John

Re: break seen as a C archaism

2018-03-15 Thread Remi Forax
- Mail original -
> De: "mark" 
> À: "amber-spec-experts" 
> Envoyé: Jeudi 15 Mars 2018 20:06:40
> Objet: Re: break seen as a C archaism

> On 2018-03-15T14:50:45 -0400
> Brian Goetz  wrote:
>>
>> > If you are reconsidering options, reconsider "yield", meaning
>> >"break current context with this value".
>> 
>> Still feeling a little burned by first time we floated this, but willing
>> to try another run up the flagpole
> 
> Silly idea, but... *puts on fireproof suit*:
> 
>  "finally x;"

I believe we can also use any new keywords given that you can not have an 
identifier followed by an identifier in Java.

by example
  pass x;
  quit x;
  end x;
  
> 
> --
> Mark Raynsford | http://www.io7m.com

Rémi


Re: break seen as a C archaism

2018-03-15 Thread Guy Steele

> On Mar 15, 2018, at 3:40 PM, Remi Forax  wrote:
> 
> 
> 
> - Mail original -
>> De: "Guy Steele" 
>> À: "mark" 
>> Cc: "amber-spec-experts" 
>> Envoyé: Jeudi 15 Mars 2018 20:18:34
>> Objet: Re: break seen as a C archaism
> 
>>> On Mar 15, 2018, at 3:06 PM, Mark Raynsford  wrote:
>>> 
>>> On 2018-03-15T14:50:45 -0400
>>> Brian Goetz  wrote:
 
> If you are reconsidering options, reconsider "yield", meaning
>  "break current context with this value".
 
 Still feeling a little burned by first time we floated this, but willing
 to try another run up the flagpole
>>> 
>>> Silly idea, but... *puts on fireproof suit*:
>>> 
>>> "finally x;"
>> 
>> Interestingly, the keywords `try` and `catch` and `finally` currently must 
>> each
>> be followed by a block, so there is indeed syntactic space to use each one 
>> with
>> a following expression instead.
>> 
>> Which only suggests that . . . *puts on fireproof suit and then climbs into a
>> concrete bunker and slams the door*:
>> 
>>  “try x;”
>> 
>> would be shorter and no sillier.
>> 
>> —Guy
> 
> It seams too close to the try-with-resources.
> 
> compare
>  try (resource) -> { };  // a try that break/return a lambda
> with
>  try (resource) { }  // a try-with-resources
> 
> Rémi

Indeed.  Mine was not a serious suggestion.  I agree with John Rose’s analysis: 
“break x;” really does seem to be the best point in the design space, 
especially since you can use “->” to hide it 98% of the time.

"But I was thinking of a plan
To dye one's whiskers green,
And always use so large a fan
That they could not be seen.”

—Lewis Carroll




Re: break seen as a C archaism

2018-03-15 Thread Remi Forax


- Mail original -
> De: "Guy Steele" 
> À: "Brian Goetz" 
> Cc: "amber-spec-experts" 
> Envoyé: Jeudi 15 Mars 2018 20:12:56
> Objet: Re: break seen as a C archaism

>> On Mar 15, 2018, at 2:50 PM, Brian Goetz  wrote:
>> 
>> 
 We had rejected this earlier for fairly obvious reasons, but let me
 ask to get a subjective response: would using "return x" be better?
>>> If you are reconsidering options, reconsider "yield", meaning
>>>   "break current context with this value".
>> 
>> Still feeling a little burned by first time we floated this, but willing to 
>> try
>> another run up the flagpole
>> 
>> In Lambda, I used the early "State of the Lambda" drafts as a means to
>> test-drive various syntax options.  SotL 2/e floated "yield" as the
>> get-out-of-lambda card, and I was unprepared for the degree of "you big fat
>> stupid idiot, don't you know what yield means" response I got.  So we beat a
>> hasty retreat from that experiment, temporarily settled on return, and then
>> failed to circle back.  I still regret the choice of return for lambda.
>> 
>> The primary objection to yield was from the async/await crowd that would 
>> want us
>> to save it for that, but I don't see them as mutually exclusive (nor do I 
>> think
>> async/await is all that likely, especially with the great work happening over
>> in Loom).
>> 
>> The loss of using something other than "break" is that now expression and
>> statement switches become more obviously different beasts, which might be OK.
> 
> I have to agree that “yield” has too much of a history in the topics of
> multithreading and coroutining, giving it all the wrong connotations for our
> purpose here.

yes !
and if Loom at some point requires a syntax instead of being a pure API, it 
will be unfortunate.

Rémi


Re: break seen as a C archaism

2018-03-15 Thread Remi Forax


- Mail original -
> De: "Guy Steele" 
> À: "mark" 
> Cc: "amber-spec-experts" 
> Envoyé: Jeudi 15 Mars 2018 20:18:34
> Objet: Re: break seen as a C archaism

>> On Mar 15, 2018, at 3:06 PM, Mark Raynsford  wrote:
>> 
>> On 2018-03-15T14:50:45 -0400
>> Brian Goetz  wrote:
>>> 
 If you are reconsidering options, reconsider "yield", meaning
   "break current context with this value".
>>> 
>>> Still feeling a little burned by first time we floated this, but willing
>>> to try another run up the flagpole
>> 
>> Silly idea, but... *puts on fireproof suit*:
>> 
>>  "finally x;"
> 
> Interestingly, the keywords `try` and `catch` and `finally` currently must 
> each
> be followed by a block, so there is indeed syntactic space to use each one 
> with
> a following expression instead.
> 
> Which only suggests that . . . *puts on fireproof suit and then climbs into a
> concrete bunker and slams the door*:
> 
>   “try x;”
> 
> would be shorter and no sillier.
> 
> —Guy

It seams too close to the try-with-resources.

compare
  try (resource) -> { };  // a try that break/return a lambda
with
  try (resource) { }  // a try-with-resources

Rémi


Re: break seen as a C archaism

2018-03-15 Thread Guy Steele

> On Mar 15, 2018, at 3:06 PM, Mark Raynsford  wrote:
> 
> On 2018-03-15T14:50:45 -0400
> Brian Goetz  wrote:
>> 
>>> If you are reconsidering options, reconsider "yield", meaning
>>>   "break current context with this value".  
>> 
>> Still feeling a little burned by first time we floated this, but willing 
>> to try another run up the flagpole
> 
> Silly idea, but... *puts on fireproof suit*:
> 
>  "finally x;"

Interestingly, the keywords `try` and `catch` and `finally` currently must each 
be followed by a block, so there is indeed syntactic space to use each one with 
a following expression instead. 

Which only suggests that . . . *puts on fireproof suit and then climbs into a 
concrete bunker and slams the door*:

   “try x;”

would be shorter and no sillier.

—Guy



Re: break seen as a C archaism

2018-03-15 Thread John Rose
On Mar 15, 2018, at 11:11 AM, Brian Goetz  wrote:
> We had rejected this earlier for fairly obvious reasons, but let me
> ask to get a subjective response: would using "return x" be better?
> On the one hand, it's not really a return, and it doesn't build on the
> user intuition about the control flow aspects of break, but on the
> other, the return statement is already prepared to take a value, so
> its not adding a "new form" to the existing statement, though it is
> adding a new and different context.  (We abuse it slightly in lambdas,
> but people seem OK with this, probably because they think of lambdas
> as methods anyway.)

Here's my take on how this is going, for what it's worth.

We're going round and round on this because there's isn't a comfortable
spot to land.  But there is a nearly comfortable spot, which is where we
started:  Although break's legacy syntax requires an overload for it to
accept a value, the following two legacy facts pull us toward break:
  - break is to switch as return is to a method body (in branch behavior)
  - return is a branch which can be overloaded with an optional value
Now, switches are becoming more like methods: They can return values.
So the most direct path is to overload break "like return", in some way.
What way?  Well, the straightforward way works, with the usual tricks
to avoid ambiguities in overloaded constructs.  At that point we have
added to the language by increasing symmetry, a win.

Let's beware of making new language features #{ Stand Out }.  It makes
them look silly and puzzling when they mature.  Many objections to
novelties like "break x" are of two potential kinds:  a. "I want the new
thing to be easier to spot", b. "Programmers will never be at ease with
that".  People tend to use a. as a proxy for b., but as we go round
and round I think many of us tend to forget about b., which is the
real point.  Can anyone successfully argue that "break x" liable to b.?
I doubt it.

Our quest for continuity and symmetry with the past is our best
trick for avoiding b. (and c., "Let's fork the language"), even at
the temporary cost of a.

Neal Gafter says it very well:
> It is better to design the feature so that it fits well with the existing
> features of the language, even if it might at first seem jarring that
> things have changed. Users will quickly get over the newness of
> the changes and learn to understand the language as a whole as
> it is (after the change).

The adding of -> to the mix is an inspired move (thanks, Brian)
because it repurposes another existing part of the language,
and adds it as sugar for "break x", keeping continuity and
improving clarity at the same time.

My $0.02.

— John

P.S. FTR here's the reference to Neal's blog:
http://gafter.blogspot.com/2017/06/making-new-language-features-stand-out.html

P.P.S. The above reasoning might lead to other places too:  If we were to
make loops return values, then "break" would do the same for them.
Also "continue" could be overloaded to deliver a partial result to the
loop control.  That's sci fi at the present moment, but I'm showing it as
an example how the logic works.

Re: break seen as a C archaism

2018-03-15 Thread Guy Steele

> On Mar 15, 2018, at 2:50 PM, Brian Goetz  wrote:
> 
> 
>>> We had rejected this earlier for fairly obvious reasons, but let me
>>> ask to get a subjective response: would using "return x" be better?
>> If you are reconsidering options, reconsider "yield", meaning
>>   "break current context with this value".
> 
> Still feeling a little burned by first time we floated this, but willing to 
> try another run up the flagpole
> 
> In Lambda, I used the early "State of the Lambda" drafts as a means to 
> test-drive various syntax options.  SotL 2/e floated "yield" as the 
> get-out-of-lambda card, and I was unprepared for the degree of "you big fat 
> stupid idiot, don't you know what yield means" response I got.  So we beat a 
> hasty retreat from that experiment, temporarily settled on return, and then 
> failed to circle back.  I still regret the choice of return for lambda.
> 
> The primary objection to yield was from the async/await crowd that would want 
> us to save it for that, but I don't see them as mutually exclusive (nor do I 
> think async/await is all that likely, especially with the great work 
> happening over in Loom).
> 
> The loss of using something other than "break" is that now expression and 
> statement switches become more obviously different beasts, which might be OK.

I have to agree that “yield” has too much of a history in the topics of 
multithreading and coroutining, giving it all the wrong connotations for our 
purpose here.



Re: break seen as a C archaism

2018-03-15 Thread Mark Raynsford
On 2018-03-15T14:50:45 -0400
Brian Goetz  wrote:
>
> > If you are reconsidering options, reconsider "yield", meaning
> >"break current context with this value".  
> 
> Still feeling a little burned by first time we floated this, but willing 
> to try another run up the flagpole

Silly idea, but... *puts on fireproof suit*:

  "finally x;"

-- 
Mark Raynsford | http://www.io7m.com



Re: break seen as a C archaism

2018-03-15 Thread Doug Lea
On 03/15/2018 02:11 PM, Brian Goetz wrote:
>> - That we are overloading an existing control construct, "break", 
>> to mean something just different enough to be uncomfortable;
>> 
>> 
>> To some degree yes, since `break ` already means
>> something.
> 
> We had rejected this earlier for fairly obvious reasons, but let me
> ask to get a subjective response: would using "return x" be better?

If you are reconsidering options, reconsider "yield", meaning
  "break current context with this value".

Which is what we are allowing break with val to mean.

Which argues for allowing either (break-val or yield-val) in lambdas as
well because...

> (We abuse it slightly in lambdas, but people seem OK with this,
> probably because they think of lambdas as methods anyway.)

-Doug