From brian.goetz at oracle.com Fri Sep 7 18:41:12 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 7 Sep 2018 14:41:12 -0400 Subject: Updated pattern match documents Message-ID: I've updated the documents regarding pattern matching, and uploaded them here: http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html The first document is an update of a previous document (old version available here: http://cr.openjdk.java.net/~briangoetz/amber/pattern-match_1.html), and outlines the general arc of the feature and general motivation. The second captures the discussions we've had regarding the messy details of typing, scoping, nullability, shadowing, etc. I think we've made a lot of progress on these. We would not implement this all at once; we'd proceed incrementally, probably starting with type patterns in `instanceof`, and then proceeding to `switch` or to deconstruction patterns. Please review and comment. From jb at giraudeau.info Fri Sep 7 20:12:08 2018 From: jb at giraudeau.info (Jean-Baptiste Giraudeau) Date: Fri, 7 Sep 2018 22:12:08 +0200 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: <8c2c5c61-0170-3054-4f4a-6ba714faf831@giraudeau.info> Hi Brian, As a scala user this looks very familiar. From a functional programmer point-of-view, there is a few topics that I'd very much like to see mentioned, even every shortly. 1. tail call optimizations: as pattern matching is very often associated with recursion it would be nice to mention any plan about it being supported one day (or not). 2. type casing / casting on a universally quantified type variables: this breaks parametricity, so functional programmers would want to avoid it. As I understand, in such case a default branch is required, correct? It would then be a nice improvement over scala, which does not emit a warning on non-exhaustive matches in such cases. Requiring `default` means that a functional programmer can be sure that their pattern match is "legal" (ie. only on ADT) as long as `default` is never used. The best would a compiler flag that would only allows structural decomposition on sealed/enum... but this is probably asking too much...? 3. Support of GADT. Is there any plan to support unification in GADT structural decomposition? ie. would the following code be compilable, one day: sealed interface Term{} record Zero() implements Term; record Succ(Term pred) implements Term; record Pred(Term succ) implements Term; record IsZero(Term i) implements Term; record If(Term cond, Term then, Term otherwise) implements Term; ??? static T eval(Term term) { ??????? return switch (term) { ??????????? case Zero() -> 0; ??????????? case Succ(var pred) -> eval(pred) + 1; ??????????? case Pred(var succ) -> eval(succ) - 1; ??????????? case IsZero(var t) -> eval(t) ==0; ??????????? case If(var cond, var then, var otherwise) -> eval(cond) ? eval(then) : eval(otherwise) ??????? } ??? } cheers, - jb On 9/7/18 8:41 PM, Brian Goetz wrote: > I've updated the documents regarding pattern matching, and uploaded > them here: > > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html > http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html > > The first document is an update of a previous document (old version > available here: > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match_1.html), > and outlines the general arc of the feature and general motivation. > > The second captures the discussions we've had regarding the messy > details of typing, scoping, nullability, shadowing, etc.? I think > we've made a lot of progress on these. > > We would not implement this all at once; we'd proceed incrementally, > probably starting with type patterns in `instanceof`, and then > proceeding to `switch` or to deconstruction patterns. > > Please review and comment. > From brian.goetz at oracle.com Fri Sep 7 20:30:16 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 7 Sep 2018 16:30:16 -0400 Subject: Updated pattern match documents In-Reply-To: <8c2c5c61-0170-3054-4f4a-6ba714faf831@giraudeau.info> References: <8c2c5c61-0170-3054-4f4a-6ba714faf831@giraudeau.info> Message-ID: Thanks for your comments, some comments inline. Also, please don't cross-post between amber-spec-observers and amber-spec-comments; use amber-spec-observers for general discussion. > As a scala user this looks very familiar. Familiar, but slightly different.? Language features can't be dropped directly from one language into another. One area where we would like to do better than Scala here is the integration of patterns as first-class members of classes.? Scala's patterns are inherently static, and rely on some pretty ad-hoc compiler transformations of magic methods like unapply.? But much of that is farther down the road. > 1. tail call optimizations: as pattern matching is very often associated > with recursion it would be nice to mention any plan about it being > supported one day (or not). Hard to speculate on how a single feature would integrate with tail calls, when we don't yet have a story for how the platform will support tail calls.? However, the cases in which tail calls are most critical in pattern matching -- sequence patterns -- are not there yet, so we have some time. > 2. type casing / casting on a universally quantified type variables: > this breaks parametricity, so functional programmers would want to avoid > it. As I understand, in such case a default branch is required, correct? > It would then be a nice improvement over scala, which does not emit a > warning on non-exhaustive matches in such cases. Exhaustiveness checking is a bit messy.? For expression switches, we require that switches be exhaustive, which means either (a) there's a total pattern at the bottom, (b) it's an enum switch and all the enums are accounted for (in which case we generate a hidden default to detect enums added after compilation), or (c) its a switch on a sealed type and all the type choices are accounted for (same deal with a hidden default.) For statement switches, however, we do not require them to be exhaustive; we're painted into a corner by existing switch semantics.? We might at some point support some way to say "I want this switch to be exhaustive" to engage the type checker's help. > 3. Support of GADT. Is there any plan to support unification in GADT > structural decomposition? ie. would the following code be compilable, > one day: > > sealed interface Term{} > record Zero() implements Term; > record Succ(Term pred) implements Term; > record Pred(Term succ) implements Term; > record IsZero(Term i) implements Term; > record If(Term cond, Term then, Term otherwise) > implements Term; > > > ??? static T eval(Term term) { > ??????? return switch (term) { > ??????????? case Zero() -> 0; > ??????????? case Succ(var pred) -> eval(pred) + 1; > ??????????? case Pred(var succ) -> eval(succ) - 1; > ??????????? case IsZero(var t) -> eval(t) ==0; > ??????????? case If(var cond, var then, var otherwise) -> eval(cond) ? > eval(then) : eval(otherwise) > ??????? } > ??? } > I think we can get to Zero/Succ/Pred/IsZero, as we can distinguish between them by inspecting their dynamic type.? The current story, which rejects unchecked cast conversions in the applicability check, is probably a little too rigid, but I think we can get there, because the goal here its fundamentally consistent with the approach we've taken. For If, we're fine, because we know term to be a Term, and it doesn't require an unchecked cast to get from Term to If. So, I don't see this as posing any surprise challenges. From amaembo at gmail.com Sun Sep 9 05:37:32 2018 From: amaembo at gmail.com (Tagir Valeev) Date: Sun, 9 Sep 2018 12:37:32 +0700 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: Hello! Great work, thanks! Seems that the new document steps away from dedicated matching operator like __matches which we saw before and reuses instanceof instead. Does this mean that sole type name like String which is used in instanceof currently is also a pattern? This could conflict with named constant. E. g.: class Test { static final int String = 5; void test(Object obj) { if(obj instanceof String) { // obj == 5 or is a string? } } } With best regards, Tagir Valeev. ??, 8 ????. 2018 ?., 1:41 Brian Goetz : > I've updated the documents regarding pattern matching, and uploaded them > here: > > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html > http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html > > The first document is an update of a previous document (old version > available here: > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match_1.html), and > outlines the general arc of the feature and general motivation. > > The second captures the discussions we've had regarding the messy > details of typing, scoping, nullability, shadowing, etc. I think we've > made a lot of progress on these. > > We would not implement this all at once; we'd proceed incrementally, > probably starting with type patterns in `instanceof`, and then > proceeding to `switch` or to deconstruction patterns. > > Please review and comment. > > From brian.goetz at oracle.com Sun Sep 9 13:03:59 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 9 Sep 2018 09:03:59 -0400 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: <16198608-e1a7-a68b-e9f5-1d1c5af77ce5@oracle.com> > Seems that the new document steps away from dedicated matching > operator like __matches which we saw before and reuses instanceof > instead. Yes -- the __matches notation was always a placeholder for something, which might have been `instanceof` all along; we just weren't sure whether `instanceof` could be cleanly extended.? But, given that it can, this seems a pretty sensible path. > Does this mean that sole type name like String which is used in > instanceof currently is also a pattern? This is possible, but we don't go quite that far in the current round; instead, we say that instanceof can take a type or a pattern on the RHS.? (Related question, in the other direction: can a deconstruction pattern take a binding variable for the whole thing, as in `D(int x) d`?) > This could conflict with named constant. E. g.: > > class Test { > ? static final int String = 5; > > ? void test(Object obj) { > ? ? if(obj instanceof String) { > ? ? ? // obj == 5 or is a string? > ? ? } > ? } > } > We'd have this problem even more broadly if `T` were a pattern; is ??? case String: a type pattern, or a constant pattern?? At least now, we only have to deal with this ambiguity in `instanceof`.? And, it might not be unreasonable to restrict the set of patterns you can put on the RHS of an `instanceof`; constant patterns on the RHS of instanceof would only be there "for completeness".? So we could restrict the grammar to be: ??? instanceof ( | | ) and this problem goes away.? (Saying `x instanceof 3` is kind of silly; you could just say `x == 3`.? Same for `var` and `_` patterns.)? And the result is that all these patterns are type-based, which is clearly in the mission of `instanceof`. If not, we have a problem where the grammar might simply accept an identifier, and then type checking will have to do more work before we know what the construct means.? (This happens too with things like `a.b.c`; any of those dots could be about field access, or package membership, or nested membership; we parse it now and sort it out later, according to some set of rules.) From mark at io7m.com Mon Sep 10 14:50:35 2018 From: mark at io7m.com (Mark Raynsford) Date: Mon, 10 Sep 2018 15:50:35 +0100 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: <20180910155035.6bc9736c@almond.int.arc7.info> On 2018-09-07T14:41:12 -0400 Brian Goetz wrote: > I've updated the documents regarding pattern matching, and uploaded them > here: > > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html > http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html I need to give the semantics document another serious read (I don't care much about syntax, personally), but at first impression, I particularly like how nullability has been handled. Nullable patterns seem like a great way to support both null-hostile and null-tolerant programming. -- Mark Raynsford | http://www.io7m.com From guy.steele at oracle.com Mon Sep 10 15:05:12 2018 From: guy.steele at oracle.com (Guy Steele) Date: Mon, 10 Sep 2018 11:05:12 -0400 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: <1472FD96-0E3A-4121-8969-C119BCF0E43F@oracle.com> > On Sep 7, 2018, at 2:41 PM, Brian Goetz wrote: > > I've updated the documents regarding pattern matching, and uploaded them here: > > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html "if the data structure is a tree represents a design in a CAD application? => "if the data structure is a tree that represents a design in a CAD application? (add ?that?) "case AddNode(Node left, Node right)) -> ?? => "case AddNode(Node left, Node right) -> ?? (delete extraneous right paren) At end of section ?Composing patterns?, show an actual example of multiply nested patterns, such as "AddNode(Node x, IntNode(int n))?. "whether the manifest type adds or distracts from readability and maintainability? => "whether the manifest type adds to or distracts from readability and maintainability? (add ?to?) "it is also reasonably to have? => "it is also reasonable to have? It?s worth pointing out that one possible spelling of ?__let? is to use no token at all. Then certain degenerate cases are the same as when using a local variable declaration with initializer. > http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html > > The first document is an update of a previous document (old version available here: http://cr.openjdk.java.net/~briangoetz/amber/pattern-match_1.html), and outlines the general arc of the feature and general motivation. > > The second captures the discussions we've had regarding the messy details of typing, scoping, nullability, shadowing, etc. I think we've made a lot of progress on these. > > We would not implement this all at once; we'd proceed incrementally, probably starting with type patterns in `instanceof`, and then proceeding to `switch` or to deconstruction patterns. > > Please review and comment. > From scolebourne at joda.org Mon Sep 10 22:21:12 2018 From: scolebourne at joda.org (Stephen Colebourne) Date: Mon, 10 Sep 2018 23:21:12 +0100 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: Nice documents. A question and a few thoughts. Why can 'default' not also capture null? Since null is not currently allowed in switch, the incompatibility is not immediately obvious. If the plan is to allow nulls into switch based on the presence or absence of a null accepting pattern, that does make me uncomfortable (too much action at a distance in a large switch). Use of ? nullable types to allow null I'm broadly happy with this - the ? reads well. I'm less comfortable that this will be the only place in the language that supports nullable types. While fully aware of feature creep, I don't want nullable types to stick out like a sore thumb either. Since records are an entirely new feature and closely associated with pattern matching, it is very appealing to use nullable types for the fields of a record. In fact, I'd go further - any type that wants to have a deconstructor/extractor should be written in terms of nullable types. Scoping and instanceof While the rules are no doubt exactly what makes logical sense, they are undoubtedly complex. I think it is fair to ask whether they are a step too far. The simple examples (p instanceof Point(x, y) && x > 0 && y > 0) are obvious enough, but some of the other forms that can be written are seriously obtuse. As such I have some doubts about associating patterns with the existing 'instanceof' (or perhaps it is associating && and || with patterns in if statements). The occasionally mentioned 'when' clause would separate the two parts and has the potential to be clearer if it allows limits to be placed on the associated expressions, for example: if (p case Point(x, y) when x > 0 && y > 0) {...} It would be very easy to explain the mapping from 'switch' to if/else chains with the reuse of 'case', and I think 'case' will read better with more complex patterns. Moreover, I'm yet to be convinced that pattern-style expressions belong everywhere that an expression can go, thus reusing 'instanceof' doesn't entirely appeal to me. Extractor syntax I'm unconvinced about the syntax used in the documents for extractor methods. When invoking it, the caller passes no parameters, yet the syntax suggests that it has parameters. I could suggest alternative syntaxes, but for good behaviour I won't. Stephen On Fri, 7 Sep 2018 at 19:41, Brian Goetz wrote: > > I've updated the documents regarding pattern matching, and uploaded them > here: > > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html > http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html > > The first document is an update of a previous document (old version > available here: > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match_1.html), and > outlines the general arc of the feature and general motivation. > > The second captures the discussions we've had regarding the messy > details of typing, scoping, nullability, shadowing, etc. I think we've > made a lot of progress on these. > > We would not implement this all at once; we'd proceed incrementally, > probably starting with type patterns in `instanceof`, and then > proceeding to `switch` or to deconstruction patterns. > > Please review and comment. > From amaembo at gmail.com Tue Sep 11 03:15:23 2018 From: amaembo at gmail.com (Tagir Valeev) Date: Tue, 11 Sep 2018 10:15:23 +0700 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: Hello! Regarding dominance of the combination of patterns. The semantics document says: > This includes patterns that are dominated by prior case labels, as well as case labels that are dominated by combinations of prior case labels -- such as a T? pattern that follows a nullable pattern and a T pattern. I think, this part requires clarification. Some interesting cases: switch(boolValue) {case true:case false:case _:break;} -- is case _ a compilation error? What if case _ is changed to default? switch(boxedBoolValue) {case true:case false:case null:case _:break;} -- the same question assuming enum Direction {UP, DOWN} and Box(Direction) switch(box) {case Box(UP):case Box(DOWN):case Box b:break;} -- I assume that case Box b is allowed here as it can match Box(null). Even if Box(Direction) constructor requires that Direction is not null, compiler cannot know this. Or can? switch(box) {case Box(UP):case Box(DOWN):case Box(null):case Box b:break;} -- what now? Do we consider the combination of Box(UP), Box(DOWN) and Box(null) as exhaustive? Also what about combinations of several fields? Assuming TwoFlags(boolean, boolean): switch(twoFlags) {case TwoFlags(true, _):case TwoFlags(_, true):case TwoFlags(false, false):case TwoFlags t:break;} -- here all combinations are covered by first three patterns, so TwoFlags t cannot match anything. Will it be reported? What if we have ten enum fields? Will compiler track all covered value combinations and issue an error if it's statically known that some pattern is unreachable? I'm not sure about computational complexity of such tracking in common case. With best regards, Tagir Valeev. On Sat, Sep 8, 2018 at 1:41 AM Brian Goetz wrote: > > I've updated the documents regarding pattern matching, and uploaded them > here: > > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html > http://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html > > The first document is an update of a previous document (old version > available here: > http://cr.openjdk.java.net/~briangoetz/amber/pattern-match_1.html), and > outlines the general arc of the feature and general motivation. > > The second captures the discussions we've had regarding the messy > details of typing, scoping, nullability, shadowing, etc. I think we've > made a lot of progress on these. > > We would not implement this all at once; we'd proceed incrementally, > probably starting with type patterns in `instanceof`, and then > proceeding to `switch` or to deconstruction patterns. > > Please review and comment. > From brian.goetz at oracle.com Tue Sep 11 10:41:17 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 11 Sep 2018 06:41:17 -0400 Subject: Updated pattern match documents In-Reply-To: References: Message-ID: <64202f44-21a0-499a-044a-9f91dea9627f@oracle.com> > I think, this part requires clarification. Some interesting cases: > > switch(boolValue) {case true:case false:case _:break;} -- is case _ a > compilation error? What if case _ is changed to default? > switch(boxedBoolValue) {case true:case false:case null:case _:break;} > -- the same question So, boolean is slightly easier than enum, because it's a lot less likely that new boolean values will appear via separate compilation than with enums.? Though, it sometimes happens: ??? https://thedailywtf.com/articles/What_Is_Truth_0x3f_ So let's start with enums.? Today, users often have to code a `default` branch even when all enums are covered.? This is annoying, and we'd like to give users some relief from having to include silly code, but the motivation goes deeper than that.? If you have a switch expression over an enum without a default, the compiler will tell you when you've left out a case.? But if you have a default, the compiler will happily let you cover N-1 of the cases.? So not only is requiring a silly default annoying to the user, it takes away the compiler's ability to type check.? So clearly we want users to be able to enter exhaustive switches (over booleans, enums, sealed types, and maybe even byte) without default. That said, we probably still want to allow a default even when the switch is exhaustive, because perhaps the user wants to customize the handling of such problems with a more scrutable error than simply getting an ICCE.? So, even though `default` / case _ might be dead at compile time, it might not be dead at runtime.? (For boolean and byte, OK, it's dead.? But that's a special case.) That's a different case (heh) than: ??? case Integer i -> 0; ??? case integer j -> 1; The second arm is going to be dead no matter what.? The examples of dominance that I gave were primarily type-based, so they fall in the latter category.? We should reject the second arm. So, I think the dominance story holds up, but we do need to adjust it to handle cases that are exhaustive at compile time but are not guaranteed to be so at run time (which is primarily restricted to enums and sealed types.) (Also note that exhaustiveness checking can easily become a lifetime activity.? The easy cases are easy, but there's a long tail of whack-a-mole that probably ends in the halting problem.) > assuming enum Direction {UP, DOWN} and Box(Direction) > switch(box) {case Box(UP):case Box(DOWN):case Box b:break;} -- I > assume that case Box b is allowed here as it can match Box(null). Even > if Box(Direction) constructor requires that Direction is not null, > compiler cannot know this. Or can? Currently can not.? But even if it could, we're back in enum territory, and its possible that a new direction, LEFT, shows up at runtime.? So a `Box` or `Box(var x)` or `_` case are acceptable here.? But I think this derives from the fact that enums are inherently more fungible than booleans? So, you're really asking two questions: ?- Under what conditions do we require a catch-all case? ?- Under what conditions do we allow a catch-all case, even if the switch seems exhaustive? For the first, we require a catch-all if (a) the switch is an expression switch and (b) we cannot prove that the cases are exhaustive _relative to compile-time type knowledge_.? So if you switch on enums: ??? case (trafficLightColor) { ??????? case RED: ??????? case YELLOW: ??????? case GREEN: ??? } you're good, even though a new color could come along later.? The compiler will insert a catch-all case here, throwing ICCE.? And there's no null possible, since none of the cases are nullable, so the switch will throw on null. Raising it up a level: ??? case (box) { // assume Box ??????? case Box(RED): ... ??????? case Box(YELLOW): ... ??????? case Box(GREEN): ... ??? } we can detect at compile time that we haven't handled Box(null), though it seems a bit mean to require a default here.? So we may want to treat null specially here -- let's think about that. For the latter question, I think when we are reasoning about exhaustiveness in a brittle way (enums and sealed classes), we want to allow a catch-all case even if it seems dead at compile time. But if we're reasoning about exhaustiveness through types, then a `default` or `_` case might be truly dead, and we should reject it. > Also what about combinations of several fields? Assuming > TwoFlags(boolean, boolean): > switch(twoFlags) {case TwoFlags(true, _):case TwoFlags(_, true):case > TwoFlags(false, false):case TwoFlags t:break;} -- here all > combinations are covered by first three patterns, so TwoFlags t cannot > match anything. Will it be reported? What if we have ten enum fields? > Will compiler track all covered value combinations and issue an error > if it's statically known that some pattern is unreachable? I'm not > sure about computational complexity of such tracking in common case. This is starting down that slippery slope of "lifetime activity" I was referring to :) From alex.buckley at oracle.com Wed Sep 19 18:42:16 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Wed, 19 Sep 2018 11:42:16 -0700 Subject: New JEP: Concise Method Bodies Message-ID: <5BA29888.4000302@oracle.com> https://bugs.openjdk.java.net/browse/JDK-8209434 From mark.reinhold at oracle.com Wed Sep 19 18:54:46 2018 From: mark.reinhold at oracle.com (mark.reinhold at oracle.com) Date: Wed, 19 Sep 2018 11:54:46 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <5BA29888.4000302@oracle.com> References: <5BA29888.4000302@oracle.com> Message-ID: <20180919115446.639340752@eggemoggin.niobe.net> 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com: > https://bugs.openjdk.java.net/browse/JDK-8209434 Or, more readably: http://openjdk.java.net/jeps/8209434 - Mark From kevinb at google.com Wed Sep 19 19:31:38 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Wed, 19 Sep 2018 12:31:38 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <20180919115446.639340752@eggemoggin.niobe.net> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> Message-ID: Hello, I think it's relatively easy to see the benefits when there a fair number of parameters to pass through. In other cases, it looks like you're gaining a very *small* amount of syntactic conciseness (mostly omitting `return`) and not much else? Is there any actual *conceptual* simplicity or clarity being gained? JEPs don't seem to often include any discussion of what the costs of the feature change. So evaluating benefit vs. cost is not easy. For example, in this case, it becomes harder to understand and explain what a method reference even *is*. I've been saying "it's just a lambda expression", but either that's gone, or it's now becoming harder to understand and explain what a lambda expression is. I think moral-hazard arguments also deserve a bit of thought. public A b(C c, D d, E e, F f) { return g.h(c, d, e, f); } If I forgot an "if e is empty, throw" check in here, I'll just insert it. But if it was this: public A b(C c, D d, E e, F f) = g::h; I'm probably less likely to do that. This is a bit similar to why our style guide requires braces around single-statement if blocks. It's too annoying to deal with inserting them and removing them all the time as conditions change. Perhaps these costs don't add up to anything massive, but we should still get a fix on them because if it turns out the benefits *also* don't add up to something massive then....? I hope this is helpful. On Wed, Sep 19, 2018 at 11:58 AM wrote: > 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com: > > https://bugs.openjdk.java.net/browse/JDK-8209434 > > Or, more readably: http://openjdk.java.net/jeps/8209434 > > - Mark > -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com From forax at univ-mlv.fr Wed Sep 19 19:40:41 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 19 Sep 2018 21:40:41 +0200 (CEST) Subject: New JEP: Concise Method Bodies In-Reply-To: <20180919115446.639340752@eggemoggin.niobe.net> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> Message-ID: <1548697396.670631.1537386041090.JavaMail.zimbra@u-pem.fr> There is a ';' at the end of dayOfWeek that should not be there. String dayOfWeek(int d) -> switch (d) { case 1 -> "SUNDAY"; case 2 -> "MONDAY"; ... }; // <---- should be removed R?mi ----- Mail original ----- > De: "mark reinhold" > ?: "Alex Buckley" > Cc: "amber-spec-experts" > Envoy?: Mercredi 19 Septembre 2018 20:54:46 > Objet: Re: New JEP: Concise Method Bodies > 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com: >> https://bugs.openjdk.java.net/browse/JDK-8209434 > > Or, more readably: http://openjdk.java.net/jeps/8209434 > > - Mark From forax at univ-mlv.fr Wed Sep 19 19:49:23 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 19 Sep 2018 21:49:23 +0200 (CEST) Subject: New JEP: Concise Method Bodies In-Reply-To: <1548697396.670631.1537386041090.JavaMail.zimbra@u-pem.fr> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <1548697396.670631.1537386041090.JavaMail.zimbra@u-pem.fr> Message-ID: <1522176255.671249.1537386563212.JavaMail.zimbra@u-pem.fr> oops, no, the ';' is necessary here, sorry. R?mi ----- Mail original ----- > De: "Remi Forax" > ?: "mark reinhold" > Cc: "amber-spec-experts" > Envoy?: Mercredi 19 Septembre 2018 21:40:41 > Objet: Re: New JEP: Concise Method Bodies > There is a ';' at the end of dayOfWeek that should not be there. > > String dayOfWeek(int d) -> switch (d) { > case 1 -> "SUNDAY"; > case 2 -> "MONDAY"; > ... > }; // <---- should be removed > > > R?mi > > ----- Mail original ----- >> De: "mark reinhold" >> ?: "Alex Buckley" >> Cc: "amber-spec-experts" >> Envoy?: Mercredi 19 Septembre 2018 20:54:46 >> Objet: Re: New JEP: Concise Method Bodies > >> 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com: >>> https://bugs.openjdk.java.net/browse/JDK-8209434 >> >> Or, more readably: http://openjdk.java.net/jeps/8209434 >> > > - Mark From alex.buckley at oracle.com Wed Sep 19 19:54:40 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Wed, 19 Sep 2018 12:54:40 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <1522176255.671249.1537386563212.JavaMail.zimbra@u-pem.fr> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <1548697396.670631.1537386041090.JavaMail.zimbra@u-pem.fr> <1522176255.671249.1537386563212.JavaMail.zimbra@u-pem.fr> Message-ID: <5BA2A980.9050907@oracle.com> Right. A concise method body is introduced with an arrow or equals sign, and concluded with a semicolon. It just so happens that the concise method body below features a switch expression, which (unusually among expressions) has a block of its own. (And that's why I chose it as an example, to stress the concise-method-body feature.) Alex On 9/19/2018 12:49 PM, Remi Forax wrote: > oops, > no, the ';' is necessary here, sorry. > > R?mi > > ----- Mail original ----- >> De: "Remi Forax" >> ?: "mark reinhold" >> Cc: "amber-spec-experts" >> Envoy?: Mercredi 19 Septembre 2018 21:40:41 >> Objet: Re: New JEP: Concise Method Bodies > >> There is a ';' at the end of dayOfWeek that should not be there. >> >> String dayOfWeek(int d) -> switch (d) { >> case 1 -> "SUNDAY"; >> case 2 -> "MONDAY"; >> ... >> }; // <---- should be removed >> >> >> R?mi >> >> ----- Mail original ----- >>> De: "mark reinhold" >>> ?: "Alex Buckley" >>> Cc: "amber-spec-experts" >>> Envoy?: Mercredi 19 Septembre 2018 20:54:46 >>> Objet: Re: New JEP: Concise Method Bodies >> >>> 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com: >>>> https://bugs.openjdk.java.net/browse/JDK-8209434 >>> >>> Or, more readably: http://openjdk.java.net/jeps/8209434 >>> >>> - Mark From alex.buckley at oracle.com Wed Sep 19 21:43:44 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Wed, 19 Sep 2018 14:43:44 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> Message-ID: <5BA2C310.9000206@oracle.com> Hi Kevin, On 9/19/2018 12:31 PM, Kevin Bourrillion wrote: > In other cases, it looks like you're gaining a very /small/ amount of > syntactic conciseness (mostly omitting `return`) and not much else? Is > there any actual /conceptual/ simplicity or clarity being gained? Let me focus on the single expression form. The argument we've made is: statement lambdas have a concise form, expression lambdas, that improves clarity, and method bodies are like statement lambdas, so they should have a concise form too. Maybe that's stretching the connection between statement lambdas and method bodies too thin, but it's a fair starting point. Perhaps the outcome will be classes with a mishmash of method body forms, where the jumping between {} and -> acts to hurt readability overall even if individual methods are simpler. (Shades of switch expressions having both : and -> cases.) And, empirically, perhaps there are very few method bodies in your codebase simple enough to adopt the -> form. (Data welcome.) Alex > JEPs don't seem to often include any discussion of what the costs of the > feature change. So evaluating benefit vs. cost is not easy. For example, > in this case, it becomes harder to understand and explain what a method > reference even /is/. I've been saying "it's just a lambda expression", > but either that's gone, or it's now becoming harder to understand and > explain what a lambda expression is. > > I think moral-hazard arguments also deserve a bit of thought. > > public A b(C c, D d, E e, F f) { return g.h(c, d, e, f); } > > If I forgot an "if e is empty, throw" check in here, I'll just insert > it. But if it was this: > > public A b(C c, D d, E e, F f) = g::h; > > I'm probably less likely to do that. > > This is a bit similar to why our style guide requires braces around > single-statement if blocks. It's too annoying to deal with inserting > them and removing them all the time as conditions change. > > Perhaps these costs don't add up to anything massive, but we should > still get a fix on them because if it turns out the benefits > /also/ don't add up to something massive then....? > > I hope this is helpful. > > > On Wed, Sep 19, 2018 at 11:58 AM > wrote: > > 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com > : > > https://bugs.openjdk.java.net/browse/JDK-8209434 > > Or, more readably: http://openjdk.java.net/jeps/8209434 > > - Mark > > > > -- > Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com > From brian.goetz at oracle.com Wed Sep 19 22:23:39 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 19 Sep 2018 18:23:39 -0400 Subject: Fwd: JEP draft: Concise Method Bodies - extend this to local functions? References: Message-ID: This was received from the suggestion box ? My thoughts on this: local functions are a potentially useful feature, and one that interacts nicely with the concise form, but the two features are orthogonal; there?s nothing to be gained by doing them together that is not gained by doing them sequentially in either order. While I?ve got nothing against local functions, I would rather do local functions in the context of a more general cleanup about nesting constraints (e.g., restrictions on static fields of inner classes, private classes nested in interfaces, local interfaces and enums, etc.) There?s a whole pile of ?it makes sense to nest X in Y, but you can?t? irregularities that can be cleaned up at once ? but I think there?s more immediate payback in doing the more constrained feature of concise method bodies first. > Begin forwarded message: > > From: Lukas Eder > Subject: JEP draft: Concise Method Bodies - extend this to local functions? > Date: September 19, 2018 at 4:44:04 PM EDT > To: amber-spec-comments at openjdk.java.net > > Hello, > > I've just seen this new JEP draft, which really looks very useful: > http://openjdk.java.net/jeps/8209434 > > Now, given that this would be possible: > > int x(String s) -> s.length(); > > And given that this almost looks like a named lambda expression, could this > maybe be an occasion to re-discuss the possibility of supporting named > lambda expression / local functions? > > E.g. > > void m() { > > // lambda local to m() > ToIntFunction x1 = (String s) -> s.length(); > > // "method" local to m() > int x2(String s) -> s.length(); > > // We can now do: > int i1 = x1.apply("abc"); > > // More concise > int i2 = x2("abc"); > } > > I know this was discussed for Java 8 and rejected, but given the high > similarity of the currently proposed concise method body syntax and the > lambda syntax, I feel that on a high level, this might appear coherent and > useful. > > Of course, in such a case, it would appear useful to allow the original > method body syntax as well in a local method: > > void m() { > int x3(String s) { > return s.length(); > } > } > > Also, many other languages have this feature, e.g. Scala, Ceylon, Kotlin > > Thanks, > Lukas From lukas.eder at gmail.com Thu Sep 20 07:05:00 2018 From: lukas.eder at gmail.com (Lukas Eder) Date: Thu, 20 Sep 2018 09:05:00 +0200 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: References: Message-ID: Hi Brian, I absolutely agree that there is no reason to mix the two features. The only reason I brought it up is because I found the currently proposed syntax for concise method bodies so similar to lambdas (which is great), which are often abused as poor man's local methods. I also find the idea of the general cleanup of nesting constraints *very* interesting. Thanks, Lukas On Thu, Sep 20, 2018 at 12:23 AM Brian Goetz wrote: > This was received from the suggestion box ? > > > My thoughts on this: local functions are a potentially useful feature, and > one that interacts nicely with the concise form, but the two features are > orthogonal; there?s nothing to be gained by doing them together that is not > gained by doing them sequentially in either order. While I?ve got nothing > against local functions, I would rather do local functions in the context > of a more general cleanup about nesting constraints (e.g., restrictions on > static fields of inner classes, private classes nested in interfaces, local > interfaces and enums, etc.) There?s a whole pile of ?it makes sense to > nest X in Y, but you can?t? irregularities that can be cleaned up at once ? > but I think there?s more immediate payback in doing the more constrained > feature of concise method bodies first. > > > > Begin forwarded message: > > > > From: Lukas Eder > > Subject: JEP draft: Concise Method Bodies - extend this to local > functions? > > Date: September 19, 2018 at 4:44:04 PM EDT > > To: amber-spec-comments at openjdk.java.net > > > > Hello, > > > > I've just seen this new JEP draft, which really looks very useful: > > http://openjdk.java.net/jeps/8209434 > > > > Now, given that this would be possible: > > > > int x(String s) -> s.length(); > > > > And given that this almost looks like a named lambda expression, could > this > > maybe be an occasion to re-discuss the possibility of supporting named > > lambda expression / local functions? > > > > E.g. > > > > void m() { > > > > // lambda local to m() > > ToIntFunction x1 = (String s) -> s.length(); > > > > // "method" local to m() > > int x2(String s) -> s.length(); > > > > // We can now do: > > int i1 = x1.apply("abc"); > > > > // More concise > > int i2 = x2("abc"); > > } > > > > I know this was discussed for Java 8 and rejected, but given the high > > similarity of the currently proposed concise method body syntax and the > > lambda syntax, I feel that on a high level, this might appear coherent > and > > useful. > > > > Of course, in such a case, it would appear useful to allow the original > > method body syntax as well in a local method: > > > > void m() { > > int x3(String s) { > > return s.length(); > > } > > } > > > > Also, many other languages have this feature, e.g. Scala, Ceylon, Kotlin > > > > Thanks, > > Lukas > > From john.r.rose at oracle.com Thu Sep 20 13:40:19 2018 From: john.r.rose at oracle.com (John Rose) Date: Thu, 20 Sep 2018 09:40:19 -0400 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: References: Message-ID: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> On Sep 19, 2018, at 6:23 PM, Brian Goetz wrote: > > I think there?s more immediate payback in doing the more constrained feature of concise method bodies first. +1 Also, local functions seem inevitably to expand into mutually recursive groups of locals. ("Why can't I do factorial? ?") There are some design ideas for all that, but it's complicated enough on its own that it has to be done on its own or as part of a larger project. And FTR I am very enthusiastic about CMB's: They are a decisive improvement in Java's ability to do software reuse at method granularity. They include both static and dynamic delegation as special cases, which are patterns Java hasn't been so good at to date. I remember proposals for first-class delegation support in the past, and CMB's subsume those, IMO. ? John From forax at univ-mlv.fr Thu Sep 20 16:18:16 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 20 Sep 2018 18:18:16 +0200 (CEST) Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> Message-ID: <967860541.1129877.1537460296154.JavaMail.zimbra@u-pem.fr> > De: "John Rose" > ?: "Brian Goetz" > Cc: "amber-spec-experts" > Envoy?: Jeudi 20 Septembre 2018 15:40:19 > Objet: Re: JEP draft: Concise Method Bodies - extend this to local functions? > On Sep 19, 2018, at 6:23 PM, Brian Goetz < [ mailto:brian.goetz at oracle.com | > brian.goetz at oracle.com ] > wrote: >> I think there?s more immediate payback in doing the more constrained feature of >> concise method bodies first. > +1 > Also, local functions seem inevitably to expand into mutually recursive groups > of locals. > ("Why can't I do factorial? ?") > There are some design ideas for all that, but it's complicated enough on its own > that it > has to be done on its own or as part of a larger project. > And FTR I am very enthusiastic about CMB's: They are a decisive improvement > in Java's ability to do software reuse at method granularity. They include both > static and dynamic delegation as special cases, which are patterns Java hasn't > been so good at to date. I remember proposals for first-class delegation support > in the past, and CMB's subsume those, IMO. There is also have an issue with method references because a local function has no owner type (from the Java POV, obviously there is an owner class once desugared by the compiler), class A { static void foo() { } static void m() { void foo() { } A::foo // ok A.m::foo or ::foo ?? } } One solution is to allow ::foo, which first, look for a local method, the a static method and then a method method imported by an import static. > ? John R?mi From forax at univ-mlv.fr Thu Sep 20 16:32:28 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 20 Sep 2018 18:32:28 +0200 (CEST) Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> Message-ID: <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> > De: "John Rose" > ?: "Brian Goetz" > Cc: "amber-spec-experts" > Envoy?: Jeudi 20 Septembre 2018 15:40:19 > Objet: Re: JEP draft: Concise Method Bodies - extend this to local functions? > On Sep 19, 2018, at 6:23 PM, Brian Goetz < [ mailto:brian.goetz at oracle.com | > brian.goetz at oracle.com ] > wrote: >> I think there?s more immediate payback in doing the more constrained feature of >> concise method bodies first. > +1 > Also, local functions seem inevitably to expand into mutually recursive groups > of locals. > ("Why can't I do factorial? ?") > There are some design ideas for all that, but it's complicated enough on its own > that it > has to be done on its own or as part of a larger project. > And FTR I am very enthusiastic about CMB's: They are a decisive improvement > in Java's ability to do software reuse at method granularity. They include both > static and dynamic delegation as special cases, which are patterns Java hasn't > been so good at to date. I remember proposals for first-class delegation support > in the past, and CMB's subsume those, IMO. And explicit delegations is far better than implicit delegation as Kotlin does, but while i find the single expression form useful, the method reference form is very similar to the syntax that was once proposed for default methods and i still find this syntax ugly. There is also a potential confusion between Function fun() = Utils::bar; and Function fun() -> Utils::bar; > ? John R?mi From kevinb at google.com Thu Sep 20 19:05:22 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Thu, 20 Sep 2018 12:05:22 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <5BA2C310.9000206@oracle.com> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <5BA2C310.9000206@oracle.com> Message-ID: On Wed, Sep 19, 2018 at 2:44 PM Alex Buckley wrote: On 9/19/2018 12:31 PM, Kevin Bourrillion wrote: > > In other cases, it looks like you're gaining a very /small/ amount of > > syntactic conciseness (mostly omitting `return`) and not much else? Is > > there any actual /conceptual/ simplicity or clarity being gained? > > Let me focus on the single expression form. The argument we've made is: > statement lambdas have a concise form, expression lambdas, that improves > clarity, and method bodies are like statement lambdas, so they should > have a concise form too. Okay. I get it. And I think this is the exact sort of parallel structure argument that reduces conceptual weight of a *new* language design. I think something very different happens for a language as solidified as Java. We cannot make it simpler than it is; when we add simpler things, then people just have to know both the new way and the old way. We can only ever add complexity. Arrowform switch is a good example where I think we can all agree that a certain bar is cleared. It is so broadly applicable and makes code so much easier to reason about that it manages to pay for itself. In this case, I think the `=*` *form *might* also clear that bar because of the automatic parameter pass-through. But I cannot currently see how the `->` form comes close to clearing it. > (Data welcome.) > Ooh, you know the magic words! Okay, we will analyze cases amenable to the `=` form, but I don't currently see a reason to gather stats on `->` form applicability. > JEPs don't seem to often include any discussion of what the costs of the > > feature change. So evaluating benefit vs. cost is not easy. For example, > > in this case, it becomes harder to understand and explain what a method > > reference even /is/. I've been saying "it's just a lambda expression", > > but either that's gone, or it's now becoming harder to understand and > > explain what a lambda expression is. > > > > I think moral-hazard arguments also deserve a bit of thought. > > > > public A b(C c, D d, E e, F f) { return g.h(c, d, e, f); } > > > > If I forgot an "if e is empty, throw" check in here, I'll just insert > > it. But if it was this: > > > > public A b(C c, D d, E e, F f) = g::h; > > > > I'm probably less likely to do that. > > > > This is a bit similar to why our style guide requires braces around > > single-statement if blocks. It's too annoying to deal with inserting > > them and removing them all the time as conditions change. > > > > Perhaps these costs don't add up to anything massive, but we should > > still get a fix on them because if it turns out the benefits > > /also/ don't add up to something massive then....? > > > > I hope this is helpful. > > > > > > On Wed, Sep 19, 2018 at 11:58 AM > > wrote: > > > > 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com > > : > > > https://bugs.openjdk.java.net/browse/JDK-8209434 > > > > Or, more readably: http://openjdk.java.net/jeps/8209434 > > > > - Mark > > > > > > > > -- > > Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com > > > -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com From maurizio.cimadamore at oracle.com Thu Sep 20 20:08:26 2018 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 20 Sep 2018 21:08:26 +0100 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> Message-ID: <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> On 20/09/18 17:32, Remi Forax wrote: > There is also a potential confusion between > ? Function fun() = Utils::bar; > and > ? Function fun() -> Utils::bar; > You meant between Function fun() = Utils::bar; and Function fun = Utils::bar; ? (first is method body, second is variable initializer) Maurizio From maurizio.cimadamore at oracle.com Thu Sep 20 20:10:59 2018 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 20 Sep 2018 21:10:59 +0100 Subject: New JEP: Concise Method Bodies In-Reply-To: References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <5BA2C310.9000206@oracle.com> Message-ID: <0f8c84df-1bd8-86d6-fc13-8c8e94f301b8@oracle.com> On 20/09/18 20:05, Kevin Bourrillion wrote: > In this case, I think the `=/` /form /might/?also clear that bar > because of the automatic parameter pass-through. But I cannot > currently see how the `->` form comes close to clearing it. Not sure I get it - surely every getter might benefit form this? int getX() -> x instead of int getX() { return x; } You could claim that the gain is minimal, but I'd suspect there's lots of applicable cases? Maurizio From alex.buckley at oracle.com Thu Sep 20 20:19:05 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 20 Sep 2018 13:19:05 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <5BA2C310.9000206@oracle.com> Message-ID: <5BA400B9.5040403@oracle.com> On 9/20/2018 12:05 PM, Kevin Bourrillion wrote: > In this case, I think the `=/` /form /might/ also clear that bar because > of the automatic parameter pass-through. But I cannot currently see how > the `->` form comes close to clearing it. > >> (Data welcome.) > > Ooh, you know the magic words! Okay, we will analyze cases amenable to > the `=` form, but I don't currently see a reason to gather stats on `->` > form applicability. As ever, thank you for any and all analysis that you can provide. FWIW I've updated the JEP with an example of using `->` in anonymous classes -- it's quite fun. Alex From alex.buckley at oracle.com Thu Sep 20 20:22:30 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 20 Sep 2018 13:22:30 -0700 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> Message-ID: <5BA40186.2070309@oracle.com> On 9/20/2018 1:08 PM, Maurizio Cimadamore wrote: > On 20/09/18 17:32, Remi Forax wrote: >> There is also a potential confusion between >> Function fun() = Utils::bar; >> and >> Function fun() -> Utils::bar; >> > You meant between > > Function fun() = Utils::bar; > > and > > Function fun = Utils::bar; > > ? > > (first is method body, second is variable initializer) I think Remi is noting the fact that, when using `->`, the single expression can be a method reference expression. I have already recorded this situation near the end of the JEP. Alex From kevinb at google.com Thu Sep 20 20:24:32 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Thu, 20 Sep 2018 13:24:32 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <0f8c84df-1bd8-86d6-fc13-8c8e94f301b8@oracle.com> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <5BA2C310.9000206@oracle.com> <0f8c84df-1bd8-86d6-fc13-8c8e94f301b8@oracle.com> Message-ID: Oh yes, I do know there are many applicable cases. If I do the research on this I think *all* it will tell me is "yes, there are many applicable cases". My claim is, indeed, that we should be valuing the savings of a `return` keyword at "very low" - in fact, so low that it is outweighed merely by the Paradox of Choice. On Thu, Sep 20, 2018 at 1:11 PM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > > > On 20/09/18 20:05, Kevin Bourrillion wrote: > > In this case, I think the `=*` *form *might* also clear that bar because > of the automatic parameter pass-through. But I cannot currently see how the > `->` form comes close to clearing it. > > Not sure I get it - surely every getter might benefit form this? > > int getX() -> x > > instead of > > int getX() { return x; } > > You could claim that the gain is minimal, but I'd suspect there's lots of > applicable cases? > > Maurizio > -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com From maurizio.cimadamore at oracle.com Thu Sep 20 20:28:42 2018 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 20 Sep 2018 21:28:42 +0100 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <5BA40186.2070309@oracle.com> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> <5BA40186.2070309@oracle.com> Message-ID: <7910a7cf-e84a-150a-184e-00c58e3cd076@oracle.com> On 20/09/18 21:22, Alex Buckley wrote: > On 9/20/2018 1:08 PM, Maurizio Cimadamore wrote: >> On 20/09/18 17:32, Remi Forax wrote: >>> There is also a potential confusion between >>> ? Function fun() = Utils::bar; >>> and >>> ? Function fun() -> Utils::bar; >>> >> You meant between >> >> Function fun() = Utils::bar; >> >> and >> >> Function fun = Utils::bar; >> >> ? >> >> (first is method body, second is variable initializer) > > I think Remi is noting the fact that, when using `->`, the single > expression can be a method reference expression. I have already > recorded this situation near the end of the JEP. Ok - then I added another :-) [not sure we should be worried about it, but perhaps worth mentioning in the JEP] Maurizio > > Alex From alex.buckley at oracle.com Thu Sep 20 20:46:51 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 20 Sep 2018 13:46:51 -0700 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <7910a7cf-e84a-150a-184e-00c58e3cd076@oracle.com> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> <5BA40186.2070309@oracle.com> <7910a7cf-e84a-150a-184e-00c58e3cd076@oracle.com> Message-ID: <5BA4073B.2050600@oracle.com> On 9/20/2018 1:28 PM, Maurizio Cimadamore wrote: >>> Function fun() = Utils::bar; >>> Function fun = Utils::bar; >>> >>> (first is method body, second is variable initializer) >> >> I think Remi is noting the fact that, when using `->`, the single >> expression can be a method reference expression. I have already >> recorded this situation near the end of the JEP. > Ok - then I added another :-) [not sure we should be worried about it, > but perhaps worth mentioning in the JEP] The puzzler practically writes itself. We distinguish: 1. boolean isEmpty(String s) = String::isEmpty; 2. Predicate isEmpty = String::isEmpty; 3. Predicate isEmpty(String s) -> String::isEmpty; 1. Method declaration, using method reference form. 2. Field declaration, initialized with a method reference exprssion. 3. Method declaration, using single expression form. Alex From cay.horstmann at sjsu.edu Thu Sep 20 20:47:13 2018 From: cay.horstmann at sjsu.edu (Cay Horstmann) Date: Thu, 20 Sep 2018 22:47:13 +0200 Subject: New JEP: Concise Method Bodies In-Reply-To: <5BA2C310.9000206@oracle.com> References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> <5BA2C310.9000206@oracle.com> Message-ID: Le 19/09/2018 ? 23:43, Alex Buckley a ?crit?: > Let me focus on the single expression form. The argument we've made is: > statement lambdas have a concise form, expression lambdas, that improves > clarity, and method bodies are like statement lambdas, so they should > have a concise form too. Maybe that's stretching the connection between > statement lambdas and method bodies too thin, but it's a fair starting > point. Perhaps the outcome will be classes with a mishmash of method > body forms, where the jumping between {} and -> acts to hurt readability > overall even if individual methods are simpler. Wouldn't those who desire uniformity in this matter be able to achieve it in the following way? public class BankAccount { private double balance; . . . public double getBalance() -> balance; public double withdraw(double amount) -> switch(0) { default -> { if (amount <= balance) balance -= amount; break balance; }}; } Cheers, Cay -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From forax at univ-mlv.fr Thu Sep 20 21:16:27 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 20 Sep 2018 23:16:27 +0200 (CEST) Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <7910a7cf-e84a-150a-184e-00c58e3cd076@oracle.com> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> <5BA40186.2070309@oracle.com> <7910a7cf-e84a-150a-184e-00c58e3cd076@oracle.com> Message-ID: <1341343563.9002.1537478187431.JavaMail.zimbra@u-pem.fr> ----- Mail original ----- > De: "Maurizio Cimadamore" > ?: "Alex Buckley" , "amber-spec-experts" > Envoy?: Jeudi 20 Septembre 2018 22:28:42 > Objet: Re: JEP draft: Concise Method Bodies - extend this to local functions? > On 20/09/18 21:22, Alex Buckley wrote: >> On 9/20/2018 1:08 PM, Maurizio Cimadamore wrote: >>> On 20/09/18 17:32, Remi Forax wrote: >>>> There is also a potential confusion between >>>> ? Function fun() = Utils::bar; >>>> and >>>> ? Function fun() -> Utils::bar; >>>> >>> You meant between >>> >>> Function fun() = Utils::bar; >>> >>> and >>> >>> Function fun = Utils::bar; >>> >>> ? >>> >>> (first is method body, second is variable initializer) >> >> I think Remi is noting the fact that, when using `->`, the single >> expression can be a method reference expression. I have already >> recorded this situation near the end of the JEP. yes, but in your example the return type is not the same, i prefer mine class Utils { Function fun() = this::bar; Function fun2() -> this::bar; Function bar() { return null; } String bar(String s) { return null; } } > Ok - then I added another :-) [not sure we should be worried about it, > but perhaps worth mentioning in the JEP] > R?mi From alex.buckley at oracle.com Thu Sep 20 22:09:29 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 20 Sep 2018 15:09:29 -0700 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <1341343563.9002.1537478187431.JavaMail.zimbra@u-pem.fr> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <724045742.1130915.1537461148678.JavaMail.zimbra@u-pem.fr> <07dde3fa-6d88-7bf0-d24b-cf844b6b5e95@oracle.com> <5BA40186.2070309@oracle.com> <7910a7cf-e84a-150a-184e-00c58e3cd076@oracle.com> <1341343563.9002.1537478187431.JavaMail.zimbra@u-pem.fr> Message-ID: <5BA41A99.8040804@oracle.com> On 9/20/2018 2:16 PM, Remi Forax wrote: > yes, but in your example the return type is not the same, i prefer mine > > class Utils { > Function fun() = this::bar; > Function fun2() -> this::bar; > > Function bar() { return null; } > String bar(String s) { return null; } > } Yes, it's good to omit parameters for the methods with concise bodies. I've updated the JEP. (Hope I got it right!) Alex From brian.goetz at oracle.com Fri Sep 21 00:30:53 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 20 Sep 2018 20:30:53 -0400 Subject: JEP draft: Concise Method Bodies - extend this to local functions? In-Reply-To: <967860541.1129877.1537460296154.JavaMail.zimbra@u-pem.fr> References: <4EB5E410-7026-471A-889E-B2C7E6DE8D85@oracle.com> <967860541.1129877.1537460296154.JavaMail.zimbra@u-pem.fr> Message-ID: > > There is also have an issue with method references because a local > function has no owner type (from the Java POV, obviously there is an > owner class once desugared by the compiler), Yes, unqualified method references have been on our radar since Java 8, and yes, we know that local methods would need them, and yes, the rules would parallel those for unqualified method invocations.? (I didn't raise these in response to Lukas' suggestion about local methods, because I want to keep the discussion focused on the feature in front of us.) From brian.goetz at oracle.com Fri Sep 21 00:37:29 2018 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 20 Sep 2018 20:37:29 -0400 Subject: New JEP: Concise Method Bodies In-Reply-To: References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> Message-ID: <26d9f33e-da28-714d-ba42-c8a82a5de329@oracle.com> > I think moral-hazard arguments also deserve a bit of thought. I was thinking moral hazard too, but in the other direction.? The higher the per-method overhead, the more likely people are to write poorly factored methods and to duplicate code, because declaring another method feels too heavy. Just as `var` lowers the barrier to pulling a subexpression into a variable with a name, increasing readability, lowering the bar to declaring a method does the same. From amaembo at gmail.com Fri Sep 21 00:47:26 2018 From: amaembo at gmail.com (Tagir Valeev) Date: Fri, 21 Sep 2018 07:47:26 +0700 Subject: New JEP: Concise Method Bodies In-Reply-To: References: <5BA29888.4000302@oracle.com> <20180919115446.639340752@eggemoggin.niobe.net> Message-ID: Hello, Kevin! Yes, it's a little bit hard to migrate between block body - expression body - method reference. However we already have this problem in lambdas, and we are living with this without much hassle. That's because every decent IDE can convert between these forms for you. Btw IDEA has an action to convert Kotlin block method body to expression form and vice versa. If course we will add similar feature for Java. With best regards, Tagir Valeev. ??, 20 ????. 2018 ?., 2:32 Kevin Bourrillion : > Hello, > > I think it's relatively easy to see the benefits when there a fair number > of parameters to pass through. > > In other cases, it looks like you're gaining a very *small* amount of > syntactic conciseness (mostly omitting `return`) and not much else? Is > there any actual *conceptual* simplicity or clarity being gained? > > JEPs don't seem to often include any discussion of what the costs of the > feature change. So evaluating benefit vs. cost is not easy. For example, in > this case, it becomes harder to understand and explain what a method > reference even *is*. I've been saying "it's just a lambda expression", > but either that's gone, or it's now becoming harder to understand and > explain what a lambda expression is. > > I think moral-hazard arguments also deserve a bit of thought. > > public A b(C c, D d, E e, F f) { return g.h(c, d, e, f); } > > If I forgot an "if e is empty, throw" check in here, I'll just insert it. > But if it was this: > > public A b(C c, D d, E e, F f) = g::h; > > I'm probably less likely to do that. > > This is a bit similar to why our style guide requires braces around > single-statement if blocks. It's too annoying to deal with inserting them > and removing them all the time as conditions change. > > Perhaps these costs don't add up to anything massive, but we should still > get a fix on them because if it turns out the benefits *also* don't add > up to something massive then....? > > I hope this is helpful. > > > On Wed, Sep 19, 2018 at 11:58 AM wrote: > >> 2018/9/19 11:42:16 -0700, alex.buckley at oracle.com: >> > https://bugs.openjdk.java.net/browse/JDK-8209434 >> >> Or, more readably: http://openjdk.java.net/jeps/8209434 >> >> - Mark >> > > > -- > Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com > From kevinb at google.com Fri Sep 21 23:07:14 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Fri, 21 Sep 2018 16:07:14 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <5BA29888.4000302@oracle.com> References: <5BA29888.4000302@oracle.com> Message-ID: "The method reference form can use most kinds of method references after the = sign: static and unbound method references, bound method references (if the receiver *variable* is in scope for the method declaration)" Can we still bind to any expression? private String a(String b, int c) throws SomeCheckedException = *d.e()*::f; ... and would this be valid whether it is `e()` or `f()` (or both) that throws SomeCheckedException? On Wed, Sep 19, 2018 at 11:52 AM Alex Buckley wrote: > https://bugs.openjdk.java.net/browse/JDK-8209434 > -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com From alex.buckley at oracle.com Mon Sep 24 17:17:18 2018 From: alex.buckley at oracle.com (Alex Buckley) Date: Mon, 24 Sep 2018 10:17:18 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: References: <5BA29888.4000302@oracle.com> Message-ID: <5BA91C1E.30401@oracle.com> On 9/21/2018 4:07 PM, Kevin Bourrillion wrote: > "The method reference form can use most kinds of method references after > the = sign: static and unbound method references, bound method > references (if the receiver *variable* is in scope for the method > declaration)" > > Can we still bind to any expression? > > private String a(String b, int c) > throws SomeCheckedException = *d.e()*::f; No limitation is intended on the receiver, as long as the method reference expression would be legal if it appeared in the traditional body of method `a`. (Details of this translation remain to be worked out.) Scope isn't the right concept to appeal to; for example, an instance variable is in scope throughout a static method, but that doesn't mean the variable can be used in the body of the static method. I'll remove the troublesome clause. Array creation references should also be mentioned alongside constructor references. > ... and would this be valid whether it is `e()` or `f()` (or both) that > throws SomeCheckedException? I expect so. Do you have a situation that suggests otherwise? Alex From kevinb at google.com Tue Sep 25 14:25:28 2018 From: kevinb at google.com (Kevin Bourrillion) Date: Tue, 25 Sep 2018 07:25:28 -0700 Subject: New JEP: Concise Method Bodies In-Reply-To: <5BA91C1E.30401@oracle.com> References: <5BA29888.4000302@oracle.com> <5BA91C1E.30401@oracle.com> Message-ID: On Mon, Sep 24, 2018 at 10:17 AM Alex Buckley wrote: On 9/21/2018 4:07 PM, Kevin Bourrillion wrote: > > > > private String a(String b, int c) > > throws SomeCheckedException = *d.e()*::f; > (Eek, I'll try to remind myself to stop boldfacing things.) > > ... and would this be valid whether it is `e()` or `f()` (or both) that > > throws SomeCheckedException? > > I expect so. Do you have a situation that suggests otherwise? > Nope, that sounds like what it should do, of course. Thanks! -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com From vicente.romero at oracle.com Tue Sep 25 19:35:46 2018 From: vicente.romero at oracle.com (Vicente Romero) Date: Tue, 25 Sep 2018 15:35:46 -0400 Subject: New JEP: Concise Method Bodies In-Reply-To: <5BA29888.4000302@oracle.com> References: <5BA29888.4000302@oracle.com> Message-ID: Hi all, I have published a public amber repo for the concise method bodies JEP. It can be found at [1], branch: concise-method-declarations. Also as suggested by Brian I have created a new finder, see [2]. Using it I have got some stats on the number of methods in the JDK that could potentially benefit from this JEP. Modulo possible cases in which the finder could be smarter these are the numbers so far: potential number of concise methods: 12770 total number of methods (modulo synthetic methods and constructors): 562636 for a percentage of: 2.27 Thanks, Vicente [1] http://hg.openjdk.java.net/amber/amber [2] http://hg.openjdk.java.net/amber/amber/file/cac8618a27ec/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java#l338 From forax at univ-mlv.fr Sun Sep 30 13:35:25 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Sun, 30 Sep 2018 15:35:25 +0200 (CEST) Subject: Concise method / method reference Message-ID: <2139881241.63125.1538314525386.JavaMail.zimbra@u-pem.fr> Hi all, i've played a little bit with the concise method prototype. i think that using '=' to 'assign' a method reference to a method signature - is visually too close to a field assignment. - send the wrong message because there is no assignment at runtime. A way to avoid the issue listed above is to replace '=' with a keyword. So instead of static IntConsumer bar() = FieldVersusMethod::foo; static IntConsumer bar = FieldVersusMethod::foo; using 'as' as keyword, we have static IntConsumer bar() as FieldVersusMethod::foo; static IntConsumer bar = FieldVersusMethod::foo; 'as' is perhaps not the best keyword here, but you get the idea. regards, R?mi From forax at univ-mlv.fr Sun Sep 30 13:48:13 2018 From: forax at univ-mlv.fr (Remi Forax) Date: Sun, 30 Sep 2018 15:48:13 +0200 (CEST) Subject: Lambda Concise method and void return type Message-ID: <1404563743.63309.1538315293569.JavaMail.zimbra@u-pem.fr> Testing the prototype, i've seen myself using -> null instead of a classical empty method body when i want to have a method that does nothing. class A { void f() -> null; // versus void f() { } } the compiler translates the concise version to aconst_null pop return instead of a plain return. Obviously, in the real world, people doesn't write empty methods all the time and i'm not sure if it's that important, anyway i think that question should be raised, should we want to support this a pattern ? R?mi From amaembo at gmail.com Sun Sep 30 14:30:21 2018 From: amaembo at gmail.com (Tagir Valeev) Date: Sun, 30 Sep 2018 21:30:21 +0700 Subject: Lambda Concise method and void return type In-Reply-To: <1404563743.63309.1538315293569.JavaMail.zimbra@u-pem.fr> References: <1404563743.63309.1538315293569.JavaMail.zimbra@u-pem.fr> Message-ID: Hello! I don't think that `void foo() -> null` should be supported. Like in lambdas if the method returns void, only expressions which can be used as expression statement should be allowed. I don't think that special support for empty bodies is necessary as {} is short enough. Especially if your code style is not very bureaucratic and allows you to write `void foo() {}` in single line. With best regards, Tagir Valeev. ??, 30 ????. 2018 ?., 20:48 Remi Forax : > Testing the prototype, i've seen myself using -> null instead of a > classical empty method body when i want to have a method that does nothing. > > class A { > void f() -> null; > // versus > void f() { > } > } > > the compiler translates the concise version to aconst_null pop return > instead of a plain return. > > Obviously, in the real world, people doesn't write empty methods all the > time and i'm not sure if it's that important, anyway i think that question > should be raised, should we want to support this a pattern ? > > R?mi >