From angelos.bimpoudis at oracle.com Fri Feb 2 21:18:42 2024 From: angelos.bimpoudis at oracle.com (Angelos Bimpoudis) Date: Fri, 2 Feb 2024 21:18:42 +0000 Subject: Integrated Implementation for JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview feature of Java 23) Message-ID: Hello all, Last week we integrated the implementation of JEP 455 on master. You can take a look at the JEP, try the new feature and give us your feedback (either on this list or directly to me). https://openjdk.org/jeps/455 https://cr.openjdk.org/~abimpoudis/instanceof/latest/ https://jdk.java.net/23/ (already available in Build 8 - 2024/2/2) (or https://openjdk.org/groups/build/doc/building.html) Best, Aggelos Biboudis -------------- next part -------------- An HTML attachment was scrubbed... URL: From duke at openjdk.org Sun Feb 4 18:20:08 2024 From: duke at openjdk.org (David Alayachew) Date: Sun, 4 Feb 2024 18:20:08 GMT Subject: [amber-docs] Integrated: Fixing the incorrect code example In-Reply-To: References: Message-ID: On Fri, 26 Jan 2024 16:25:32 GMT, David Alayachew wrote: > There are only 3 methods on java.util.regex.Matcher that have the name group. Here they are. > > https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Matcher.html#group() > > https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Matcher.html#group(int) > > https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Matcher.html#group(java.lang.String) > > And since this is an IntStream, the only possible method that could be matched is the 2nd link above. Based on that, it is clear that the code example meant to put an `m` instead of `Matcher`. This pull request has now been integrated. Changeset: 671d496d Author: David Alayachew Committer: Gavin Bierman URL: https://git.openjdk.org/amber-docs/commit/671d496d50d2f176f67645f3209ceafd8f390992 Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod Fixing the incorrect code example ------------- PR: https://git.openjdk.org/amber-docs/pull/23 From ian at darwinsys.com Tue Feb 6 16:54:58 2024 From: ian at darwinsys.com (Ian Darwin) Date: Tue, 6 Feb 2024 11:54:58 -0500 Subject: JEP445 meets JEP459 Message-ID: <26d5a32b-338a-4aae-944e-a86378ce90a5@darwinsys.com> In JEP 445 you wrote: > The changes we offer here are just one step in making Java easier to > learn. They do not even address all the speed bumps in the above > /Hello, World!/ program: The beginner may still be puzzled by the > mysterious |System.out.println| incantation, and still needs to import > basic utility classes and methods for essential functionality even in > first-week programs. We may address these pains in a future JEP. While experimenting with the String Template feature, it occurs to me that a relatively simple expansion of String Templates would pave over another of those speed bumps. Basically: ??? PRINT."Hello \{name}. Your balance is \{amount}"; Indeed, the beginner who hasn't yet met string templates can use the degenerate case ??? PRINT."Hello world"; and then later "need not discard what they learned in the early stages, but rather they see how it all fits within the larger picture." This compares favorably with, e.g., Python 3's print('Hello world') and print(f'Hello {name}, your balance is {balance}') This seems like a fairly obvious extension, so I ask: Do you already have such a thing up your collective sleeves or, if not, do you think it might be grounds for a JEP proposal? -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Feb 6 17:14:52 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 6 Feb 2024 12:14:52 -0500 Subject: JEP445 meets JEP459 In-Reply-To: <26d5a32b-338a-4aae-944e-a86378ce90a5@darwinsys.com> References: <26d5a32b-338a-4aae-944e-a86378ce90a5@darwinsys.com> Message-ID: Similar things have been suggested before, but there are two primary concerns here that make it a "clever" but unattractive-in-the-long-term direction. The main one is "the onramp should lead to the highway."? If we give a special, magic way to print templated strings, but nothing else, this is an easy incantation to teach, but it doesn't go very far.? If you want to do even a little bit more (e.g., print to a file, or to standard error, or just print out a string with no formatting, etc), you have to switch to a completely different mechanism, and now you need to know TWO things and know when to use one or the other.? It is a shortcut that becomes a "beginner's dialect" because it does not lead smoothly to learning the "regular" language. Second, the possibility that a string template could have side-effects instead of (or worse, in addition to) just taking the ingredients and mixing them up into a composite thing makes the concept of string templates more complicated.? While we can't prevent people from sneaking side effects into their template processors, we shouldn't encourage this, or suggest that all users have to work this into their mental model. So its possible, but I don't think its a good direction for the language. On 2/6/2024 11:54 AM, Ian Darwin wrote: > > In JEP 445 you wrote: > >> The changes we offer here are just one step in making Java easier to >> learn. They do not even address all the speed bumps in the above >> /Hello, World!/ program: The beginner may still be puzzled by the >> mysterious |System.out.println| incantation, and still needs to >> import basic utility classes and methods for essential functionality >> even in first-week programs. We may address these pains in a future JEP. > While experimenting with the String Template feature, it occurs to me > that a relatively simple expansion of String Templates would pave over > another of those speed bumps. Basically: > > ??? PRINT."Hello \{name}. Your balance is \{amount}"; > > Indeed, the beginner who hasn't yet met string templates can use the > degenerate case > > ??? PRINT."Hello world"; > > and then later "need not discard what they learned in the early > stages, but rather they see how it all fits within the larger picture." > > This compares favorably with, e.g., Python 3's > > print('Hello world') and > > print(f'Hello {name}, your balance is {balance}') > > This seems like a fairly obvious extension, so I ask: Do you already > have such a thing up your collective sleeves or, if not, do you think > it might be grounds for a JEP proposal? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ian at darwinsys.com Tue Feb 6 17:41:33 2024 From: ian at darwinsys.com (Ian Darwin) Date: Tue, 6 Feb 2024 12:41:33 -0500 Subject: JEP445 meets JEP459 In-Reply-To: References: <26d5a32b-338a-4aae-944e-a86378ce90a5@darwinsys.com> Message-ID: <31854059-5dfc-4bda-820d-796af3bfd046@darwinsys.com> I see your main point but can't resist the odd quibble: On 2/6/24 12:14, Brian Goetz wrote: > Similar things have been suggested before, but there are two primary > concerns here that make it a "clever" but > unattractive-in-the-long-term direction. > > The main one is "the onramp should lead to the highway."? If we give a > special, magic way to print templated strings, but nothing else, this > is an easy incantation to teach, but it doesn't go very far.? If you > want to do even a little bit more (e.g., print to a file, or to > standard error, or just print out a string with no formatting, etc), > you have to switch to a completely different mechanism, A string with no formatting would be handled like any other, just as STR."Hello world" yields (redundantly) a string with no formatting. Printing to a file is more complicated anyway as you don't usually get there without meeting IOException and try/catch or at least throws. But yes, it is a different mechanism; as part of smoothing that out, students can initially be taught that PRINT."..." is "just a shortcut" for System.out.println(STR."..."); as a side benefit, they learn about this string template that can be used anywhere. > and now you need to know TWO things and know when to use one or the > other.? It is a shortcut that becomes a "beginner's dialect" because > it does not lead smoothly to learning the "regular" language. > > Second, the possibility that a string template could have side-effects > instead of (or worse, in addition to) just taking the ingredients and > mixing them up into a composite thing makes the concept of string > templates more complicated.? While we can't prevent people from > sneaking side effects into their template processors, we shouldn't > encourage this, or suggest that all users have to work this into their > mental model. But this template processor, like STR itself, would be a final field in perhaps the StringTemplate class, imported automatically like STR. It is your processor, not theirs. > > > So its possible, but I don't think its a good direction for the language. It's your call. Thanks for the feedback. I'll withdraw the suggestion and hope that some day, some way can be found to simplify this particular "speed bump". I respect that the team always holds off until the best or "correct" way can be found. > > On 2/6/2024 11:54 AM, Ian Darwin wrote: >> While experimenting with the String Template feature, it occurs to me >> that a relatively simple expansion of String Templates would pave >> over another of those speed bumps. Basically: >> >> ??? PRINT."Hello \{name}. Your balance is \{amount}"; >> >> Indeed, the beginner who hasn't yet met string templates can use the >> degenerate case >> >> ??? PRINT."Hello world"; >> >> and then later "need not discard what they learned in the early >> stages, but rather they see how it all fits within the larger picture." >> >> This compares favorably with, e.g., Python 3's >> >> print('Hello world') and >> >> print(f'Hello {name}, your balance is {balance}') >> >> This seems like a fairly obvious extension, so I ask: Do you already >> have such a thing up your collective sleeves or, if not, do you think >> it might be grounds for a JEP proposal? >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Feb 6 18:05:59 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 6 Feb 2024 13:05:59 -0500 Subject: JEP445 meets JEP459 In-Reply-To: <31854059-5dfc-4bda-820d-796af3bfd046@darwinsys.com> References: <26d5a32b-338a-4aae-944e-a86378ce90a5@darwinsys.com> <31854059-5dfc-4bda-820d-796af3bfd046@darwinsys.com> Message-ID: <38766d81-5de5-4110-b086-5c8f39bbb88a@oracle.com> I'll just add one more point to try and illustrate why it makes me uncomfortable.? In the python example: ??? print(f'Hello {name}, your balance is {balance}') there are two mechanisms here -- f-strings and print().? And the two are completely orthogonal; I can put any string I want inside the parens and it works, and I can take the f-string and put the result wherever I can put a string.? Each can be designed independently, and reasoned about independently, and they meet at the String type, and because of that, they compose with no additional coordination. The string processor suggested here complects two things that should be orthogonal: string interpolation and writing to stdout.? If I want to write to std out without interpolation (maybe I already have a string in hand), or I want to interpolate without printing, now I have to use another mechanism.? So it can't replace either println *or* STR, and that means people have to learn all three.? Whereas the status quo is more like the python example: we have template expressions using STR in the place of f-strings, and we have a method that takes any string and prints it.? The main defect of the status quo is the confusing rules surrounding qualification, but fixing that by denormalizing what is already a sensible separation of concerns is one step forward and two steps back.? Instead, we should address the qualification problem more directly. On 2/6/2024 12:41 PM, Ian Darwin wrote: > I see your main point but can't resist the odd quibble: > > On 2/6/24 12:14, Brian Goetz wrote: >> Similar things have been suggested before, but there are two primary >> concerns here that make it a "clever" but >> unattractive-in-the-long-term direction. >> >> The main one is "the onramp should lead to the highway."? If we give >> a special, magic way to print templated strings, but nothing else, >> this is an easy incantation to teach, but it doesn't go very far.? If >> you want to do even a little bit more (e.g., print to a file, or to >> standard error, or just print out a string with no formatting, etc), >> you have to switch to a completely different mechanism, > > A string with no formatting would be handled like any other, just as > STR."Hello world" yields (redundantly) a string with no formatting. > > Printing to a file is more complicated anyway as you don't usually get > there without meeting IOException and try/catch or at least throws. > > But yes, it is a different mechanism; as part of smoothing that out, > students can initially be taught that PRINT."..." is "just a shortcut" > for System.out.println(STR."..."); as a side benefit, they learn about > this string template that can be used anywhere. > >> and now you need to know TWO things and know when to use one or the >> other.? It is a shortcut that becomes a "beginner's dialect" because >> it does not lead smoothly to learning the "regular" language. >> >> Second, the possibility that a string template could have >> side-effects instead of (or worse, in addition to) just taking the >> ingredients and mixing them up into a composite thing makes the >> concept of string templates more complicated.? While we can't prevent >> people from sneaking side effects into their template processors, we >> shouldn't encourage this, or suggest that all users have to work this >> into their mental model. > But this template processor, like STR itself, would be a final field > in perhaps the StringTemplate class, imported automatically like STR. > It is your processor, not theirs. >> >> >> So its possible, but I don't think its a good direction for the >> language. > It's your call. Thanks for the feedback. I'll withdraw the suggestion > and hope that some day, some way can be found to simplify this > particular "speed bump". I respect that the team always holds off > until the best or "correct" way can be found. >> >> On 2/6/2024 11:54 AM, Ian Darwin wrote: >>> While experimenting with the String Template feature, it occurs to >>> me that a relatively simple expansion of String Templates would pave >>> over another of those speed bumps. Basically: >>> >>> ??? PRINT."Hello \{name}. Your balance is \{amount}"; >>> >>> Indeed, the beginner who hasn't yet met string templates can use the >>> degenerate case >>> >>> ??? PRINT."Hello world"; >>> >>> and then later "need not discard what they learned in the early >>> stages, but rather they see how it all fits within the larger picture." >>> >>> This compares favorably with, e.g., Python 3's >>> >>> print('Hello world') and >>> >>> print(f'Hello {name}, your balance is {balance}') >>> >>> This seems like a fairly obvious extension, so I ask: Do you already >>> have such a thing up your collective sleeves or, if not, do you >>> think it might be grounds for a JEP proposal? >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ian at darwinsys.com Tue Feb 6 19:11:04 2024 From: ian at darwinsys.com (Ian Darwin) Date: Tue, 6 Feb 2024 14:11:04 -0500 Subject: JEP445 meets JEP459 In-Reply-To: <38766d81-5de5-4110-b086-5c8f39bbb88a@oracle.com> References: <26d5a32b-338a-4aae-944e-a86378ce90a5@darwinsys.com> <31854059-5dfc-4bda-820d-796af3bfd046@darwinsys.com> <38766d81-5de5-4110-b086-5c8f39bbb88a@oracle.com> Message-ID: <53c49377-7462-46a0-883e-04ce81ebf594@darwinsys.com> On 2/6/24 13:05, Brian Goetz wrote: > I'll just add one more point to try and illustrate why it makes me > uncomfortable.? In the python example: > > ??? print(f'Hello {name}, your balance is {balance}') > > there are two mechanisms here -- f-strings and print().? And the two > are completely orthogonal; I can put any string I want inside the > parens and it works, and I can take the f-string and put the result > wherever I can put a string.? Each can be designed independently, and > reasoned about independently, and they meet at the String type, and > because of that, they compose with no additional coordination. > > The string processor suggested here complects two things that should > be orthogonal: string interpolation and writing to stdout. If I want > to write to std out without interpolation (maybe I already have a > string in hand), or I want to interpolate without printing, now I have > to use another mechanism.? So it can't replace either println *or* > STR, and that means people have to learn all three.? Whereas the > status quo is more like the python example: we have template > expressions using STR in the place of f-strings, and we have a method > that takes any string and prints it.? The main defect of the status > quo is the confusing rules surrounding qualification, but fixing that > by denormalizing what is already a sensible separation of concerns is > one step forward and two steps back.? Instead, we should address the > qualification problem more directly. You are, as usual, quite right. Therefore, one possible way to take it head on: in the System class, redefine "out" along the following lines (I realize that System.out is more complicated but this is the sketch): public static PrintStream out = new PrintStream() { |? public static void PRINT(String line) { println(line); } }; and have this System.out.PRINT be auto-statically imported, like STR is (y first thought was just to add the method to PrintStream, but that would pollute the latter's namespace). It avoids confounding the two ideas and paves over the rules about qualification. Students will learn soon enough that System.out.println() can be used (when they start reading old code), but they don't have to learn it up front. > > > > On 2/6/2024 12:41 PM, Ian Darwin wrote: >> I see your main point but can't resist the odd quibble: >> >> On 2/6/24 12:14, Brian Goetz wrote: >>> Similar things have been suggested before, but there are two primary >>> concerns here that make it a "clever" but >>> unattractive-in-the-long-term direction. >>> >>> The main one is "the onramp should lead to the highway."? If we give >>> a special, magic way to print templated strings, but nothing else, >>> this is an easy incantation to teach, but it doesn't go very far.? >>> If you want to do even a little bit more (e.g., print to a file, or >>> to standard error, or just print out a string with no formatting, >>> etc), you have to switch to a completely different mechanism, >> >> A string with no formatting would be handled like any other, just as >> STR."Hello world" yields (redundantly) a string with no formatting. >> >> Printing to a file is more complicated anyway as you don't usually >> get there without meeting IOException and try/catch or at least throws. >> >> But yes, it is a different mechanism; as part of smoothing that out, >> students can initially be taught that PRINT."..." is "just a >> shortcut" for System.out.println(STR."..."); as a side benefit, they >> learn about this string template that can be used anywhere. >> >>> and now you need to know TWO things and know when to use one or the >>> other.? It is a shortcut that becomes a "beginner's dialect" because >>> it does not lead smoothly to learning the "regular" language. >>> >>> Second, the possibility that a string template could have >>> side-effects instead of (or worse, in addition to) just taking the >>> ingredients and mixing them up into a composite thing makes the >>> concept of string templates more complicated.? While we can't >>> prevent people from sneaking side effects into their template >>> processors, we shouldn't encourage this, or suggest that all users >>> have to work this into their mental model. >> But this template processor, like STR itself, would be a final field >> in perhaps the StringTemplate class, imported automatically like STR. >> It is your processor, not theirs. >>> >>> >>> So its possible, but I don't think its a good direction for the >>> language. >> It's your call. Thanks for the feedback. I'll withdraw the suggestion >> and hope that some day, some way can be found to simplify this >> particular "speed bump". I respect that the team always holds off >> until the best or "correct" way can be found. >>> >>> On 2/6/2024 11:54 AM, Ian Darwin wrote: >>>> While experimenting with the String Template feature, it occurs to >>>> me that a relatively simple expansion of String Templates would >>>> pave over another of those speed bumps. Basically: >>>> >>>> ??? PRINT."Hello \{name}. Your balance is \{amount}"; >>>> >>>> Indeed, the beginner who hasn't yet met string templates can use >>>> the degenerate case >>>> >>>> ??? PRINT."Hello world"; >>>> >>>> and then later "need not discard what they learned in the early >>>> stages, but rather they see how it all fits within the larger picture." >>>> >>>> This compares favorably with, e.g., Python 3's >>>> >>>> print('Hello world') and >>>> >>>> print(f'Hello {name}, your balance is {balance}') >>>> >>>> This seems like a fairly obvious extension, so I ask: Do you >>>> already have such a thing up your collective sleeves or, if not, do >>>> you think it might be grounds for a JEP proposal? >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark.reinhold at oracle.com Thu Feb 15 20:02:44 2024 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Thu, 15 Feb 2024 20:02:44 +0000 Subject: New candidate JEP: 465: String Templates Message-ID: <20240215200239.22A846C1C13@eggemoggin.niobe.net> https://openjdk.org/jeps/465 Summary: Enhance the Java programming language with string templates. String templates complement Java's existing string literals and text blocks by coupling literal text with embedded expressions and template processors to produce specialized results. - Mark From im741314 at gmail.com Sun Feb 18 11:53:56 2024 From: im741314 at gmail.com (Charles) Date: Sun, 18 Feb 2024 19:53:56 +0800 Subject: possible bug with instanceof pattern matching Message-ID: Hi all What I'm about to report below is *openjdk 17*. This doesn't compile if (ex instanceof JedisException je || (ex instanceof ExecutionException ee && ee.getCause() instanceof JedisException je) ){ ... blah blah } reason being the second je is already defined in the scope. [image: image.png] if you think about it. if ex is je, then, the second part won't trigger. And if the second part is reached, then ex is not je. Hence there is only going to be one statement mapped to je. no confusion here. I feel this should be allowed. Let's assume the above is the way it should be. I use different names for the second variable. if (ex instanceof JedisException je || (ex instanceof ExecutionException ee && ee.getCause() instanceof JedisException second_je) ) { log.error(je); log.error(second_je); } [image: image.png] This still doesn't compile. I would like to bring this issue up for discussion. and as always, have a great day *Best Regards* *Charles* -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 37408 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 33303 bytes Desc: not available URL: From brian.goetz at oracle.com Sun Feb 18 15:32:48 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 18 Feb 2024 10:32:48 -0500 Subject: possible bug with instanceof pattern matching In-Reply-To: References: Message-ID: <40b4d583-971d-4079-b5ab-f4e34a0ff32a@oracle.com> This is not a bug; this potential feature was discussed at some length during the design process. Another way this potential-feature could show up is: ??? switch (container) { ??????? case Box(String s), Bag(String s): ... use s ... ??? } The reason that we chose not to proceed with such "binding merging" is that when you get inside the block, `je` is one variable with two declarations; you don't really know where the declaration is.? (So IDE navigations like "go to declaration" would have to learn to highlight TWO (or more) declarations, for example.) This feature isn't fundamentally impossible, and we could consider it again in the future, but it was a deliberate decision to not go this far at this time. On 2/18/2024 6:53 AM, Charles wrote: > Hi all > > > What I'm about to report below is *openjdk 17*. > > > This doesn't compile > > if (ex instanceof JedisException je > ? ? ? ? ? ? ? ? ? ? ? ? ? ? || (ex instanceof ExecutionException ee && > ee.getCause() instanceof JedisException je) > ? ? ? ? ? ? ){ > ? ?... blah blah > } > > reason being the second je is already defined in the scope. > image.png > > if you think about it. if ex is je, then, the second part won't > trigger. And if the second part is reached, then ex is not je. Hence > there is only going to be one statement mapped to je. > no confusion here. I feel this should be allowed. > > > Let's assume the above is the way it should be. I use?different names > for the second variable. > > ?if (ex instanceof JedisException je > ? ? ? ? ? ? ? ? ? ? || (ex instanceof ExecutionException ee && > ee.getCause() instanceof JedisException second_je) > ? ? ? ? ? ? ) { > log.error(je); > log.error(second_je); > ? ? ? ? ? ? } > > image.png > This still doesn't compile. > > I would like to bring this issue up for discussion. > > > > > and as always, have a great day > * > * > *Best Regards > * > *Charles* > * > * > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 37408 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 33303 bytes Desc: not available URL: From dennis_woithe at web.de Sun Feb 18 17:54:58 2024 From: dennis_woithe at web.de (dennis_woithe at web.de) Date: Sun, 18 Feb 2024 18:54:58 +0100 Subject: Suggestion for JEP draft 8323335 Message-ID: An HTML attachment was scrubbed... URL: From cay.horstmann at gmail.com Sun Feb 18 21:12:09 2024 From: cay.horstmann at gmail.com (Cay Horstmann) Date: Sun, 18 Feb 2024 22:12:09 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: Message-ID: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 for beginning students. I am the author of college texts for introductory programming. Like other authors, I introduce the Scanner class (and not Console) for reading user input. Given that students already know about System.out, it is simpler to call System.out.print("How old are you? "); int x = in.nextInt(); // in is a Scanner than int x = Integer.parseInt(console.readLine("How old are you? ")); or with the JEP draft: int x = Integer.parseInt(input("How old are you? ")); Then again, having a prompt string is nice too, so I could imagine using the Console API with Integer.parseInt and Double.parseDouble, instead of Scanner.nextInt/nextDouble. But why have a third API, i.e. "input"? I think there are two feasible directions. Either embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding "input" into the mix is just clutter, and ambiguous clutter at that. At least readLine makes it clear that the entire line is consumed. Cheers, Cay -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From brian.goetz at oracle.com Sun Feb 18 21:43:58 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 18 Feb 2024 16:43:58 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> Message-ID: I think you are counting characters and not counting concepts. Scanner has a ton of complexity in it that can easily trip up beginners.? The main sin (though there are others) is that input and parsing are complected (e.g., nextInt), which only causes more problems (e.g., end of line issues.)?? Reading from the console is clearly a () -> String operation.? The input() method does one thing, which is get a line of text.? That's simple. Integer.parseInt (or, soon, patterns that match against string and bind an int) also does one thing: convert a string from int.? It may seem verbose to have to do both explicitly, but it allows each of these operations to be simple, and it is perfectly obvious what is going on.? On the other hand, Scanner is a world of complexity on its own. Console::readLine is nice, but first you have to get a Console. ("Why can I print something without having to get some magic helper object, but I can't do the same for reading?")? What we're optimizing for here is conceptual simplicity; the simplest possible input method is the inverse of println.? The fact that input has to be validated is a fact of life; we can treat validation separately from IO (and we should), and it gets simpler when you do. On 2/18/2024 4:12 PM, Cay Horstmann wrote: > I would like to comment on the simplicity of > https://openjdk.org/jeps/8323335 for beginning students. > > I am the author of college texts for introductory programming. Like > other authors, I introduce the Scanner class (and not Console) for > reading user input. Given that students already know about System.out, > it is simpler to call > > System.out.print("How old are you? "); > int x = in.nextInt(); // in is a Scanner > > than > > int x = Integer.parseInt(console.readLine("How old are you? ")); > > or with the JEP draft: > > int x = Integer.parseInt(input("How old are you? ")); > > Then again, having a prompt string is nice too, so I could imagine > using the Console API with Integer.parseInt and Double.parseDouble, > instead of Scanner.nextInt/nextDouble. > > But why have a third API, i.e. "input"? > > I think there are two feasible directions. Either embrace the Scanner > API and next/nextInt/nextDouble/nextLine, or the Console API and > readLine. Adding "input" into the mix is just clutter, and ambiguous > clutter at that. At least readLine makes it clear that the entire line > is consumed. > > Cheers, > > Cay > > -- > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From brian.goetz at oracle.com Sun Feb 18 22:08:04 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 18 Feb 2024 17:08:04 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> Message-ID: OK, so is this really just that that you are bikeshedding the name?? Renaming `input` to `readLine`? This is a perfectly reasonable naming choice, of course, but also, not what you suggested the first time around: > ... "a third API" ... > ... "there are two feasible directions" ... So what exactly are you suggesting? On 2/18/2024 5:03 PM, Cay Horstmann wrote: > Like I said, either the scanner methods or the console methods are fine. > > I am of course aware of the utility/complexity of Scanner, and can > understand the motivation to have a simpler/feebler behavior in > SimpleIO. Like the one in Console. > > You don't have to "get a console". A SimpleIO.readLine method can just > invoke readLine on the system console. > > My objection is to add yet another "input" method into the mix. > "input" is weak. Does it read a token or the entire line? Does it > consume the newline? And if it does just what readLine does, why > another method name? Because "input" is three characters fewer? Let's > not count characters. > > On 18/02/2024 22.43, Brian Goetz wrote: >> I think you are counting characters and not counting concepts. >> >> Scanner has a ton of complexity in it that can easily trip up >> beginners.? The main sin (though there are others) is that input and >> parsing are complected (e.g., nextInt), which only causes more >> problems (e.g., end of line issues.)?? Reading from the console is >> clearly a () -> String operation.? The input() method does one thing, >> which is get a line of text.? That's simple. >> >> Integer.parseInt (or, soon, patterns that match against string and >> bind an int) also does one thing: convert a string from int.? It may >> seem verbose to have to do both explicitly, but it allows each of >> these operations to be simple, and it is perfectly obvious what is >> going on. On the other hand, Scanner is a world of complexity on its >> own. >> >> Console::readLine is nice, but first you have to get a Console. ("Why >> can I print something without having to get some magic helper object, >> but I can't do the same for reading?")? What we're optimizing for >> here is conceptual simplicity; the simplest possible input method is >> the inverse of println.? The fact that input has to be validated is a >> fact of life; we can treat validation separately from IO (and we >> should), and it gets simpler when you do. >> >> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>> I would like to comment on the simplicity of >>> https://openjdk.org/jeps/8323335 for beginning students. >>> >>> I am the author of college texts for introductory programming. Like >>> other authors, I introduce the Scanner class (and not Console) for >>> reading user input. Given that students already know about >>> System.out, it is simpler to call >>> >>> System.out.print("How old are you? "); >>> int x = in.nextInt(); // in is a Scanner >>> >>> than >>> >>> int x = Integer.parseInt(console.readLine("How old are you? ")); >>> >>> or with the JEP draft: >>> >>> int x = Integer.parseInt(input("How old are you? ")); >>> >>> Then again, having a prompt string is nice too, so I could imagine >>> using the Console API with Integer.parseInt and Double.parseDouble, >>> instead of Scanner.nextInt/nextDouble. >>> >>> But why have a third API, i.e. "input"? >>> >>> I think there are two feasible directions. Either embrace the >>> Scanner API and next/nextInt/nextDouble/nextLine, or the Console API >>> and readLine. Adding "input" into the mix is just clutter, and >>> ambiguous clutter at that. At least readLine makes it clear that the >>> entire line is consumed. >>> >>> Cheers, >>> >>> Cay >>> >>> -- >>> >>> Cay S. Horstmann | >>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>> | mailto:cay at horstmann.com >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cay at horstmann.com Sun Feb 18 22:03:19 2024 From: cay at horstmann.com (Cay Horstmann) Date: Sun, 18 Feb 2024 23:03:19 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> Message-ID: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> Like I said, either the scanner methods or the console methods are fine. I am of course aware of the utility/complexity of Scanner, and can understand the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in Console. You don't have to "get a console". A SimpleIO.readLine method can just invoke readLine on the system console. My objection is to add yet another "input" method into the mix. "input" is weak. Does it read a token or the entire line? Does it consume the newline? And if it does just what readLine does, why another method name? Because "input" is three characters fewer? Let's not count characters. On 18/02/2024 22.43, Brian Goetz wrote: > I think you are counting characters and not counting concepts. > > Scanner has a ton of complexity in it that can easily trip up beginners.? The main sin (though there are others) is that input and parsing are complected (e.g., nextInt), which only causes more problems (e.g., end of line issues.)?? Reading from the console is clearly a () -> String operation.? The input() method does one thing, which is get a line of text.? That's simple. > > Integer.parseInt (or, soon, patterns that match against string and bind an int) also does one thing: convert a string from int.? It may seem verbose to have to do both explicitly, but it allows each of these operations to be simple, and it is perfectly obvious what is going on. On the other hand, Scanner is a world of complexity on its own. > > Console::readLine is nice, but first you have to get a Console. ("Why can I print something without having to get some magic helper object, but I can't do the same for reading?")? What we're optimizing for here is conceptual simplicity; the simplest possible input method is the inverse of println.? The fact that input has to be validated is a fact of life; we can treat validation separately from IO (and we should), and it gets simpler when you do. > > On 2/18/2024 4:12 PM, Cay Horstmann wrote: >> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 for beginning students. >> >> I am the author of college texts for introductory programming. Like other authors, I introduce the Scanner class (and not Console) for reading user input. Given that students already know about System.out, it is simpler to call >> >> System.out.print("How old are you? "); >> int x = in.nextInt(); // in is a Scanner >> >> than >> >> int x = Integer.parseInt(console.readLine("How old are you? ")); >> >> or with the JEP draft: >> >> int x = Integer.parseInt(input("How old are you? ")); >> >> Then again, having a prompt string is nice too, so I could imagine using the Console API with Integer.parseInt and Double.parseDouble, instead of Scanner.nextInt/nextDouble. >> >> But why have a third API, i.e. "input"? >> >> I think there are two feasible directions. Either embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding "input" into the mix is just clutter, and ambiguous clutter at that. At least readLine makes it clear that the entire line is consumed. >> >> Cheers, >> >> Cay >> >> -- >> >> Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com > -- -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From talden at gmail.com Sun Feb 18 23:11:25 2024 From: talden at gmail.com (Aaron Scott-Boddendijk) Date: Mon, 19 Feb 2024 12:11:25 +1300 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> Message-ID: > Scanner has a ton of complexity in it that can easily trip up beginners. This part should be said again and louder. As someone who spends a lot of time assisting new programmers online (mostly Discord/Reddit), this is a multiple-times-a-day, every day of the week problem (and this is not hyperbole). This occurs so very often that many such communities have prepared bot-responses making exactly Brian's point (using `==` with `String` is probably the other really common one). `Scanner` is a highly versatile tool for blasting holes in the feet of beginners. And promoting `Scanner.nextInt()` when you really mean "line of input that is an int" is aiming the gun. The individual concepts have to be visible or we'll continue to maim new programmers. On Mon, Feb 19, 2024 at 10:44?AM Brian Goetz wrote: > I think you are counting characters and not counting concepts. > > Scanner has a ton of complexity in it that can easily trip up > beginners. The main sin (though there are others) is that input and > parsing are complected (e.g., nextInt), which only causes more problems > (e.g., end of line issues.) Reading from the console is clearly a () > -> String operation. The input() method does one thing, which is get a > line of text. That's simple. > > Integer.parseInt (or, soon, patterns that match against string and bind > an int) also does one thing: convert a string from int. It may seem > verbose to have to do both explicitly, but it allows each of these > operations to be simple, and it is perfectly obvious what is going on. > On the other hand, Scanner is a world of complexity on its own. > > Console::readLine is nice, but first you have to get a Console. ("Why > can I print something without having to get some magic helper object, > but I can't do the same for reading?") What we're optimizing for here > is conceptual simplicity; the simplest possible input method is the > inverse of println. The fact that input has to be validated is a fact > of life; we can treat validation separately from IO (and we should), and > it gets simpler when you do. > > On 2/18/2024 4:12 PM, Cay Horstmann wrote: > > I would like to comment on the simplicity of > > https://openjdk.org/jeps/8323335 for beginning students. > > > > I am the author of college texts for introductory programming. Like > > other authors, I introduce the Scanner class (and not Console) for > > reading user input. Given that students already know about System.out, > > it is simpler to call > > > > System.out.print("How old are you? "); > > int x = in.nextInt(); // in is a Scanner > > > > than > > > > int x = Integer.parseInt(console.readLine("How old are you? ")); > > > > or with the JEP draft: > > > > int x = Integer.parseInt(input("How old are you? ")); > > > > Then again, having a prompt string is nice too, so I could imagine > > using the Console API with Integer.parseInt and Double.parseDouble, > > instead of Scanner.nextInt/nextDouble. > > > > But why have a third API, i.e. "input"? > > > > I think there are two feasible directions. Either embrace the Scanner > > API and next/nextInt/nextDouble/nextLine, or the Console API and > > readLine. Adding "input" into the mix is just clutter, and ambiguous > > clutter at that. At least readLine makes it clear that the entire line > > is consumed. > > > > Cheers, > > > > Cay > > > > -- > > > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Feb 19 00:56:22 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Sun, 18 Feb 2024 19:56:22 -0500 Subject: Suggestion for JEP draft 8323335 In-Reply-To: References: Message-ID: I have nothing useful to add other than saying that, yes, you are in the right spot, and I also think this feature is a really good idea. That said, having it return the object in question means that tracing down your print statements so that you can delete them will be a little harder. Not a good enough reason to say no, mind you, but something to keep in mind. On Sun, Feb 18, 2024, 1:00?PM wrote: > Hello, > I hope this email finds you well. > I have recently reviewed the draft for the JEP "Implicitly Declared > Classes and Instance Main Methods (Third Preview)" and came up with a > suggestion for a minor enhancement to the SimpleIO class. > The JEP aims to enhance the accessibility of simple IO actions, primarily > by introducing the SimpleIO class to the java.io package with the > following signatures: > > public class SimpleIO { > public static void println(Object obj) ... > public static void print(Object obj) ... > public static String input(String prompt) throws UncheckedIOException > ... > } > > One of the proposed functionalities is to allow implicitly declared > classes to automatically import the static methods of SimpleIO, thereby > simplifying console input and output operations for beginner programmers. > I propose a small addition to the SimpleIO class that would enhance its > usability further. Specifically, I suggest modifying the println and print > methods to return the passed object, enabling the inlining of print(ln) > statements. Here's the proposed modification: > > > public static T println(T obj) { > System.out.println(obj); > return obj; > } > public static T print(T obj) { > System.out.print(obj); > return obj; > } > > This enhancement would facilitate constructs such as: > > return foo > ? println(bar()) > : baz(); > > This change would particularly benefit beginners who wish to quickly print > something without first creating a variable for it. Additionally, users > exploring the SimpleIO class would have a very basic exposure to generic > methods. > I believe this suggestion aligns with the objectives of the JEP and would > enhance the user experience for novice programmers. > Please let me know if this email is the appropriate channel for submitting > such suggestions. If not, I would appreciate guidance on the correct > procedure. > Thank you for considering my proposal. > > Best regards, > Dennis Woithe > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Mon Feb 19 08:03:49 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Mon, 19 Feb 2024 09:03:49 +0100 (CET) Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> Message-ID: <528334885.9633181.1708329829296.JavaMail.zimbra@univ-eiffel.fr> ----- Original Message ----- > From: "cay horstmann" > To: "amber-dev" > Sent: Sunday, February 18, 2024 10:12:09 PM > Subject: SimpleIO in JEP draft 8323335 > I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 > for beginning students. > > I am the author of college texts for introductory programming. Like other > authors, I introduce the Scanner class (and not Console) for reading user > input. Given that students already know about System.out, it is simpler to call > > System.out.print("How old are you? "); > int x = in.nextInt(); // in is a Scanner > > than > > int x = Integer.parseInt(console.readLine("How old are you? ")); > > or with the JEP draft: > > int x = Integer.parseInt(input("How old are you? ")); > > Then again, having a prompt string is nice too, so I could imagine using the > Console API with Integer.parseInt and Double.parseDouble, instead of > Scanner.nextInt/nextDouble. > > But why have a third API, i.e. "input"? > > I think there are two feasible directions. Either embrace the Scanner API and > next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding > "input" into the mix is just clutter, and ambiguous clutter at that. At least > readLine makes it clear that the entire line is consumed. "input" is used in Python, but in Python, "print" means print and add a new line. So either we are consistent with Python and we have "input"/"print" and no "println", or we are more like the other IO methods in Java and use "println" and "readLine". One can note that this is not fully consistent, because either "println" should be "printLine" or "readLine" should be "readln". But this is how Java actually works. I also entertained the idea of using a varargs for "println" to avoid to teach "+" on string (or STR."") at the beginning, like console.log() does in JavaScript. In that case, we can add an overload of the existing "println", like this static void println(Object first, Object... others) I think it has to be an overload because you still want to take a look to the javadoc of "readLine" and "println" without seeing any "..." and it can not be println(Object...) because it will magically works with arrays of objects but not with arrays of primitives. In one hand, i'n not sure about that adding "println(Object, Object...)" is a good idea, we may want to keep it simple. In the other hand, i'm pretty sure "print" should be removed, because it's confusing to have both "print" and "println" (at least there is not "printf") and the semantics of "print" is not obvious for beginners ("println" and "readLine" are line oriented, but "print" is not). > > Cheers, > > Cay regards, R?mi > > -- > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From cay at horstmann.com Mon Feb 19 08:09:16 2024 From: cay at horstmann.com (Cay Horstmann) Date: Mon, 19 Feb 2024 09:09:16 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> Message-ID: Yes, that's what I am saying. If scanners live in vain, stick with a subset of the Console methods. Use its readLine. Make it so that SimpleIO uses System.console(). And add print and println to Console. The JEP talks about being able to start programming without having to know about static methods. How does a beginner read a number? With Integer.parseInt(readLine(prompt))? What about locales? Is print/println localized? Console.printf is. If so, how are beginners from around the world supposed to read localized numbers? With NumberFormat.getInstance().parse(readLine(prompt))? Adding localized readInt/readDouble to SimpleIO might do the trick. Do they consume the trailing newline? (The equivalent Scanner methods don't, which is definitely a sharp edge for beginners.) On 18/02/2024 23.08, Brian Goetz wrote: > OK, so is this really just that that you are bikeshedding the name?? Renaming `input` to `readLine`? > > This is a perfectly reasonable naming choice, of course, but also, not what you suggested the first time around: > > > ... "a third API" ... > > > ... "there are two feasible directions" ... > > So what exactly are you suggesting? > > > > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >> Like I said, either the scanner methods or the console methods are fine. >> >> I am of course aware of the utility/complexity of Scanner, and can understand the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in Console. >> >> You don't have to "get a console". A SimpleIO.readLine method can just invoke readLine on the system console. >> >> My objection is to add yet another "input" method into the mix. "input" is weak. Does it read a token or the entire line? Does it consume the newline? And if it does just what readLine does, why another method name? Because "input" is three characters fewer? Let's not count characters. >> >> On 18/02/2024 22.43, Brian Goetz wrote: >>> I think you are counting characters and not counting concepts. >>> >>> Scanner has a ton of complexity in it that can easily trip up beginners.? The main sin (though there are others) is that input and parsing are complected (e.g., nextInt), which only causes more problems (e.g., end of line issues.)?? Reading from the console is clearly a () -> String operation.? The input() method does one thing, which is get a line of text.? That's simple. >>> >>> Integer.parseInt (or, soon, patterns that match against string and bind an int) also does one thing: convert a string from int.? It may seem verbose to have to do both explicitly, but it allows each of these operations to be simple, and it is perfectly obvious what is going on. On the other hand, Scanner is a world of complexity on its own. >>> >>> Console::readLine is nice, but first you have to get a Console. ("Why can I print something without having to get some magic helper object, but I can't do the same for reading?")? What we're optimizing for here is conceptual simplicity; the simplest possible input method is the inverse of println.? The fact that input has to be validated is a fact of life; we can treat validation separately from IO (and we should), and it gets simpler when you do. >>> >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>>> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 for beginning students. >>>> >>>> I am the author of college texts for introductory programming. Like other authors, I introduce the Scanner class (and not Console) for reading user input. Given that students already know about System.out, it is simpler to call >>>> >>>> System.out.print("How old are you? "); >>>> int x = in.nextInt(); // in is a Scanner >>>> >>>> than >>>> >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >>>> >>>> or with the JEP draft: >>>> >>>> int x = Integer.parseInt(input("How old are you? ")); >>>> >>>> Then again, having a prompt string is nice too, so I could imagine using the Console API with Integer.parseInt and Double.parseDouble, instead of Scanner.nextInt/nextDouble. >>>> >>>> But why have a third API, i.e. "input"? >>>> >>>> I think there are two feasible directions. Either embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding "input" into the mix is just clutter, and ambiguous clutter at that. At least readLine makes it clear that the entire line is consumed. >>>> >>>> Cheers, >>>> >>>> Cay >>>> >>>> -- >>>> >>>> Cay S. Horstmann | https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ | mailto:cay at horstmann.com >>> >> > -- -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From cay at horstmann.com Mon Feb 19 08:14:31 2024 From: cay at horstmann.com (Cay Horstmann) Date: Mon, 19 Feb 2024 09:14:31 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <528334885.9633181.1708329829296.JavaMail.zimbra@univ-eiffel.fr> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <528334885.9633181.1708329829296.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <315514f8-d824-4d7c-b22e-c74a91d3c2bf@horstmann.com> On 19/02/2024 09.03, Remi Forax wrote: > In the other hand, i'm pretty sure "print" should be removed, because it's confusing to have both "print" and "println" (at least there is not "printf") and the semantics of "print" is not obvious for beginners ("println" and "readLine" are line oriented, but "print" is not). The absence of print without a newline is a sharp edge for beginning Python programmers, who have to learn about print(something, end='') as soon as they want to print something like * ** *** **** -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From amaembo at gmail.com Mon Feb 19 09:09:35 2024 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 19 Feb 2024 10:09:35 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> Message-ID: I agree that simple methods to get numeric input are essential for beginners. They should not be distracted with a complex ceremony. Instead, they should be able to learn control flow statements and simple algorithms as soon as possible, having a simple way to get numbers from the user. With best regards, Tagir Valeev. On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann wrote: > Yes, that's what I am saying. If scanners live in vain, stick with a > subset of the Console methods. Use its readLine. Make it so that SimpleIO > uses System.console(). And add print and println to Console. > > The JEP talks about being able to start programming without having to know > about static methods. How does a beginner read a number? With > Integer.parseInt(readLine(prompt))? > > What about locales? Is print/println localized? Console.printf is. If so, > how are beginners from around the world supposed to read localized numbers? > With NumberFormat.getInstance().parse(readLine(prompt))? > > Adding localized readInt/readDouble to SimpleIO might do the trick. Do > they consume the trailing newline? (The equivalent Scanner methods don't, > which is definitely a sharp edge for beginners.) > > On 18/02/2024 23.08, Brian Goetz wrote: > > OK, so is this really just that that you are bikeshedding the name? > Renaming `input` to `readLine`? > > > > This is a perfectly reasonable naming choice, of course, but also, not > what you suggested the first time around: > > > > > ... "a third API" ... > > > > > ... "there are two feasible directions" ... > > > > So what exactly are you suggesting? > > > > > > > > On 2/18/2024 5:03 PM, Cay Horstmann wrote: > >> Like I said, either the scanner methods or the console methods are fine. > >> > >> I am of course aware of the utility/complexity of Scanner, and can > understand the motivation to have a simpler/feebler behavior in SimpleIO. > Like the one in Console. > >> > >> You don't have to "get a console". A SimpleIO.readLine method can just > invoke readLine on the system console. > >> > >> My objection is to add yet another "input" method into the mix. "input" > is weak. Does it read a token or the entire line? Does it consume the > newline? And if it does just what readLine does, why another method name? > Because "input" is three characters fewer? Let's not count characters. > >> > >> On 18/02/2024 22.43, Brian Goetz wrote: > >>> I think you are counting characters and not counting concepts. > >>> > >>> Scanner has a ton of complexity in it that can easily trip up > beginners. The main sin (though there are others) is that input and > parsing are complected (e.g., nextInt), which only causes more problems > (e.g., end of line issues.) Reading from the console is clearly a () -> > String operation. The input() method does one thing, which is get a line > of text. That's simple. > >>> > >>> Integer.parseInt (or, soon, patterns that match against string and > bind an int) also does one thing: convert a string from int. It may seem > verbose to have to do both explicitly, but it allows each of these > operations to be simple, and it is perfectly obvious what is going on. On > the other hand, Scanner is a world of complexity on its own. > >>> > >>> Console::readLine is nice, but first you have to get a Console. ("Why > can I print something without having to get some magic helper object, but I > can't do the same for reading?") What we're optimizing for here is > conceptual simplicity; the simplest possible input method is the inverse of > println. The fact that input has to be validated is a fact of life; we can > treat validation separately from IO (and we should), and it gets simpler > when you do. > >>> > >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: > >>>> I would like to comment on the simplicity of > https://openjdk.org/jeps/8323335 for beginning students. > >>>> > >>>> I am the author of college texts for introductory programming. Like > other authors, I introduce the Scanner class (and not Console) for reading > user input. Given that students already know about System.out, it is > simpler to call > >>>> > >>>> System.out.print("How old are you? "); > >>>> int x = in.nextInt(); // in is a Scanner > >>>> > >>>> than > >>>> > >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); > >>>> > >>>> or with the JEP draft: > >>>> > >>>> int x = Integer.parseInt(input("How old are you? ")); > >>>> > >>>> Then again, having a prompt string is nice too, so I could imagine > using the Console API with Integer.parseInt and Double.parseDouble, instead > of Scanner.nextInt/nextDouble. > >>>> > >>>> But why have a third API, i.e. "input"? > >>>> > >>>> I think there are two feasible directions. Either embrace the Scanner > API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. > Adding "input" into the mix is just clutter, and ambiguous clutter at that. > At least readLine makes it clear that the entire line is consumed. > >>>> > >>>> Cheers, > >>>> > >>>> Cay > >>>> > >>>> -- > >>>> > >>>> Cay S. Horstmann | > https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ > | mailto:cay at horstmann.com > >>> > >> > > > > -- > > -- > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com > -------------- next part -------------- An HTML attachment was scrubbed... URL: From amaembo at gmail.com Mon Feb 19 09:12:03 2024 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 19 Feb 2024 10:12:03 +0100 Subject: Suggestion for JEP draft 8323335 In-Reply-To: References: Message-ID: Given that SimpleIO is targeted to beginners, I doubt that we should promote the code style that includes side-effects like printing inside complex expressions. I don't think this is a Java way. I would say that creating a variable in this sample would result in a cleaner and more readable code, which is what should be taught from the very beginning. With best regards, Tagir Valeev. On Sun, Feb 18, 2024 at 7:00?PM wrote: > Hello, > I hope this email finds you well. > I have recently reviewed the draft for the JEP "Implicitly Declared > Classes and Instance Main Methods (Third Preview)" and came up with a > suggestion for a minor enhancement to the SimpleIO class. > The JEP aims to enhance the accessibility of simple IO actions, primarily > by introducing the SimpleIO class to the java.io package with the > following signatures: > > public class SimpleIO { > public static void println(Object obj) ... > public static void print(Object obj) ... > public static String input(String prompt) throws UncheckedIOException > ... > } > > One of the proposed functionalities is to allow implicitly declared > classes to automatically import the static methods of SimpleIO, thereby > simplifying console input and output operations for beginner programmers. > I propose a small addition to the SimpleIO class that would enhance its > usability further. Specifically, I suggest modifying the println and print > methods to return the passed object, enabling the inlining of print(ln) > statements. Here's the proposed modification: > > > public static T println(T obj) { > System.out.println(obj); > return obj; > } > public static T print(T obj) { > System.out.print(obj); > return obj; > } > > This enhancement would facilitate constructs such as: > > return foo > ? println(bar()) > : baz(); > > This change would particularly benefit beginners who wish to quickly print > something without first creating a variable for it. Additionally, users > exploring the SimpleIO class would have a very basic exposure to generic > methods. > I believe this suggestion aligns with the objectives of the JEP and would > enhance the user experience for novice programmers. > Please let me know if this email is the appropriate channel for submitting > such suggestions. If not, I would appreciate guidance on the correct > procedure. > Thank you for considering my proposal. > > Best regards, > Dennis Woithe > -------------- next part -------------- An HTML attachment was scrubbed... URL: From amaembo at gmail.com Mon Feb 19 09:19:52 2024 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 19 Feb 2024 10:19:52 +0100 Subject: possible bug with instanceof pattern matching In-Reply-To: References: Message-ID: A side note: you are showing the screenshots from IntelliJ IDEA. Being one of IntelliJ IDEA developers, I appreciate it. However, please note that error messages displayed by IntelliJ IDEA in the editor are not originating from javac. It's an independent implementation of the Java compiler frontend (except code generation) based on reading the specification and examining the reference implementation behavior. While we try our best to implement it correctly, it could differ in details from how the javac behaves, as there could be bugs in IntelliJ IDEA, or bugs in javac, or unclear places in the specification. I think that for discussions in this mailing list, showing messages from javac is more appropriate. If you prefer using IntelliJ, you may find them in the Build tool window when you actually build the project. With best regards, Tagir Valeev. On Sun, Feb 18, 2024 at 4:23?PM Charles wrote: > Hi all > > > What I'm about to report below is *openjdk 17*. > > > This doesn't compile > > if (ex instanceof JedisException je > || (ex instanceof ExecutionException ee && > ee.getCause() instanceof JedisException je) > ){ > ... blah blah > } > > reason being the second je is already defined in the scope. > [image: image.png] > > if you think about it. if ex is je, then, the second part won't trigger. > And if the second part is reached, then ex is not je. Hence there is only > going to be one statement mapped to je. > no confusion here. I feel this should be allowed. > > > Let's assume the above is the way it should be. I use different names for > the second variable. > > if (ex instanceof JedisException je > || (ex instanceof ExecutionException ee && > ee.getCause() instanceof JedisException second_je) > ) { > log.error(je); > log.error(second_je); > } > > [image: image.png] > This still doesn't compile. > > I would like to bring this issue up for discussion. > > > > > and as always, have a great day > > > *Best Regards* > *Charles* > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 37408 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 33303 bytes Desc: not available URL: From forax at univ-mlv.fr Mon Feb 19 12:09:17 2024 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 19 Feb 2024 13:09:17 +0100 (CET) Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <315514f8-d824-4d7c-b22e-c74a91d3c2bf@horstmann.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <528334885.9633181.1708329829296.JavaMail.zimbra@univ-eiffel.fr> <315514f8-d824-4d7c-b22e-c74a91d3c2bf@horstmann.com> Message-ID: <1640042679.9999230.1708344557568.JavaMail.zimbra@univ-eiffel.fr> ----- Original Message ----- > From: "Cay Horstmann" > To: "Remi Forax" , "Brian Goetz" > Cc: "amber-dev" > Sent: Monday, February 19, 2024 9:14:31 AM > Subject: Re: SimpleIO in JEP draft 8323335 > On 19/02/2024 09.03, Remi Forax wrote: > >> In the other hand, i'm pretty sure "print" should be removed, because it's >> confusing to have both "print" and "println" (at least there is not "printf") >> and the semantics of "print" is not obvious for beginners ("println" and >> "readLine" are line oriented, but "print" is not). > > The absence of print without a newline is a sharp edge for beginning Python > programmers, who have to learn about print(something, end='') as soon as they > want to print something like > > * > ** > *** > **** for (int i = 1; i <= 4; i++) { println("*".repeat(i)); } Both print() and Scanner are using an implicit IO state which is "where you are ?". They are both not simple. > > -- > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com R?mi From forax at univ-mlv.fr Mon Feb 19 12:25:50 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Mon, 19 Feb 2024 13:25:50 +0100 (CET) Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> Message-ID: <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> I agree with Brian here, as a teacher, you have to talk about parsing and formatting, those should not be hidden. The classical program is: input -> strings -> objects -> strings -> output R?mi > From: "Tagir Valeev" > To: "Cay Horstmann" > Cc: "Brian Goetz" , "amber-dev" > Sent: Monday, February 19, 2024 10:09:35 AM > Subject: Re: SimpleIO in JEP draft 8323335 > I agree that simple methods to get numeric input are essential for beginners. > They should not be distracted with a complex ceremony. Instead, they should be > able to learn control flow statements and simple algorithms as soon as > possible, having a simple way to get numbers from the user. > With best regards, > Tagir Valeev. > On Mon, Feb 19, 2024 at 9:10 AM Cay Horstmann < [ mailto:cay at horstmann.com | > cay at horstmann.com ] > wrote: >> Yes, that's what I am saying. If scanners live in vain, stick with a subset of >> the Console methods. Use its readLine. Make it so that SimpleIO uses >> System.console(). And add print and println to Console. >> The JEP talks about being able to start programming without having to know about >> static methods. How does a beginner read a number? With >> Integer.parseInt(readLine(prompt))? >> What about locales? Is print/println localized? Console.printf is. If so, how >> are beginners from around the world supposed to read localized numbers? With >> NumberFormat.getInstance().parse(readLine(prompt))? >> Adding localized readInt/readDouble to SimpleIO might do the trick. Do they >> consume the trailing newline? (The equivalent Scanner methods don't, which is >> definitely a sharp edge for beginners.) >> On 18/02/2024 23.08, Brian Goetz wrote: >>> OK, so is this really just that that you are bikeshedding the name? Renaming >> > `input` to `readLine`? >>> This is a perfectly reasonable naming choice, of course, but also, not what you >> > suggested the first time around: >> > > ... "a third API" ... >> > > ... "there are two feasible directions" ... >> > So what exactly are you suggesting? >> > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >> >> Like I said, either the scanner methods or the console methods are fine. >>>> I am of course aware of the utility/complexity of Scanner, and can understand >>>> the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in >> >> Console. >>>> You don't have to "get a console". A SimpleIO.readLine method can just invoke >> >> readLine on the system console. >>>> My objection is to add yet another "input" method into the mix. "input" is weak. >>>> Does it read a token or the entire line? Does it consume the newline? And if it >>>> does just what readLine does, why another method name? Because "input" is three >> >> characters fewer? Let's not count characters. >> >> On 18/02/2024 22.43, Brian Goetz wrote: >> >>> I think you are counting characters and not counting concepts. >>>>> Scanner has a ton of complexity in it that can easily trip up beginners. The >>>>> main sin (though there are others) is that input and parsing are complected >>>>> (e.g., nextInt), which only causes more problems (e.g., end of line issues.) >>>>> Reading from the console is clearly a () -> String operation. The input() >> >>> method does one thing, which is get a line of text. That's simple. >>>>> Integer.parseInt (or, soon, patterns that match against string and bind an int) >>>>> also does one thing: convert a string from int. It may seem verbose to have to >>>>> do both explicitly, but it allows each of these operations to be simple, and it >>>>> is perfectly obvious what is going on. On the other hand, Scanner is a world of >> >>> complexity on its own. >>>>> Console::readLine is nice, but first you have to get a Console. ("Why can I >>>>> print something without having to get some magic helper object, but I can't do >>>>> the same for reading?") What we're optimizing for here is conceptual >>>>> simplicity; the simplest possible input method is the inverse of println. The >>>>> fact that input has to be validated is a fact of life; we can treat validation >> >>> separately from IO (and we should), and it gets simpler when you do. >> >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>>>>> I would like to comment on the simplicity of [ https://openjdk.org/jeps/8323335 >> >>>> | https://openjdk.org/jeps/8323335 ] for beginning students. >>>>>> I am the author of college texts for introductory programming. Like other >>>>>> authors, I introduce the Scanner class (and not Console) for reading user >> >>>> input. Given that students already know about System.out, it is simpler to call >> >>>> System.out.print("How old are you? "); >> >>>> int x = in.nextInt(); // in is a Scanner >> >>>> than >> >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >> >>>> or with the JEP draft: >> >>>> int x = Integer.parseInt(input("How old are you? ")); >>>>>> Then again, having a prompt string is nice too, so I could imagine using the >>>>>> Console API with Integer.parseInt and Double.parseDouble, instead of >> >>>> Scanner.nextInt/nextDouble. >> >>>> But why have a third API, i.e. "input"? >>>>>> I think there are two feasible directions. Either embrace the Scanner API and >>>>>> next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding >>>>>> "input" into the mix is just clutter, and ambiguous clutter at that. At least >> >>>> readLine makes it clear that the entire line is consumed. >> >>>> Cheers, >> >>>> Cay >> >>>> -- >>>>>> Cay S. Horstmann | [ >>>>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>>>>> | >>>>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >> >>>> ] | mailto: [ mailto:cay at horstmann.com | cay at horstmann.com ] >> -- >> -- >> Cay S. Horstmann | [ http://horstmann.com/ | http://horstmann.com ] | mailto: [ >> mailto:cay at horstmann.com | cay at horstmann.com ] -------------- next part -------------- An HTML attachment was scrubbed... URL: From eirbjo at gmail.com Mon Feb 19 12:44:00 2024 From: eirbjo at gmail.com (=?UTF-8?B?RWlyaWsgQmrDuHJzbsO4cw==?=) Date: Mon, 19 Feb 2024 13:44:00 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> Message-ID: On Sun, Feb 18, 2024 at 11:08?PM Brian Goetz wrote: > OK, so is this really just that that you are bikeshedding the name? > Renaming `input` to `readLine`? > Just a thought: Perhaps there is more to this than just bikeshedding.. At least, there is an asymmetry here which could affect learners: "print (line)" is something the *program* does, affecting its environment (the user) "read (line)" is something the *program* does, affecting the user, but ultimately the program state "input": is something the *user* does (or provides if a noun), having an effect on the program state As a learner of programming, I remember trying to "think like the program" when reasoning about code. Maybe this switch of perspective/subject between print and input isn't particularly helpful in that regard? Cheers, Eirik. -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.r.doyle at gmail.com Mon Feb 19 14:18:20 2024 From: p.r.doyle at gmail.com (Patrick Doyle) Date: Mon, 19 Feb 2024 09:18:20 -0500 Subject: "case catch" instead of "case throws"? Message-ID: In Brian's "Uniform handling of failure in switch", he proposes the syntax "case throws". I see the motivation (it certainly reads nicely) but since such clauses are catching exceptions, wouldn't it be more in line with the rest of the language to use "case catch"? This would also serve to preserve the word "throws" for its usual purpose if ever "switch ... throws" becomes a thing. -- Patrick Doyle p.r.doyle at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From holo3146 at gmail.com Mon Feb 19 14:43:01 2024 From: holo3146 at gmail.com (Holo The Sage Wolf) Date: Mon, 19 Feb 2024 16:43:01 +0200 Subject: "case catch" instead of "case throws"? In-Reply-To: References: Message-ID: The branch catches a case of throws On Mon, 19 Feb 2024, 16:18 Patrick Doyle, wrote: > In Brian's "Uniform handling of failure in switch", he proposes the syntax > "case throws". I see the motivation (it certainly reads nicely) but since > such clauses are catching exceptions, wouldn't it be more in line with the > rest of the language to use "case catch"? > > This would also serve to preserve the word "throws" for its usual purpose > if ever "switch ... throws" becomes a thing. > > -- > Patrick Doyle > p.r.doyle at gmail.com > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cay at horstmann.com Mon Feb 19 14:58:34 2024 From: cay at horstmann.com (Cay Horstmann) Date: Mon, 19 Feb 2024 15:58:34 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <13d1104b-3c9c-4000-96d9-8029bd300614@horstmann.com> To make parsing beginner-friendly, Integer.parseInt and Double.parseDouble need to be statically imported: int n = parseInt(input("How old are you? ")); Obviously we can't do int(input(prompt)) like in Python. PS. I previously asked about locales. I presume that print and println are not intended to be localized for numbers, just like the PrintStream methods. For consistency, inputs should then also use the Java number literal syntax. I believe that is acceptable for Java learners, even if their locale uses a different number format. PPS. What happened to my beloved readLine, you may ask. Sadly, simply adopting Console.readLine does not work. It uses a format string for the prompt. We do not want beginners to ponder why double percentage = parseDouble(readLine("Enter %age")) throws a MissingFormatArgumentException (which, btw, hangs JShell). PPPS. Is it intended that print, println, input use System.getConsole() under the hood? I am asking because the console potentially uses a different character encoding than PrintStream and Scanner. On 19/02/2024 13.25, Remi Forax wrote: > I agree with Brian here, > as a teacher, you have to talk about parsing and formatting, those should not be hidden. > > The classical program is: > ?? input -> strings -> objects -> strings -> output > > R?mi > > ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ > > *From: *"Tagir Valeev" > *To: *"Cay Horstmann" > *Cc: *"Brian Goetz" , "amber-dev" > *Sent: *Monday, February 19, 2024 10:09:35 AM > *Subject: *Re: SimpleIO in JEP draft 8323335 > > I agree that simple methods to get numeric input are essential for beginners. They should not be distracted with a complex ceremony. Instead, they should be able to learn control flow statements and simple algorithms as soon as possible, having a simple way to get numbers from the user. > With best?regards, > Tagir Valeev. > > On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann > wrote: > > Yes, that's what I am saying. If scanners live in vain, stick with a subset of the Console methods. Use its readLine. Make it so that SimpleIO uses System.console(). And add print and println to Console. > > The JEP talks about being able to start programming without having to know about static methods. How does a beginner read a number? With Integer.parseInt(readLine(prompt))? > > What about locales? Is print/println localized? Console.printf is. If so, how are beginners from around the world supposed to read localized numbers? With NumberFormat.getInstance().parse(readLine(prompt))? > > Adding localized readInt/readDouble to SimpleIO might do the trick. Do they consume the trailing newline? (The equivalent Scanner methods don't, which is definitely a sharp edge for beginners.) > > On 18/02/2024 23.08, Brian Goetz wrote: > > OK, so is this really just that that you are bikeshedding the name?? Renaming `input` to `readLine`? > > > > This is a perfectly reasonable naming choice, of course, but also, not what you suggested the first time around: > > > >? > ... "a third API" ... > > > >? > ... "there are two feasible directions" ... > > > > So what exactly are you suggesting? > > > > > > > > On 2/18/2024 5:03 PM, Cay Horstmann wrote: > >> Like I said, either the scanner methods or the console methods are fine. > >> > >> I am of course aware of the utility/complexity of Scanner, and can understand the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in Console. > >> > >> You don't have to "get a console". A SimpleIO.readLine method can just invoke readLine on the system console. > >> > >> My objection is to add yet another "input" method into the mix. "input" is weak. Does it read a token or the entire line? Does it consume the newline? And if it does just what readLine does, why another method name? Because "input" is three characters fewer? Let's not count characters. > >> > >> On 18/02/2024 22.43, Brian Goetz wrote: > >>> I think you are counting characters and not counting concepts. > >>> > >>> Scanner has a ton of complexity in it that can easily trip up beginners.? The main sin (though there are others) is that input and parsing are complected (e.g., nextInt), which only causes more problems (e.g., end of line issues.)?? Reading from the console is clearly a () -> String operation.? The input() method does one thing, which is get a line of text.? That's simple. > >>> > >>> Integer.parseInt (or, soon, patterns that match against string and bind an int) also does one thing: convert a string from int.? It may seem verbose to have to do both explicitly, but it allows each of these operations to be simple, and it is perfectly obvious what is going on. On the other hand, Scanner is a world of complexity on its own. > >>> > >>> Console::readLine is nice, but first you have to get a Console. ("Why can I print something without having to get some magic helper object, but I can't do the same for reading?")? What we're optimizing for here is conceptual simplicity; the simplest possible input method is the inverse of println.? The fact that input has to be validated is a fact of life; we can treat validation separately from IO (and we should), and it gets simpler when you do. > >>> > >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: > >>>> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 for beginning students. > >>>> > >>>> I am the author of college texts for introductory programming. Like other authors, I introduce the Scanner class (and not Console) for reading user input. Given that students already know about System.out, it is simpler to call > >>>> > >>>> System.out.print("How old are you? "); > >>>> int x = in.nextInt(); // in is a Scanner > >>>> > >>>> than > >>>> > >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); > >>>> > >>>> or with the JEP draft: > >>>> > >>>> int x = Integer.parseInt(input("How old are you? ")); > >>>> > >>>> Then again, having a prompt string is nice too, so I could imagine using the Console API with Integer.parseInt and Double.parseDouble, instead of Scanner.nextInt/nextDouble. > >>>> > >>>> But why have a third API, i.e. "input"? > >>>> > >>>> I think there are two feasible directions. Either embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding "input" into the mix is just clutter, and ambiguous clutter at that. At least readLine makes it clear that the entire line is consumed. > >>>> > >>>> Cheers, > >>>> > >>>> Cay > >>>> > >>>> -- > >>>> > >>>> Cay S. Horstmann | https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ | mailto:cay at horstmann.com > >>> > >> > > > > -- > > -- > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com > > -- -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From pedro.lamarao at prodist.com.br Mon Feb 19 15:00:52 2024 From: pedro.lamarao at prodist.com.br (=?UTF-8?Q?Pedro_Lamar=C3=A3o?=) Date: Mon, 19 Feb 2024 12:00:52 -0300 Subject: "case catch" instead of "case throws"? In-Reply-To: References: Message-ID: I also read it as "(in) case (it) throws". Em seg., 19 de fev. de 2024 ?s 11:44, Holo The Sage Wolf escreveu: > The branch catches a case of throws > > On Mon, 19 Feb 2024, 16:18 Patrick Doyle, wrote: > >> In Brian's "Uniform handling of failure in switch", he proposes the >> syntax "case throws". I see the motivation (it certainly reads nicely) but >> since such clauses are catching exceptions, wouldn't it be more in line >> with the rest of the language to use "case catch"? >> >> This would also serve to preserve the word "throws" for its usual purpose >> if ever "switch ... throws" becomes a thing. >> >> -- >> Patrick Doyle >> p.r.doyle at gmail.com >> > -- Pedro Lamar?o -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Feb 19 16:27:26 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 19 Feb 2024 11:27:26 -0500 Subject: possible bug with instanceof pattern matching In-Reply-To: References: <40b4d583-971d-4079-b5ab-f4e34a0ff32a@oracle.com> Message-ID: <34b8fc23-b303-4852-9500-1df870840332@oracle.com> Correct.? In your second example, neither JE is in scope.? The simple rule about pattern scoping is that a pattern variable is in scope where it would be definitely assigned.? (The definite assignment rules look complicated in the spec, but they are the obvious rules of "I couldn't get here without having been through here first" that we all run when we simulate Java code in our heads.)? So in ??? if (x instanceof Foo f || x instanceof Bar b) { ... } neither f nor b are in scope inside the block, because neither is definitely assigned when we get to the block.? (We may know that one of the two patterns matched if we get into the block (in fact, exactly one), but because we have no idea which one, we cannot conclude that either pattern variable is definitely assigned.) On 2/19/2024 1:19 AM, Charles wrote: > Hi Brian > > Thanks for clarifying. I suppose the second case, which uses two > separate variables, is also explained by that. > > Since pattern matching doesn't differentiate which "je" got created, > it can't tell which variable will eventually be visible in the scope. > Hence it is saying both variables are not visible in the scope. > > > > > and as always, have a great day > * > * > *Best Regards > * > *Charles* > * > * > > > > > On Sun, Feb 18, 2024 at 11:33?PM Brian Goetz > wrote: > > This is not a bug; this potential feature was discussed at some > length during the design process.? Another way this > potential-feature could show up is: > > ??? switch (container) { > ??????? case Box(String s), Bag(String s): ... use s ... > ??? } > > The reason that we chose not to proceed with such "binding > merging" is that when you get inside the block, `je` is one > variable with two declarations; you don't really know where the > declaration is.? (So IDE navigations like "go to declaration" > would have to learn to highlight TWO (or more) declarations, for > example.) > > This feature isn't fundamentally impossible, and we could consider > it again in the future, but it was a deliberate decision to not go > this far at this time. > > > On 2/18/2024 6:53 AM, Charles wrote: >> Hi all >> >> >> What I'm about to report below is *openjdk 17*. >> >> >> This doesn't compile >> >> if (ex instanceof JedisException je >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? || (ex instanceof ExecutionException >> ee && ee.getCause() instanceof JedisException je) >> ? ? ? ? ? ? ){ >> ? ?... blah blah >> } >> >> reason being the second je is already defined in the scope. >> image.png >> >> if you think about it. if ex is je, then, the second part won't >> trigger. And if the second part is reached, then ex is not je. >> Hence there is only going to be one statement mapped to je. >> no confusion here. I feel this should be allowed. >> >> >> Let's assume the above is the way it should be. I use?different >> names for the second variable. >> >> ?if (ex instanceof JedisException je >> ? ? ? || (ex instanceof ExecutionException ee && ee.getCause() >> instanceof JedisException second_je) >> ? ? ? ? ? ? ) { >> log.error(je); >> log.error(second_je); >> ? ? ? ? ? ? } >> >> image.png >> This still doesn't compile. >> >> I would like to bring this issue up for discussion. >> >> >> >> >> and as always, have a great day >> * >> * >> *Best Regards >> * >> *Charles* >> * >> * >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 37408 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 33303 bytes Desc: not available URL: From brian.goetz at oracle.com Mon Feb 19 16:45:31 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 19 Feb 2024 11:45:31 -0500 Subject: "case catch" instead of "case throws"? In-Reply-To: References: Message-ID: No :) It was discussed why not to use bare "catch" on the EG list. "Case catch" is slightly different, but I'd like to explain why this is not in the spirit of the feature. To recap one of the reasons we rejected bare `catch`: because it is asking a question _about the selector_ (did evaluating the selector throw), not about the _block_ (did something in this switch block throw.)? If we called it catch, this would surely be confusing. The essence of switch is "evaluate a thing, then do one of the following things as a result."? With an exhaustive switch with no fall through, its "exactly one thing"; let's go with that as our model: evaluate a thing, then do exactly one of the following things. We pick which thing to do based on case selectors.? Currently we have case selectors for constants, patterns, and catch-all (default).? Each of these selectors should refer back _to the computation_ that is the switch selector.? A `case ` says "did it evaluate to this constant."? A `case ` says "did it evaluate to something that matches this pattern."? A `case throws ` says "did it throw something that matches this pattern."? But "case catch" would be asking "did it evaluate to something that catches this exception", which doesn't really even make sense. Further, I know we are all used to the word "catch" from try-catch, but "catch" is a very imperative framing, which comes from a day where language control constructs were all statements (while, for, if, try, etc), not expressions.? Over the last 30 years we've learned that statements suck.? (Because, expressions compose, and statements don't, and composition is the best tool we have.) So I think the desire to hold onto "catch" here (in addition to the problems discussed on the EG list) is mostly skating to where the puck *was*, rather than where it is *going*. On 2/19/2024 9:18 AM, Patrick Doyle wrote: > In Brian's "Uniform handling of failure in switch", he proposes the > syntax "case throws". I see the motivation (it certainly reads nicely) > but since such clauses are catching exceptions, wouldn't it be more in > line with the rest of the language to use "case catch"? > > This would also serve to preserve the word "throws" for its usual > purpose if ever "switch ... throws" becomes a thing. > > -- > Patrick Doyle > p.r.doyle at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Feb 19 17:06:51 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 19 Feb 2024 12:06:51 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> There's a reason there are so many opinions here: because the goals are in conflict.? Everyone wants simplicity, but people don't agree on what "simple" means.? (Cue the jokes about "I would simply not write programs with bugs.") Yes, getting numbers from the user is a basic task.? But it is not, in any way, simple!? Because reading numbers from the input is invariably complected with discarding things that are "acceptably non-numbery" (e.g., whitespace), which is neither simple nor usually terribly well documented.? We've all encountered the problem in many language runtimes where reading a number using the "friendly way" leaves the input in a state that requires fixing or yields surprises for the next operation. This is because reading a number from an input stream is not any sort of primitive; it is the composite of reading from the input, deciding what to skip, deciding when to stop reading, converting to another type, deciding what state to leave the input stream in, and deciding what to do if no number could be found (or if the number was too big to fit into an int, etc.)? This is not^3 simple! C starts with a simple and principled answer, which is that the IO primitive is getchar() and putchar().? Reading or writing one character is unquestionably a primitive.? (But also, unless you are writing `cat`, no one wants to program with getchar and putchar, because it's too primitive.) One can make a reasonable case for "write a line / read a line" being sensible primitives.? They are simple enough: no parsing, no deciding what to throw away, no possible errors other than EOF, it is clear what state you leave the stream in.? These may not be what the student wants, but they are primitives a student can deal with without having to understand parsing and error handling and statefulness yet. ??? String s = getALine(); ??? printALine(s); is a program every student can reason about. But, it is true that dealing in strings, while honest and simple, is not always what the student wants.? But herein lies the strongest argument for not trying to reinvent Scanner here: the ability to read numbers makes the complexity of the problem, and hence of the API, much much bigger.? (Scanner was very well intentioned, and was not written by children, and yet none of us want to use it.? That's a sign that a one-size-fits-all magic input processing system is harder than it looks, and for something that is explicitly aimed at beginners, is a double warning sign.) I could imagine someone suggesting "why don't you just add `readLineAsInt`".? But what would happen next?? Well, there would be a million requests (including from folks like Cay) of "you should add X", and then the result is a mishmash jumble of an API (that's already terrible), but worse, it's an onramp that leads to nowhere.? Once the user's needs are slightly more complicated, they are nowhere. Remi has it absolutely right (yes, I really said that) with > The classical program is: > ?? input -> strings -> objects -> strings -> output We do not do users a favor by blurring the distinction between "input -> string" and "string -> object", and because the latter is so much more open-ended than the former, the latter infects the former with its complexity if we try. Is this simple API the most wonderful, be-all of APIs?? Of course not.? But it is a sensible set of primitives that users can understand and *build on* in a transparent way. Some teachers may immediately reach for teaching Integer::parseInt; that's a reasonable strategy, it exposes students to the questions of "what happens when preconditions fail", and the two compose just fine.? But maybe you don't like Integer::parseInt for some reason.? Another way to teach this is to have them write it themselves.? This will expose them to all sorts of interesting questions (what about whitespace? what about double negatives?), but of course is also throwing in the deep end of the pool.? But SimpleIO::readMeALinePlease is agnostic; it works with both approaches. Could the JDK use some better tools for parsing?? Sure; pattern matching has a role to play here, a `String::unformat` would be really cool, and I love parser combinators.? All of this can happen in the future, and none have the effect of making this API look like yet another white elephant like Scanner.? Because it focused purely on the basics. On 2/19/2024 7:25 AM, Remi Forax wrote: > I agree with Brian here, > as a teacher, you have to talk about parsing and formatting, those > should not be hidden. > > The classical program is: > ?? input -> strings -> objects -> strings -> output > > R?mi > > ------------------------------------------------------------------------ > > *From: *"Tagir Valeev" > *To: *"Cay Horstmann" > *Cc: *"Brian Goetz" , "amber-dev" > > *Sent: *Monday, February 19, 2024 10:09:35 AM > *Subject: *Re: SimpleIO in JEP draft 8323335 > > I agree that simple methods to get numeric input are essential for > beginners. They should not be distracted with a complex ceremony. > Instead, they should be able to learn control flow statements and > simple algorithms as soon as possible, having a simple way to get > numbers from the user. > With best?regards, > Tagir Valeev. > > On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann > wrote: > > Yes, that's what I am saying. If scanners live in vain, stick > with a subset of the Console methods. Use its readLine. Make > it so that SimpleIO uses System.console(). And add print and > println to Console. > > The JEP talks about being able to start programming without > having to know about static methods. How does a beginner read > a number? With Integer.parseInt(readLine(prompt))? > > What about locales? Is print/println localized? Console.printf > is. If so, how are beginners from around the world supposed to > read localized numbers? With > NumberFormat.getInstance().parse(readLine(prompt))? > > Adding localized readInt/readDouble to SimpleIO might do the > trick. Do they consume the trailing newline? (The equivalent > Scanner methods don't, which is definitely a sharp edge for > beginners.) > > On 18/02/2024 23.08, Brian Goetz wrote: > > OK, so is this really just that that you are bikeshedding > the name?? Renaming `input` to `readLine`? > > > > This is a perfectly reasonable naming choice, of course, but > also, not what you suggested the first time around: > > > >? > ... "a third API" ... > > > >? > ... "there are two feasible directions" ... > > > > So what exactly are you suggesting? > > > > > > > > On 2/18/2024 5:03 PM, Cay Horstmann wrote: > >> Like I said, either the scanner methods or the console > methods are fine. > >> > >> I am of course aware of the utility/complexity of Scanner, > and can understand the motivation to have a simpler/feebler > behavior in SimpleIO. Like the one in Console. > >> > >> You don't have to "get a console". A SimpleIO.readLine > method can just invoke readLine on the system console. > >> > >> My objection is to add yet another "input" method into the > mix. "input" is weak. Does it read a token or the entire line? > Does it consume the newline? And if it does just what readLine > does, why another method name? Because "input" is three > characters fewer? Let's not count characters. > >> > >> On 18/02/2024 22.43, Brian Goetz wrote: > >>> I think you are counting characters and not counting concepts. > >>> > >>> Scanner has a ton of complexity in it that can easily trip > up beginners.? The main sin (though there are others) is that > input and parsing are complected (e.g., nextInt), which only > causes more problems (e.g., end of line issues.)?? Reading > from the console is clearly a () -> String operation.? The > input() method does one thing, which is get a line of text.? > That's simple. > >>> > >>> Integer.parseInt (or, soon, patterns that match against > string and bind an int) also does one thing: convert a string > from int.? It may seem verbose to have to do both explicitly, > but it allows each of these operations to be simple, and it is > perfectly obvious what is going on. On the other hand, Scanner > is a world of complexity on its own. > >>> > >>> Console::readLine is nice, but first you have to get a > Console. ("Why can I print something without having to get > some magic helper object, but I can't do the same for > reading?")? What we're optimizing for here is conceptual > simplicity; the simplest possible input method is the inverse > of println.? The fact that input has to be validated is a fact > of life; we can treat validation separately from IO (and we > should), and it gets simpler when you do. > >>> > >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: > >>>> I would like to comment on the simplicity of > https://openjdk.org/jeps/8323335 for beginning students. > >>>> > >>>> I am the author of college texts for introductory > programming. Like other authors, I introduce the Scanner class > (and not Console) for reading user input. Given that students > already know about System.out, it is simpler to call > >>>> > >>>> System.out.print("How old are you? "); > >>>> int x = in.nextInt(); // in is a Scanner > >>>> > >>>> than > >>>> > >>>> int x = Integer.parseInt(console.readLine("How old are > you? ")); > >>>> > >>>> or with the JEP draft: > >>>> > >>>> int x = Integer.parseInt(input("How old are you? ")); > >>>> > >>>> Then again, having a prompt string is nice too, so I > could imagine using the Console API with Integer.parseInt and > Double.parseDouble, instead of Scanner.nextInt/nextDouble. > >>>> > >>>> But why have a third API, i.e. "input"? > >>>> > >>>> I think there are two feasible directions. Either embrace > the Scanner API and next/nextInt/nextDouble/nextLine, or the > Console API and readLine. Adding "input" into the mix is just > clutter, and ambiguous clutter at that. At least readLine > makes it clear that the entire line is consumed. > >>>> > >>>> Cheers, > >>>> > >>>> Cay > >>>> > >>>> -- > >>>> > >>>> Cay S. Horstmann | > https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ > | mailto:cay at horstmann.com > >>> > >> > > > > -- > > -- > > Cay S. Horstmann | http://horstmann.com > > | mailto:cay at horstmann.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pedro.lamarao at prodist.com.br Mon Feb 19 18:00:45 2024 From: pedro.lamarao at prodist.com.br (=?UTF-8?Q?Pedro_Lamar=C3=A3o?=) Date: Mon, 19 Feb 2024 15:00:45 -0300 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> Message-ID: Em seg., 19 de fev. de 2024 ?s 14:08, Brian Goetz escreveu: > One can make a reasonable case for "write a line / read a line" being > sensible primitives. They are simple enough: no parsing, no deciding what > to throw away, no possible errors other than EOF, it is clear what state > you leave the stream in. These may not be what the student wants, but they > are primitives a student can deal with without having to understand parsing > and error handling and statefulness yet. > I feel that, though in appearance the discussion is about words like "read" or "print" or "input", which convey actions, the core of the issue is what primitive data format is going to have ready-made composable parsers/assemblers. To me, as you seem to suggest, "read line" is not about the read, it is about the line, a concept incredibly simple which hides enough complexity to turn a line parser into a trap for the unwary. For similar reasons, I appreciate class Properties' method load, which provides an extremely quick way to do "property maps" when needed. For these reasons, I think that the way for beginners is not actually about reads or writes, but about line streamers. -- Pedro Lamar?o -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.r.doyle at gmail.com Mon Feb 19 18:09:45 2024 From: p.r.doyle at gmail.com (Patrick Doyle) Date: Mon, 19 Feb 2024 13:09:45 -0500 Subject: "case catch" instead of "case throws"? In-Reply-To: References: Message-ID: Fair enough. I do see the grammatical appeal of "case throws" and agree that it reads better. I might characterize your answer more as "yes, this syntax is not in line with the rest of the language, and that's how we want it". :-) In the rest of Java, "throw" and "throws" indicate where exceptions are emitted, and "catch" indicates where they are handled (as regrettable as the imperative nature of the word "catch" might be). This would be the first time where "throws" introduces a syntax construct that does not throw the exception in question. -- Patrick Doyle p.r.doyle at gmail.com On Mon, Feb 19, 2024 at 11:45?AM Brian Goetz wrote: > No :) > > It was discussed why not to use bare "catch" on the EG list. "Case catch" > is slightly different, but I'd like to explain why this is not in the > spirit of the feature. > > To recap one of the reasons we rejected bare `catch`: because it is asking > a question _about the selector_ (did evaluating the selector throw), not > about the _block_ (did something in this switch block throw.) If we called > it catch, this would surely be confusing. > > The essence of switch is "evaluate a thing, then do one of the following > things as a result." With an exhaustive switch with no fall through, its > "exactly one thing"; let's go with that as our model: evaluate a thing, > then do exactly one of the following things. > > We pick which thing to do based on case selectors. Currently we have case > selectors for constants, patterns, and catch-all (default). Each of these > selectors should refer back _to the computation_ that is the switch > selector. A `case ` says "did it evaluate to this constant." A > `case ` says "did it evaluate to something that matches this > pattern." A `case throws ` says "did it throw something that > matches this pattern." But "case catch" would be asking "did it evaluate > to something that catches this exception", which doesn't really even make > sense. > > Further, I know we are all used to the word "catch" from try-catch, but > "catch" is a very imperative framing, which comes from a day where language > control constructs were all statements (while, for, if, try, etc), not > expressions. Over the last 30 years we've learned that statements suck. > (Because, expressions compose, and statements don't, and composition is the > best tool we have.) > > So I think the desire to hold onto "catch" here (in addition to the > problems discussed on the EG list) is mostly skating to where the puck > *was*, rather than where it is *going*. > > > > On 2/19/2024 9:18 AM, Patrick Doyle wrote: > > In Brian's "Uniform handling of failure in switch", he proposes the syntax > "case throws". I see the motivation (it certainly reads nicely) but since > such clauses are catching exceptions, wouldn't it be more in line with the > rest of the language to use "case catch"? > > This would also serve to preserve the word "throws" for its usual purpose > if ever "switch ... throws" becomes a thing. > > -- > Patrick Doyle > p.r.doyle at gmail.com > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pedro.lamarao at prodist.com.br Mon Feb 19 18:20:51 2024 From: pedro.lamarao at prodist.com.br (=?UTF-8?Q?Pedro_Lamar=C3=A3o?=) Date: Mon, 19 Feb 2024 15:20:51 -0300 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> Message-ID: Complementing, this would be the expected student constructs based on a "stream oriented" simple I/O. The point is that "input lines" is some kind of magic data structure, and the concept of I/O and its implications is left out of the picture. Naming is of course merely to support exposition. for (int i = 0, j = inputLineSequence.size(); i != j; ++i) { var line = inputLineSequence.get(i); // ... } for (var line : inputLineSequence) { // ... } inputLineSequence.stream().forEach(line -> { // ... }); Em seg., 19 de fev. de 2024 ?s 15:00, Pedro Lamar?o < pedro.lamarao at prodist.com.br> escreveu: > Em seg., 19 de fev. de 2024 ?s 14:08, Brian Goetz > escreveu: > > >> One can make a reasonable case for "write a line / read a line" being >> sensible primitives. They are simple enough: no parsing, no deciding what >> to throw away, no possible errors other than EOF, it is clear what state >> you leave the stream in. These may not be what the student wants, but they >> are primitives a student can deal with without having to understand parsing >> and error handling and statefulness yet. >> > > I feel that, though in appearance the discussion is about words like > "read" or "print" or "input", which convey actions, the core of the issue > is what primitive data format is going to have ready-made composable > parsers/assemblers. To me, as you seem to suggest, "read line" is not about > the read, it is about the line, a concept incredibly simple which hides > enough complexity to turn a line parser into a trap for the unwary. For > similar reasons, I appreciate class Properties' method load, which provides > an extremely quick way to do "property maps" when needed. For these > reasons, I think that the way for beginners is not actually about reads or > writes, but about line streamers. > > -- > Pedro Lamar?o > -- Pedro Lamar?o -------------- next part -------------- An HTML attachment was scrubbed... URL: From johannes.spangenberg at hotmail.de Mon Feb 19 22:25:21 2024 From: johannes.spangenberg at hotmail.de (Johannes Spangenberg) Date: Mon, 19 Feb 2024 23:25:21 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <13d1104b-3c9c-4000-96d9-8029bd300614@horstmann.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <13d1104b-3c9c-4000-96d9-8029bd300614@horstmann.com> Message-ID: Hello, I just wanted to share some information someone might find interesting. > PPPS. Is it intended that print, println, input use > System.getConsole() under the hood? I am asking because the console > potentially uses a different character encoding than PrintStream and > Scanner. I am not sure about the encoding, but System.console() may return null if the input or output are redirected. java Main > output.txt If I use this command, System.console() would return null, and the following application would run into a NullPointerException. public final class Main { public static void main(String[] args) { System.console().readLine("Input: "); } } If you consider this issue, you may always want to use System.in instead of System.console(). However, if you look at other (non-Java) applications, there is also another approach. Let's consider the following command: cat files.txt | sudo xargs -i cat {} > out 2> err With this command, sudo will prompt for your password on the Terminal, although neither STDIN, STDOUT, nor STDERR is connected to the terminal. You can observe a similar behavior with ssh. I am not aware of this being properly supported by Java. In Python, this is implemented by the getpass module for Linux and Windows. Note: Python has the unfortunate limitation that it does not have a similar method for non-password-inputs. This causes users to mix getpass(...) and input(...), causing inconsistent behavior. Here is a question on StackOverflow about the topic. PS: I personally feel like Java could potentially benefit from better utilities for interactive command line interfaces. However, if this is something we want to implemented, we shouldn't only think about beginners. Introducing a tiny separate world just for beginners does not seem very desirable to me. Anyway, this is just my personal take as a stranger. I just wrote this email because I wanted to point out the details above. -------------- next part -------------- An HTML attachment was scrubbed... URL: From im741314 at gmail.com Mon Feb 19 06:19:15 2024 From: im741314 at gmail.com (Charles) Date: Mon, 19 Feb 2024 14:19:15 +0800 Subject: possible bug with instanceof pattern matching In-Reply-To: <40b4d583-971d-4079-b5ab-f4e34a0ff32a@oracle.com> References: <40b4d583-971d-4079-b5ab-f4e34a0ff32a@oracle.com> Message-ID: Hi Brian Thanks for clarifying. I suppose the second case, which uses two separate variables, is also explained by that. Since pattern matching doesn't differentiate which "je" got created, it can't tell which variable will eventually be visible in the scope. Hence it is saying both variables are not visible in the scope. and as always, have a great day *Best Regards* *Charles* On Sun, Feb 18, 2024 at 11:33?PM Brian Goetz wrote: > This is not a bug; this potential feature was discussed at some length > during the design process. Another way this potential-feature could show > up is: > > switch (container) { > case Box(String s), Bag(String s): ... use s ... > } > > The reason that we chose not to proceed with such "binding merging" is > that when you get inside the block, `je` is one variable with two > declarations; you don't really know where the declaration is. (So IDE > navigations like "go to declaration" would have to learn to highlight TWO > (or more) declarations, for example.) > > This feature isn't fundamentally impossible, and we could consider it > again in the future, but it was a deliberate decision to not go this far at > this time. > > > On 2/18/2024 6:53 AM, Charles wrote: > > Hi all > > > What I'm about to report below is *openjdk 17*. > > > This doesn't compile > > if (ex instanceof JedisException je > || (ex instanceof ExecutionException ee && > ee.getCause() instanceof JedisException je) > ){ > ... blah blah > } > > reason being the second je is already defined in the scope. > [image: image.png] > > if you think about it. if ex is je, then, the second part won't trigger. > And if the second part is reached, then ex is not je. Hence there is only > going to be one statement mapped to je. > no confusion here. I feel this should be allowed. > > > Let's assume the above is the way it should be. I use different names for > the second variable. > > if (ex instanceof JedisException je > || (ex instanceof ExecutionException ee && > ee.getCause() instanceof JedisException second_je) > ) { > log.error(je); > log.error(second_je); > } > > [image: image.png] > This still doesn't compile. > > I would like to bring this issue up for discussion. > > > > > and as always, have a great day > > > *Best Regards * > *Charles* > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 37408 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: image.png Type: image/png Size: 33303 bytes Desc: not available URL: From p.r.doyle at gmail.com Mon Feb 19 13:52:53 2024 From: p.r.doyle at gmail.com (Patrick Doyle) Date: Mon, 19 Feb 2024 08:52:53 -0500 Subject: Bug: Compact record constructor is missing generic type info on parameters Message-ID: Hi all, I have a JUnit5 test case that demonstrates that if you use the compact constructor syntax in a record, the reflection info will be missing generic type information. Implicit constructors work fine, as do explicit canonical constructors. I found this on Temurin 21.0.2 and the Adoptium project suggested I post here. The unit test can be found in the Adoptium bug report: https://github.com/adoptium/adoptium-support/issues/1025 Let me know if there's anything I can do to help. Thanks, -- Patrick Doyle p.r.doyle at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From cay at horstmann.com Tue Feb 20 11:44:53 2024 From: cay at horstmann.com (Cay Horstmann) Date: Tue, 20 Feb 2024 12:44:53 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> Message-ID: I am one of the people who writes books for beginners. I have a whole bunch of example programs that involve reading numbers. Professors adopting my books have a ton of exercises that involve reading numbers. I can't ignore reading numbers. I agree that input and println are reasonable primitives for beginners, and that number parsing can be done in a separate step. But if that parsing step is not simple for beginners, I don't think input will find much use for beginners either. For my books, I need to decide what to do in the (n + 1)st edition. Should I stick with Scanner in = new Scanner(System.in); ... System.out.print("How old are you? "); int age = in.nextInt(); or switch to println("How old are you?"); int age = in.nextInt(); or go all the way to int age = Integer.parseInt(input("How old are you")); I have no conceptual problem with in.nextInt(). I need to explain method calls early on, so that students can work with strings. With the new way, I have a different problem. Now I need to explain to students that they can call an unqualified input, but parseInt needs to be qualified. And I have to accelerate the coverage of static methods. As Brian says, there are too many conflicting goals. If the goal is simplicity and consistency, it would be more useful not to use a magic static import. If SimpleIO.input is too long, it could be IO.in, with IO in java.lang. If the goal is convenience, it would be better to have more magically statically imported methods, in particular parseInt, parseDouble. Or readAnInt, readADouble... Cheers, Cay On 19/02/2024 18.06, Brian Goetz wrote: > There's a reason there are so many opinions here: because the goals are in conflict.? Everyone wants simplicity, but people don't agree on what "simple" means.? (Cue the jokes about "I would simply not write programs with bugs.") > > Yes, getting numbers from the user is a basic task.? But it is not, in any way, simple!? Because reading numbers from the input is invariably complected with discarding things that are "acceptably non-numbery" (e.g., whitespace), which is neither simple nor usually terribly well documented.? We've all encountered the problem in many language runtimes where reading a number using the "friendly way" leaves the input in a state that requires fixing or yields surprises for the next operation. > > This is because reading a number from an input stream is not any sort of primitive; it is the composite of reading from the input, deciding what to skip, deciding when to stop reading, converting to another type, deciding what state to leave the input stream in, and deciding what to do if no number could be found (or if the number was too big to fit into an int, etc.)? This is not^3 simple! > > C starts with a simple and principled answer, which is that the IO primitive is getchar() and putchar().? Reading or writing one character is unquestionably a primitive.? (But also, unless you are writing `cat`, no one wants to program with getchar and putchar, because it's too primitive.) > > One can make a reasonable case for "write a line / read a line" being sensible primitives.? They are simple enough: no parsing, no deciding what to throw away, no possible errors other than EOF, it is clear what state you leave the stream in.? These may not be what the student wants, but they are primitives a student can deal with without having to understand parsing and error handling and statefulness yet. > > ??? String s = getALine(); > ??? printALine(s); > > is a program every student can reason about. > > But, it is true that dealing in strings, while honest and simple, is not always what the student wants.? But herein lies the strongest argument for not trying to reinvent Scanner here: the ability to read numbers makes the complexity of the problem, and hence of the API, much much bigger.? (Scanner was very well intentioned, and was not written by children, and yet none of us want to use it.? That's a sign that a one-size-fits-all magic input processing system is harder than it looks, and for something that is explicitly aimed at beginners, is a double warning sign.) > > I could imagine someone suggesting "why don't you just add `readLineAsInt`".? But what would happen next?? Well, there would be a million requests (including from folks like Cay) of "you should add X", and then the result is a mishmash jumble of an API (that's already terrible), but worse, it's an onramp that leads to nowhere.? Once the user's needs are slightly more complicated, they are nowhere. > > Remi has it absolutely right (yes, I really said that) with > >> The classical program is: >> ?? input -> strings -> objects -> strings -> output > > We do not do users a favor by blurring the distinction between "input -> string" and "string -> object", and because the latter is so much more open-ended than the former, the latter infects the former with its complexity if we try. > > Is this simple API the most wonderful, be-all of APIs?? Of course not.? But it is a sensible set of primitives that users can understand and *build on* in a transparent way. > > Some teachers may immediately reach for teaching Integer::parseInt; that's a reasonable strategy, it exposes students to the questions of "what happens when preconditions fail", and the two compose just fine.? But maybe you don't like Integer::parseInt for some reason.? Another way to teach this is to have them write it themselves.? This will expose them to all sorts of interesting questions (what about whitespace? what about double negatives?), but of course is also throwing in the deep end of the pool.? But SimpleIO::readMeALinePlease is agnostic; it works with both approaches. > > Could the JDK use some better tools for parsing?? Sure; pattern matching has a role to play here, a `String::unformat` would be really cool, and I love parser combinators.? All of this can happen in the future, and none have the effect of making this API look like yet another white elephant like Scanner.? Because it focused purely on the basics. > > > On 2/19/2024 7:25 AM, Remi Forax wrote: >> I agree with Brian here, >> as a teacher, you have to talk about parsing and formatting, those should not be hidden. >> >> The classical program is: >> ?? input -> strings -> objects -> strings -> output >> >> R?mi >> >> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >> >> *From: *"Tagir Valeev" >> *To: *"Cay Horstmann" >> *Cc: *"Brian Goetz" , "amber-dev" >> *Sent: *Monday, February 19, 2024 10:09:35 AM >> *Subject: *Re: SimpleIO in JEP draft 8323335 >> >> I agree that simple methods to get numeric input are essential for beginners. They should not be distracted with a complex ceremony. Instead, they should be able to learn control flow statements and simple algorithms as soon as possible, having a simple way to get numbers from the user. >> With best?regards, >> Tagir Valeev. >> >> On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann wrote: >> >> Yes, that's what I am saying. If scanners live in vain, stick with a subset of the Console methods. Use its readLine. Make it so that SimpleIO uses System.console(). And add print and println to Console. >> >> The JEP talks about being able to start programming without having to know about static methods. How does a beginner read a number? With Integer.parseInt(readLine(prompt))? >> >> What about locales? Is print/println localized? Console.printf is. If so, how are beginners from around the world supposed to read localized numbers? With NumberFormat.getInstance().parse(readLine(prompt))? >> >> Adding localized readInt/readDouble to SimpleIO might do the trick. Do they consume the trailing newline? (The equivalent Scanner methods don't, which is definitely a sharp edge for beginners.) >> >> On 18/02/2024 23.08, Brian Goetz wrote: >> > OK, so is this really just that that you are bikeshedding the name?? Renaming `input` to `readLine`? >> > >> > This is a perfectly reasonable naming choice, of course, but also, not what you suggested the first time around: >> > >> >? > ... "a third API" ... >> > >> >? > ... "there are two feasible directions" ... >> > >> > So what exactly are you suggesting? >> > >> > >> > >> > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >> >> Like I said, either the scanner methods or the console methods are fine. >> >> >> >> I am of course aware of the utility/complexity of Scanner, and can understand the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in Console. >> >> >> >> You don't have to "get a console". A SimpleIO.readLine method can just invoke readLine on the system console. >> >> >> >> My objection is to add yet another "input" method into the mix. "input" is weak. Does it read a token or the entire line? Does it consume the newline? And if it does just what readLine does, why another method name? Because "input" is three characters fewer? Let's not count characters. >> >> >> >> On 18/02/2024 22.43, Brian Goetz wrote: >> >>> I think you are counting characters and not counting concepts. >> >>> >> >>> Scanner has a ton of complexity in it that can easily trip up beginners.? The main sin (though there are others) is that input and parsing are complected (e.g., nextInt), which only causes more problems (e.g., end of line issues.)?? Reading from the console is clearly a () -> String operation.? The input() method does one thing, which is get a line of text.? That's simple. >> >>> >> >>> Integer.parseInt (or, soon, patterns that match against string and bind an int) also does one thing: convert a string from int.? It may seem verbose to have to do both explicitly, but it allows each of these operations to be simple, and it is perfectly obvious what is going on. On the other hand, Scanner is a world of complexity on its own. >> >>> >> >>> Console::readLine is nice, but first you have to get a Console. ("Why can I print something without having to get some magic helper object, but I can't do the same for reading?")? What we're optimizing for here is conceptual simplicity; the simplest possible input method is the inverse of println.? The fact that input has to be validated is a fact of life; we can treat validation separately from IO (and we should), and it gets simpler when you do. >> >>> >> >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >> >>>> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 for beginning students. >> >>>> >> >>>> I am the author of college texts for introductory programming. Like other authors, I introduce the Scanner class (and not Console) for reading user input. Given that students already know about System.out, it is simpler to call >> >>>> >> >>>> System.out.print("How old are you? "); >> >>>> int x = in.nextInt(); // in is a Scanner >> >>>> >> >>>> than >> >>>> >> >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >> >>>> >> >>>> or with the JEP draft: >> >>>> >> >>>> int x = Integer.parseInt(input("How old are you? ")); >> >>>> >> >>>> Then again, having a prompt string is nice too, so I could imagine using the Console API with Integer.parseInt and Double.parseDouble, instead of Scanner.nextInt/nextDouble. >> >>>> >> >>>> But why have a third API, i.e. "input"? >> >>>> >> >>>> I think there are two feasible directions. Either embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding "input" into the mix is just clutter, and ambiguous clutter at that. At least readLine makes it clear that the entire line is consumed. >> >>>> >> >>>> Cheers, >> >>>> >> >>>> Cay >> >>>> >> >>>> -- >> >>>> >> >>>> Cay S. Horstmann | https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ | mailto:cay at horstmann.com >> >>> >> >> >> > >> >> -- >> >> -- >> >> Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com >> >> > -- -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From brian.goetz at oracle.com Tue Feb 20 14:34:09 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 20 Feb 2024 09:34:09 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> Message-ID: <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> What you're really saying is "I want more than you're giving me."? And there's nothing wrong with wanting more.? You seem to have mostly accepted that the primitive is "read a line of input as a string", but it leaves you with a problem: you don't want to read strings, you want to read numbers.? That's all fine. But the flip side of "this isn't good enough, give us more" is that if there isn't a "more" that is good enough to meet the the bar, you're going to get ... nothing.? It's a foundational design principle for Java (thanks James!) that if you don't know the right thing to do, then don't do anything (yet).? The alternatives that have been proposed (all of which we already went through before they came around again here) did not meet the bar.? This is what meets the bar.? It may not be as much as you want, but it is something, and it combines with all the other possible next steps. As a teacher, you have many choices.? You can keep doing what you've been doing, teaching Scanner; many teachers will.? Or you could distribute your own library of convenience methods -- many teachers do.? Or you could teach Integer::parseInt, which is messy, but has the benefit of being exactly as messy as the problem is -- which is also a useful lesson.? Or, or, or, or. And if you don't like the magic static import, don't use it!? Tell your students to use `SimpleIO::readAStringPlease`.? We are not trying to create a beginners dialect here. All of this is to say: we are not trying to put out a One True Only Way To Teach Java.? We're smoothing out the path in a way that admits many teaching paths, including ignoring all this stuff.? Is there more that could be done?? Of course.? And when we have a *good* candidate for what the next hundred feet of onramp looks like, we will proceed.? And I am confident that it will not conflict with these first hundred feet, because -- how could it? On 2/20/2024 6:44 AM, Cay Horstmann wrote: > I am one of the people who writes books for beginners. I have a whole > bunch of example programs that involve reading numbers. Professors > adopting my books have a ton of exercises that involve reading > numbers. I can't ignore reading numbers. > > I agree that input and println are reasonable primitives for > beginners, and that number parsing can be done in a separate step. But > if that parsing step is not simple for beginners, I don't think input > will find much use for beginners either. > > For my books, I need to decide what to do in the (n + 1)st edition. > Should I stick with > > Scanner in = new Scanner(System.in); > ... > System.out.print("How old are you? "); > int age = in.nextInt(); > > or switch to > > println("How old are you?"); > int age = in.nextInt(); > > or go all the way to > > int age = Integer.parseInt(input("How old are you")); > > I have no conceptual problem with in.nextInt(). I need to explain > method calls early on, so that students can work with strings. > > With the new way, I have a different problem. Now I need to explain to > students that they can call an unqualified input, but parseInt needs > to be qualified. And I have to accelerate the coverage of static methods. > > As Brian says, there are too many conflicting goals. > > If the goal is simplicity and consistency, it would be more useful not > to use a magic static import. If SimpleIO.input is too long, it could > be IO.in, with IO in java.lang. > > If the goal is convenience, it would be better to have more magically > statically imported methods, in particular parseInt, parseDouble. Or > readAnInt, readADouble... > > Cheers, > > Cay > > > On 19/02/2024 18.06, Brian Goetz wrote: >> There's a reason there are so many opinions here: because the goals >> are in conflict.? Everyone wants simplicity, but people don't agree >> on what "simple" means.? (Cue the jokes about "I would simply not >> write programs with bugs.") >> >> Yes, getting numbers from the user is a basic task.? But it is not, >> in any way, simple!? Because reading numbers from the input is >> invariably complected with discarding things that are "acceptably >> non-numbery" (e.g., whitespace), which is neither simple nor usually >> terribly well documented.? We've all encountered the problem in many >> language runtimes where reading a number using the "friendly way" >> leaves the input in a state that requires fixing or yields surprises >> for the next operation. >> >> This is because reading a number from an input stream is not any sort >> of primitive; it is the composite of reading from the input, deciding >> what to skip, deciding when to stop reading, converting to another >> type, deciding what state to leave the input stream in, and deciding >> what to do if no number could be found (or if the number was too big >> to fit into an int, etc.) This is not^3 simple! >> >> C starts with a simple and principled answer, which is that the IO >> primitive is getchar() and putchar().? Reading or writing one >> character is unquestionably a primitive.? (But also, unless you are >> writing `cat`, no one wants to program with getchar and putchar, >> because it's too primitive.) >> >> One can make a reasonable case for "write a line / read a line" being >> sensible primitives.? They are simple enough: no parsing, no deciding >> what to throw away, no possible errors other than EOF, it is clear >> what state you leave the stream in.? These may not be what the >> student wants, but they are primitives a student can deal with >> without having to understand parsing and error handling and >> statefulness yet. >> >> ???? String s = getALine(); >> ???? printALine(s); >> >> is a program every student can reason about. >> >> But, it is true that dealing in strings, while honest and simple, is >> not always what the student wants.? But herein lies the strongest >> argument for not trying to reinvent Scanner here: the ability to read >> numbers makes the complexity of the problem, and hence of the API, >> much much bigger.? (Scanner was very well intentioned, and was not >> written by children, and yet none of us want to use it.? That's a >> sign that a one-size-fits-all magic input processing system is harder >> than it looks, and for something that is explicitly aimed at >> beginners, is a double warning sign.) >> >> I could imagine someone suggesting "why don't you just add >> `readLineAsInt`".? But what would happen next?? Well, there would be >> a million requests (including from folks like Cay) of "you should add >> X", and then the result is a mishmash jumble of an API (that's >> already terrible), but worse, it's an onramp that leads to nowhere.? >> Once the user's needs are slightly more complicated, they are nowhere. >> >> Remi has it absolutely right (yes, I really said that) with >> >>> The classical program is: >>> ?? input -> strings -> objects -> strings -> output >> >> We do not do users a favor by blurring the distinction between "input >> -> string" and "string -> object", and because the latter is so much >> more open-ended than the former, the latter infects the former with >> its complexity if we try. >> >> Is this simple API the most wonderful, be-all of APIs?? Of course >> not.? But it is a sensible set of primitives that users can >> understand and *build on* in a transparent way. >> >> Some teachers may immediately reach for teaching Integer::parseInt; >> that's a reasonable strategy, it exposes students to the questions of >> "what happens when preconditions fail", and the two compose just >> fine.? But maybe you don't like Integer::parseInt for some reason.? >> Another way to teach this is to have them write it themselves.? This >> will expose them to all sorts of interesting questions (what about >> whitespace? what about double negatives?), but of course is also >> throwing in the deep end of the pool.? But >> SimpleIO::readMeALinePlease is agnostic; it works with both approaches. >> >> Could the JDK use some better tools for parsing?? Sure; pattern >> matching has a role to play here, a `String::unformat` would be >> really cool, and I love parser combinators.? All of this can happen >> in the future, and none have the effect of making this API look like >> yet another white elephant like Scanner.? Because it focused purely >> on the basics. >> >> >> On 2/19/2024 7:25 AM, Remi Forax wrote: >>> I agree with Brian here, >>> as a teacher, you have to talk about parsing and formatting, those >>> should not be hidden. >>> >>> The classical program is: >>> ?? input -> strings -> objects -> strings -> output >>> >>> R?mi >>> >>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >>> >>> >>> ??? *From: *"Tagir Valeev" >>> ??? *To: *"Cay Horstmann" >>> ??? *Cc: *"Brian Goetz" , "amber-dev" >>> >>> ??? *Sent: *Monday, February 19, 2024 10:09:35 AM >>> ??? *Subject: *Re: SimpleIO in JEP draft 8323335 >>> >>> ??? I agree that simple methods to get numeric input are essential >>> for beginners. They should not be distracted with a complex >>> ceremony. Instead, they should be able to learn control flow >>> statements and simple algorithms as soon as possible, having a >>> simple way to get numbers from the user. >>> ??? With best?regards, >>> ??? Tagir Valeev. >>> >>> ??? On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann >>> wrote: >>> >>> ??????? Yes, that's what I am saying. If scanners live in vain, >>> stick with a subset of the Console methods. Use its readLine. Make >>> it so that SimpleIO uses System.console(). And add print and println >>> to Console. >>> >>> ??????? The JEP talks about being able to start programming without >>> having to know about static methods. How does a beginner read a >>> number? With Integer.parseInt(readLine(prompt))? >>> >>> ??????? What about locales? Is print/println localized? >>> Console.printf is. If so, how are beginners from around the world >>> supposed to read localized numbers? With >>> NumberFormat.getInstance().parse(readLine(prompt))? >>> >>> ??????? Adding localized readInt/readDouble to SimpleIO might do the >>> trick. Do they consume the trailing newline? (The equivalent Scanner >>> methods don't, which is definitely a sharp edge for beginners.) >>> >>> ??????? On 18/02/2024 23.08, Brian Goetz wrote: >>> ??????? > OK, so is this really just that that you are bikeshedding >>> the name?? Renaming `input` to `readLine`? >>> ??????? > >>> ??????? > This is a perfectly reasonable naming choice, of course, >>> but also, not what you suggested the first time around: >>> ??????? > >>> ??????? >? > ... "a third API" ... >>> ??????? > >>> ??????? >? > ... "there are two feasible directions" ... >>> ??????? > >>> ??????? > So what exactly are you suggesting? >>> ??????? > >>> ??????? > >>> ??????? > >>> ??????? > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >>> ??????? >> Like I said, either the scanner methods or the console >>> methods are fine. >>> ??????? >> >>> ??????? >> I am of course aware of the utility/complexity of >>> Scanner, and can understand the motivation to have a simpler/feebler >>> behavior in SimpleIO. Like the one in Console. >>> ??????? >> >>> ??????? >> You don't have to "get a console". A SimpleIO.readLine >>> method can just invoke readLine on the system console. >>> ??????? >> >>> ??????? >> My objection is to add yet another "input" method into >>> the mix. "input" is weak. Does it read a token or the entire line? >>> Does it consume the newline? And if it does just what readLine does, >>> why another method name? Because "input" is three characters fewer? >>> Let's not count characters. >>> ??????? >> >>> ??????? >> On 18/02/2024 22.43, Brian Goetz wrote: >>> ??????? >>> I think you are counting characters and not counting >>> concepts. >>> ??????? >>> >>> ??????? >>> Scanner has a ton of complexity in it that can easily >>> trip up beginners.? The main sin (though there are others) is that >>> input and parsing are complected (e.g., nextInt), which only causes >>> more problems (e.g., end of line issues.)?? Reading from the console >>> is clearly a () -> String operation.? The input() method does one >>> thing, which is get a line of text.? That's simple. >>> ??????? >>> >>> ??????? >>> Integer.parseInt (or, soon, patterns that match against >>> string and bind an int) also does one thing: convert a string from >>> int.? It may seem verbose to have to do both explicitly, but it >>> allows each of these operations to be simple, and it is perfectly >>> obvious what is going on. On the other hand, Scanner is a world of >>> complexity on its own. >>> ??????? >>> >>> ??????? >>> Console::readLine is nice, but first you have to get a >>> Console. ("Why can I print something without having to get some >>> magic helper object, but I can't do the same for reading?")? What >>> we're optimizing for here is conceptual simplicity; the simplest >>> possible input method is the inverse of println.? The fact that >>> input has to be validated is a fact of life; we can treat validation >>> separately from IO (and we should), and it gets simpler when you do. >>> ??????? >>> >>> ??????? >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>> ??????? >>>> I would like to comment on the simplicity of >>> https://openjdk.org/jeps/8323335 for beginning students. >>> ??????? >>>> >>> ??????? >>>> I am the author of college texts for introductory >>> programming. Like other authors, I introduce the Scanner class (and >>> not Console) for reading user input. Given that students already >>> know about System.out, it is simpler to call >>> ??????? >>>> >>> ??????? >>>> System.out.print("How old are you? "); >>> ??????? >>>> int x = in.nextInt(); // in is a Scanner >>> ??????? >>>> >>> ??????? >>>> than >>> ??????? >>>> >>> ??????? >>>> int x = Integer.parseInt(console.readLine("How old are >>> you? ")); >>> ??????? >>>> >>> ??????? >>>> or with the JEP draft: >>> ??????? >>>> >>> ??????? >>>> int x = Integer.parseInt(input("How old are you? ")); >>> ??????? >>>> >>> ??????? >>>> Then again, having a prompt string is nice too, so I >>> could imagine using the Console API with Integer.parseInt and >>> Double.parseDouble, instead of Scanner.nextInt/nextDouble. >>> ??????? >>>> >>> ??????? >>>> But why have a third API, i.e. "input"? >>> ??????? >>>> >>> ??????? >>>> I think there are two feasible directions. Either >>> embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the >>> Console API and readLine. Adding "input" into the mix is just >>> clutter, and ambiguous clutter at that. At least readLine makes it >>> clear that the entire line is consumed. >>> ??????? >>>> >>> ??????? >>>> Cheers, >>> ??????? >>>> >>> ??????? >>>> Cay >>> ??????? >>>> >>> ??????? >>>> -- >>> ??????? >>>> >>> ??????? >>>> Cay S. Horstmann | >>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>> | mailto:cay at horstmann.com >>> ??????? >>> >>> ??????? >> >>> ??????? > >>> >>> ??????? -- >>> ??????? -- >>> >>> ??????? Cay S. Horstmann | >>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$ >>> >>> | mailto:cay at horstmann.com >>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From amaembo at gmail.com Tue Feb 20 14:47:08 2024 From: amaembo at gmail.com (Tagir Valeev) Date: Tue, 20 Feb 2024 15:47:08 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> Message-ID: I guess, this is not about "give me more" but about "design a thing that will be really useful". If SimpleIO will not be satisfactory for solving 90% of student problems, then probably there's no point in introducing it at all? Surely, one should draw a line somewhere, but it looks like if the purpose of the new API is to easen the learning of Java, then an ability to input numbers should be there. Teaching Integer::parseInt or new Scanner() sounds contradicting to the idea of hiding irrelevant details like classes and static methods from the students until they need them. Because you'll need to explain what is Integer and what is parseInt. Or probably you can say "don't care now, just write it this way, we'll cover this later". But is it much different from public static void main? Why did we start all of this in the first place? When I was a child, I learned BASIC, and I remember that one could ask a number from a user typing simply INPUT X. The concept of string variables like X$ was introduced much later, so in my mind it was completely ok that we can ask for a number, without an intermediate step like ask for a string, then convert it to the number. Not sure if it was pedagogically correct but it certainly simplified my first steps in computer programming (well, paper programming in fact, as I had no computer). With best regards, Tagir Valeev. On Tue, Feb 20, 2024 at 3:34?PM Brian Goetz wrote: > What you're really saying is "I want more than you're giving me." And > there's nothing wrong with wanting more. You seem to have mostly accepted > that the primitive is "read a line of input as a string", but it leaves you > with a problem: you don't want to read strings, you want to read numbers. > That's all fine. > > But the flip side of "this isn't good enough, give us more" is that if > there isn't a "more" that is good enough to meet the the bar, you're going > to get ... nothing. It's a foundational design principle for Java (thanks > James!) that if you don't know the right thing to do, then don't do > anything (yet). The alternatives that have been proposed (all of which we > already went through before they came around again here) did not meet the > bar. This is what meets the bar. It may not be as much as you want, but > it is something, and it combines with all the other possible next steps. > > As a teacher, you have many choices. You can keep doing what you've been > doing, teaching Scanner; many teachers will. Or you could distribute your > own library of convenience methods -- many teachers do. Or you could teach > Integer::parseInt, which is messy, but has the benefit of being exactly as > messy as the problem is -- which is also a useful lesson. Or, or, or, or. > > And if you don't like the magic static import, don't use it! Tell your > students to use `SimpleIO::readAStringPlease`. We are not trying to create > a beginners dialect here. > > All of this is to say: we are not trying to put out a One True Only Way To > Teach Java. We're smoothing out the path in a way that admits many > teaching paths, including ignoring all this stuff. Is there more that > could be done? Of course. And when we have a *good* candidate for what > the next hundred feet of onramp looks like, we will proceed. And I am > confident that it will not conflict with these first hundred feet, because > -- how could it? > > > > > > On 2/20/2024 6:44 AM, Cay Horstmann wrote: > > I am one of the people who writes books for beginners. I have a whole > bunch of example programs that involve reading numbers. Professors adopting > my books have a ton of exercises that involve reading numbers. I can't > ignore reading numbers. > > I agree that input and println are reasonable primitives for beginners, > and that number parsing can be done in a separate step. But if that parsing > step is not simple for beginners, I don't think input will find much use > for beginners either. > > For my books, I need to decide what to do in the (n + 1)st edition. Should > I stick with > > Scanner in = new Scanner(System.in); > ... > System.out.print("How old are you? "); > int age = in.nextInt(); > > or switch to > > println("How old are you?"); > int age = in.nextInt(); > > or go all the way to > > int age = Integer.parseInt(input("How old are you")); > > I have no conceptual problem with in.nextInt(). I need to explain method > calls early on, so that students can work with strings. > > With the new way, I have a different problem. Now I need to explain to > students that they can call an unqualified input, but parseInt needs to be > qualified. And I have to accelerate the coverage of static methods. > > As Brian says, there are too many conflicting goals. > > If the goal is simplicity and consistency, it would be more useful not to > use a magic static import. If SimpleIO.input is too long, it could be > IO.in, with IO in java.lang. > > If the goal is convenience, it would be better to have more magically > statically imported methods, in particular parseInt, parseDouble. Or > readAnInt, readADouble... > > Cheers, > > Cay > > > On 19/02/2024 18.06, Brian Goetz wrote: > > There's a reason there are so many opinions here: because the goals are in > conflict. Everyone wants simplicity, but people don't agree on what > "simple" means. (Cue the jokes about "I would simply not write programs > with bugs.") > > Yes, getting numbers from the user is a basic task. But it is not, in any > way, simple! Because reading numbers from the input is invariably > complected with discarding things that are "acceptably non-numbery" (e.g., > whitespace), which is neither simple nor usually terribly well documented. > We've all encountered the problem in many language runtimes where reading a > number using the "friendly way" leaves the input in a state that requires > fixing or yields surprises for the next operation. > > This is because reading a number from an input stream is not any sort of > primitive; it is the composite of reading from the input, deciding what to > skip, deciding when to stop reading, converting to another type, deciding > what state to leave the input stream in, and deciding what to do if no > number could be found (or if the number was too big to fit into an int, > etc.) This is not^3 simple! > > C starts with a simple and principled answer, which is that the IO > primitive is getchar() and putchar(). Reading or writing one character is > unquestionably a primitive. (But also, unless you are writing `cat`, no > one wants to program with getchar and putchar, because it's too primitive.) > > One can make a reasonable case for "write a line / read a line" being > sensible primitives. They are simple enough: no parsing, no deciding what > to throw away, no possible errors other than EOF, it is clear what state > you leave the stream in. These may not be what the student wants, but they > are primitives a student can deal with without having to understand parsing > and error handling and statefulness yet. > > String s = getALine(); > printALine(s); > > is a program every student can reason about. > > But, it is true that dealing in strings, while honest and simple, is not > always what the student wants. But herein lies the strongest argument for > not trying to reinvent Scanner here: the ability to read numbers makes the > complexity of the problem, and hence of the API, much much bigger. > (Scanner was very well intentioned, and was not written by children, and > yet none of us want to use it. That's a sign that a one-size-fits-all > magic input processing system is harder than it looks, and for something > that is explicitly aimed at beginners, is a double warning sign.) > > I could imagine someone suggesting "why don't you just add > `readLineAsInt`". But what would happen next? Well, there would be a > million requests (including from folks like Cay) of "you should add X", and > then the result is a mishmash jumble of an API (that's already terrible), > but worse, it's an onramp that leads to nowhere. Once the user's needs are > slightly more complicated, they are nowhere. > > Remi has it absolutely right (yes, I really said that) with > > The classical program is: > input -> strings -> objects -> strings -> output > > > We do not do users a favor by blurring the distinction between "input -> > string" and "string -> object", and because the latter is so much more > open-ended than the former, the latter infects the former with its > complexity if we try. > > Is this simple API the most wonderful, be-all of APIs? Of course not. > But it is a sensible set of primitives that users can understand and *build > on* in a transparent way. > > Some teachers may immediately reach for teaching Integer::parseInt; that's > a reasonable strategy, it exposes students to the questions of "what > happens when preconditions fail", and the two compose just fine. But maybe > you don't like Integer::parseInt for some reason. Another way to teach > this is to have them write it themselves. This will expose them to all > sorts of interesting questions (what about whitespace? what about double > negatives?), but of course is also throwing in the deep end of the pool. > But SimpleIO::readMeALinePlease is agnostic; it works with both approaches. > > Could the JDK use some better tools for parsing? Sure; pattern matching > has a role to play here, a `String::unformat` would be really cool, and I > love parser combinators. All of this can happen in the future, and none > have the effect of making this API look like yet another white elephant > like Scanner. Because it focused purely on the basics. > > > On 2/19/2024 7:25 AM, Remi Forax wrote: > > I agree with Brian here, > as a teacher, you have to talk about parsing and formatting, those should > not be hidden. > > The classical program is: > input -> strings -> objects -> strings -> output > > R?mi > > ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ > > > *From: *"Tagir Valeev" > *To: *"Cay Horstmann" > *Cc: *"Brian Goetz" , > "amber-dev" > *Sent: *Monday, February 19, 2024 10:09:35 AM > *Subject: *Re: SimpleIO in JEP draft 8323335 > > I agree that simple methods to get numeric input are essential for > beginners. They should not be distracted with a complex ceremony. Instead, > they should be able to learn control flow statements and simple algorithms > as soon as possible, having a simple way to get numbers from the user. > With best regards, > Tagir Valeev. > > On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann > wrote: > > Yes, that's what I am saying. If scanners live in vain, stick with > a subset of the Console methods. Use its readLine. Make it so that SimpleIO > uses System.console(). And add print and println to Console. > > The JEP talks about being able to start programming without having > to know about static methods. How does a beginner read a number? With > Integer.parseInt(readLine(prompt))? > > What about locales? Is print/println localized? Console.printf is. > If so, how are beginners from around the world supposed to read localized > numbers? With NumberFormat.getInstance().parse(readLine(prompt))? > > Adding localized readInt/readDouble to SimpleIO might do the > trick. Do they consume the trailing newline? (The equivalent Scanner > methods don't, which is definitely a sharp edge for beginners.) > > On 18/02/2024 23.08, Brian Goetz wrote: > > OK, so is this really just that that you are bikeshedding the > name? Renaming `input` to `readLine`? > > > > This is a perfectly reasonable naming choice, of course, but > also, not what you suggested the first time around: > > > > > ... "a third API" ... > > > > > ... "there are two feasible directions" ... > > > > So what exactly are you suggesting? > > > > > > > > On 2/18/2024 5:03 PM, Cay Horstmann wrote: > >> Like I said, either the scanner methods or the console methods > are fine. > >> > >> I am of course aware of the utility/complexity of Scanner, and > can understand the motivation to have a simpler/feebler behavior in > SimpleIO. Like the one in Console. > >> > >> You don't have to "get a console". A SimpleIO.readLine method > can just invoke readLine on the system console. > >> > >> My objection is to add yet another "input" method into the mix. > "input" is weak. Does it read a token or the entire line? Does it consume > the newline? And if it does just what readLine does, why another method > name? Because "input" is three characters fewer? Let's not count > characters. > >> > >> On 18/02/2024 22.43, Brian Goetz wrote: > >>> I think you are counting characters and not counting concepts. > >>> > >>> Scanner has a ton of complexity in it that can easily trip up > beginners. The main sin (though there are others) is that input and > parsing are complected (e.g., nextInt), which only causes more problems > (e.g., end of line issues.) Reading from the console is clearly a () -> > String operation. The input() method does one thing, which is get a line > of text. That's simple. > >>> > >>> Integer.parseInt (or, soon, patterns that match against string > and bind an int) also does one thing: convert a string from int. It may > seem verbose to have to do both explicitly, but it allows each of these > operations to be simple, and it is perfectly obvious what is going on. On > the other hand, Scanner is a world of complexity on its own. > >>> > >>> Console::readLine is nice, but first you have to get a > Console. ("Why can I print something without having to get some magic > helper object, but I can't do the same for reading?") What we're > optimizing for here is conceptual simplicity; the simplest possible input > method is the inverse of println. The fact that input has to be validated > is a fact of life; we can treat validation separately from IO (and we > should), and it gets simpler when you do. > >>> > >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: > >>>> I would like to comment on the simplicity of > https://openjdk.org/jeps/8323335 for beginning students. > >>>> > >>>> I am the author of college texts for introductory > programming. Like other authors, I introduce the Scanner class (and not > Console) for reading user input. Given that students already know about > System.out, it is simpler to call > >>>> > >>>> System.out.print("How old are you? "); > >>>> int x = in.nextInt(); // in is a Scanner > >>>> > >>>> than > >>>> > >>>> int x = Integer.parseInt(console.readLine("How old are you? > ")); > >>>> > >>>> or with the JEP draft: > >>>> > >>>> int x = Integer.parseInt(input("How old are you? ")); > >>>> > >>>> Then again, having a prompt string is nice too, so I could > imagine using the Console API with Integer.parseInt and Double.parseDouble, > instead of Scanner.nextInt/nextDouble. > >>>> > >>>> But why have a third API, i.e. "input"? > >>>> > >>>> I think there are two feasible directions. Either embrace the > Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and > readLine. Adding "input" into the mix is just clutter, and ambiguous > clutter at that. At least readLine makes it clear that the entire line is > consumed. > >>>> > >>>> Cheers, > >>>> > >>>> Cay > >>>> > >>>> -- > >>>> > >>>> Cay S. Horstmann | > https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ > | mailto:cay at horstmann.com > >>> > >> > > > > -- > -- > > Cay S. Horstmann | > https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$ > > > > | mailto:cay at horstmann.com > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Feb 20 15:12:42 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 20 Feb 2024 10:12:42 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> Message-ID: > I guess, this is not about "give me more" but about "design a thing > that will be really useful". If SimpleIO will not be satisfactory for > solving 90% of student problems, then probably there's no point in > introducing it at all? I'm willing to have that discussion! We could draw the line at "nothing", which is the status quo. That's always an option. We could draw the line at "println only".? That is surely better than nothing, succeeds 100% at hitting a very very limited goal, but is very .. limited.? But it is a perfectly viable candidate. This proposal goes one step farther, giving the dual of println.? It also seems a viable candidate, and also seems better than nothing. None of the proposals involving parsing numbers seem remotely good enough.? So they are all, currently, worse than nothing. Now, better-than-nothing is surely not the bar, though.? One of the other considerations is "if we do more later, will progress be colinear with this."? Given the degree of restraint shown here (line-based console IO <--> String), it is hard to imagine concluding later "wow, we goofed there."? Could happen, but seems unlikely, because we are sticking to sensible primitives. > Teaching Integer::parseInt or new Scanner() sounds contradicting to > the idea of hiding irrelevant details like classes and static methods > from the students until they need them. But, hiding all irrelevant detail is not the goal!? Otherwise we'd be saying "Ask ChatGPT to write your program for you!"? What we're looking to hide (temporarily) is *linguistic* mechanisms whose value is in *structuring larger programs*, until such mechanisms *provide value to the program*.? Packages, access control, static, etc, are program-organization concepts, which benefit large programs but are a tax on small ones.? When your program is six lines long, it doesn't need help organizing itself, and even if it did, these things don't help yet, they just feel like a tax. That's not to say we can't also try to simplify more things; this is the *first* JEP in this area, not the last.? But mission-creep is a real risk here, and whenever the goal is as diffuse as "simplicity", which everyone interprets their own way, mission-creep is almost inevitable.? So I don't object to "I want to solve this problem too" (we can keep talking, the JDK is a living entity), but I prefer to avoid "If you don't solve this problem, it's not worth doing anything."? Because there's always more we could do. Here's a thought experiment: what concept would we want to guide users towards for going from string to number?? My favorite is exposing the pattern dual of Integer::toString. ? The existing Integer::toString is a function int -> String; like most total functions, it has a pattern dual: ??? if (s instanceof Integer.toString(int i)) { ?????? // use i ??? } This is already much better than `Integer::parseInt`, because (a) it captures the inherent partiality of the operation, (b) you can't sweep the failure under the rug by ignoring NumberFormatException, and (c) the duality with the function `Integer::toString` is obvious; they are two sides of the same coin. But there are many other possibilities, nearly all better than Scanner.? Its a totally valid discussion, but I'm not sure we should gate this installment on it? > Because you'll need to explain what is Integer and what is parseInt. > Or probably you can say "don't care now, just write it this way, we'll > cover this later". But is it much different from public static void > main? Why did we start all of this in the first place? > > When I was a child, I learned BASIC, and I remember that one could ask > a number from a user typing simply INPUT X. The concept of string > variables like X$ was introduced much later, so in my mind it was > completely ok that we can ask for a number, without an intermediate > step like ask for a string, then convert it to the number. Not sure if > it was pedagogically?correct but it certainly simplified my first > steps in computer programming (well, paper programming in fact, as I > had no computer). > > With best regards, > Tagir Valeev. > > On Tue, Feb 20, 2024 at 3:34?PM Brian Goetz > wrote: > > What you're really saying is "I want more than you're giving me."? > And there's nothing wrong with wanting more.? You seem to have > mostly accepted that the primitive is "read a line of input as a > string", but it leaves you with a problem: you don't want to read > strings, you want to read numbers.? That's all fine. > > But the flip side of "this isn't good enough, give us more" is > that if there isn't a "more" that is good enough to meet the the > bar, you're going to get ... nothing.? It's a foundational design > principle for Java (thanks James!) that if you don't know the > right thing to do, then don't do anything (yet).? The alternatives > that have been proposed (all of which we already went through > before they came around again here) did not meet the bar.? This is > what meets the bar.? It may not be as much as you want, but it is > something, and it combines with all the other possible next steps. > > As a teacher, you have many choices.? You can keep doing what > you've been doing, teaching Scanner; many teachers will.? Or you > could distribute your own library of convenience methods -- many > teachers do.? Or you could teach Integer::parseInt, which is > messy, but has the benefit of being exactly as messy as the > problem is -- which is also a useful lesson.? Or, or, or, or. > > And if you don't like the magic static import, don't use it!? Tell > your students to use `SimpleIO::readAStringPlease`.? We are not > trying to create a beginners dialect here. > > All of this is to say: we are not trying to put out a One True > Only Way To Teach Java.? We're smoothing out the path in a way > that admits many teaching paths, including ignoring all this > stuff.? Is there more that could be done?? Of course.? And when we > have a *good* candidate for what the next hundred feet of onramp > looks like, we will proceed.? And I am confident that it will not > conflict with these first hundred feet, because -- how could it? > > > > > > On 2/20/2024 6:44 AM, Cay Horstmann wrote: >> I am one of the people who writes books for beginners. I have a >> whole bunch of example programs that involve reading numbers. >> Professors adopting my books have a ton of exercises that involve >> reading numbers. I can't ignore reading numbers. >> >> I agree that input and println are reasonable primitives for >> beginners, and that number parsing can be done in a separate >> step. But if that parsing step is not simple for beginners, I >> don't think input will find much use for beginners either. >> >> For my books, I need to decide what to do in the (n + 1)st >> edition. Should I stick with >> >> Scanner in = new Scanner(System.in); >> ... >> System.out.print("How old are you? "); >> int age = in.nextInt(); >> >> or switch to >> >> println("How old are you?"); >> int age = in.nextInt(); >> >> or go all the way to >> >> int age = Integer.parseInt(input("How old are you")); >> >> I have no conceptual problem with in.nextInt(). I need to explain >> method calls early on, so that students can work with strings. >> >> With the new way, I have a different problem. Now I need to >> explain to students that they can call an unqualified input, but >> parseInt needs to be qualified. And I have to accelerate the >> coverage of static methods. >> >> As Brian says, there are too many conflicting goals. >> >> If the goal is simplicity and consistency, it would be more >> useful not to use a magic static import. If SimpleIO.input is too >> long, it could be IO.in, with IO in java.lang. >> >> If the goal is convenience, it would be better to have more >> magically statically imported methods, in particular parseInt, >> parseDouble. Or readAnInt, readADouble... >> >> Cheers, >> >> Cay >> >> >> On 19/02/2024 18.06, Brian Goetz wrote: >>> There's a reason there are so many opinions here: because the >>> goals are in conflict.? Everyone wants simplicity, but people >>> don't agree on what "simple" means.? (Cue the jokes about "I >>> would simply not write programs with bugs.") >>> >>> Yes, getting numbers from the user is a basic task. But it is >>> not, in any way, simple!? Because reading numbers from the input >>> is invariably complected with discarding things that are >>> "acceptably non-numbery" (e.g., whitespace), which is neither >>> simple nor usually terribly well documented.? We've all >>> encountered the problem in many language runtimes where reading >>> a number using the "friendly way" leaves the input in a state >>> that requires fixing or yields surprises for the next operation. >>> >>> This is because reading a number from an input stream is not any >>> sort of primitive; it is the composite of reading from the >>> input, deciding what to skip, deciding when to stop reading, >>> converting to another type, deciding what state to leave the >>> input stream in, and deciding what to do if no number could be >>> found (or if the number was too big to fit into an int, etc.)? >>> This is not^3 simple! >>> >>> C starts with a simple and principled answer, which is that the >>> IO primitive is getchar() and putchar(). Reading or writing one >>> character is unquestionably a primitive.? (But also, unless you >>> are writing `cat`, no one wants to program with getchar and >>> putchar, because it's too primitive.) >>> >>> One can make a reasonable case for "write a line / read a line" >>> being sensible primitives.? They are simple enough: no parsing, >>> no deciding what to throw away, no possible errors other than >>> EOF, it is clear what state you leave the stream in.? These may >>> not be what the student wants, but they are primitives a student >>> can deal with without having to understand parsing and error >>> handling and statefulness yet. >>> >>> ???? String s = getALine(); >>> ???? printALine(s); >>> >>> is a program every student can reason about. >>> >>> But, it is true that dealing in strings, while honest and >>> simple, is not always what the student wants.? But herein lies >>> the strongest argument for not trying to reinvent Scanner here: >>> the ability to read numbers makes the complexity of the problem, >>> and hence of the API, much much bigger.? (Scanner was very well >>> intentioned, and was not written by children, and yet none of us >>> want to use it.? That's a sign that a one-size-fits-all magic >>> input processing system is harder than it looks, and for >>> something that is explicitly aimed at beginners, is a double >>> warning sign.) >>> >>> I could imagine someone suggesting "why don't you just add >>> `readLineAsInt`".? But what would happen next? Well, there would >>> be a million requests (including from folks like Cay) of "you >>> should add X", and then the result is a mishmash jumble of an >>> API (that's already terrible), but worse, it's an onramp that >>> leads to nowhere.? Once the user's needs are slightly more >>> complicated, they are nowhere. >>> >>> Remi has it absolutely right (yes, I really said that) with >>> >>>> The classical program is: >>>> ?? input -> strings -> objects -> strings -> output >>> >>> We do not do users a favor by blurring the distinction between >>> "input -> string" and "string -> object", and because the latter >>> is so much more open-ended than the former, the latter infects >>> the former with its complexity if we try. >>> >>> Is this simple API the most wonderful, be-all of APIs?? Of >>> course not.? But it is a sensible set of primitives that users >>> can understand and *build on* in a transparent way. >>> >>> Some teachers may immediately reach for teaching >>> Integer::parseInt; that's a reasonable strategy, it exposes >>> students to the questions of "what happens when preconditions >>> fail", and the two compose just fine.? But maybe you don't like >>> Integer::parseInt for some reason.? Another way to teach this is >>> to have them write it themselves.? This will expose them to all >>> sorts of interesting questions (what about whitespace? what >>> about double negatives?), but of course is also throwing in the >>> deep end of the pool. But SimpleIO::readMeALinePlease is >>> agnostic; it works with both approaches. >>> >>> Could the JDK use some better tools for parsing? Sure; pattern >>> matching has a role to play here, a `String::unformat` would be >>> really cool, and I love parser combinators.? All of this can >>> happen in the future, and none have the effect of making this >>> API look like yet another white elephant like Scanner. Because >>> it focused purely on the basics. >>> >>> >>> On 2/19/2024 7:25 AM, Remi Forax wrote: >>>> I agree with Brian here, >>>> as a teacher, you have to talk about parsing and formatting, >>>> those should not be hidden. >>>> >>>> The classical program is: >>>> ?? input -> strings -> objects -> strings -> output >>>> >>>> R?mi >>>> >>>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >>>> >>>> >>>> ??? *From: *"Tagir Valeev" >>>> >>>> ??? *To: *"Cay Horstmann" >>>> >>>> ??? *Cc: *"Brian Goetz" >>>> , "amber-dev" >>>> >>>> ??? *Sent: *Monday, February 19, 2024 10:09:35 AM >>>> ??? *Subject: *Re: SimpleIO in JEP draft 8323335 >>>> >>>> ??? I agree that simple methods to get numeric input are >>>> essential for beginners. They should not be distracted with a >>>> complex ceremony. Instead, they should be able to learn control >>>> flow statements and simple algorithms as soon as possible, >>>> having a simple way to get numbers from the user. >>>> ??? With best?regards, >>>> ??? Tagir Valeev. >>>> >>>> ??? On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann >>>> wrote: >>>> >>>> ??????? Yes, that's what I am saying. If scanners live in vain, >>>> stick with a subset of the Console methods. Use its readLine. >>>> Make it so that SimpleIO uses System.console(). And add print >>>> and println to Console. >>>> >>>> ??????? The JEP talks about being able to start programming >>>> without having to know about static methods. How does a >>>> beginner read a number? With Integer.parseInt(readLine(prompt))? >>>> >>>> ??????? What about locales? Is print/println localized? >>>> Console.printf is. If so, how are beginners from around the >>>> world supposed to read localized numbers? With >>>> NumberFormat.getInstance().parse(readLine(prompt))? >>>> >>>> ??????? Adding localized readInt/readDouble to SimpleIO might >>>> do the trick. Do they consume the trailing newline? (The >>>> equivalent Scanner methods don't, which is definitely a sharp >>>> edge for beginners.) >>>> >>>> ??????? On 18/02/2024 23.08, Brian Goetz wrote: >>>> ??????? > OK, so is this really just that that you are >>>> bikeshedding the name?? Renaming `input` to `readLine`? >>>> ??????? > >>>> ??????? > This is a perfectly reasonable naming choice, of >>>> course, but also, not what you suggested the first time around: >>>> ??????? > >>>> ??????? >? > ... "a third API" ... >>>> ??????? > >>>> ??????? >? > ... "there are two feasible directions" ... >>>> ??????? > >>>> ??????? > So what exactly are you suggesting? >>>> ??????? > >>>> ??????? > >>>> ??????? > >>>> ??????? > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >>>> ??????? >> Like I said, either the scanner methods or the >>>> console methods are fine. >>>> ??????? >> >>>> ??????? >> I am of course aware of the utility/complexity of >>>> Scanner, and can understand the motivation to have a >>>> simpler/feebler behavior in SimpleIO. Like the one in Console. >>>> ??????? >> >>>> ??????? >> You don't have to "get a console". A >>>> SimpleIO.readLine method can just invoke readLine on the system >>>> console. >>>> ??????? >> >>>> ??????? >> My objection is to add yet another "input" method >>>> into the mix. "input" is weak. Does it read a token or the >>>> entire line? Does it consume the newline? And if it does just >>>> what readLine does, why another method name? Because "input" is >>>> three characters fewer? Let's not count characters. >>>> ??????? >> >>>> ??????? >> On 18/02/2024 22.43, Brian Goetz wrote: >>>> ??????? >>> I think you are counting characters and not >>>> counting concepts. >>>> ??????? >>> >>>> ??????? >>> Scanner has a ton of complexity in it that can >>>> easily trip up beginners.? The main sin (though there are >>>> others) is that input and parsing are complected (e.g., >>>> nextInt), which only causes more problems (e.g., end of line >>>> issues.) Reading from the console is clearly a () -> String >>>> operation.? The input() method does one thing, which is get a >>>> line of text.? That's simple. >>>> ??????? >>> >>>> ??????? >>> Integer.parseInt (or, soon, patterns that match >>>> against string and bind an int) also does one thing: convert a >>>> string from int.? It may seem verbose to have to do both >>>> explicitly, but it allows each of these operations to be >>>> simple, and it is perfectly obvious what is going on. On the >>>> other hand, Scanner is a world of complexity on its own. >>>> ??????? >>> >>>> ??????? >>> Console::readLine is nice, but first you have to >>>> get a Console. ("Why can I print something without having to >>>> get some magic helper object, but I can't do the same for >>>> reading?")? What we're optimizing for here is conceptual >>>> simplicity; the simplest possible input method is the inverse >>>> of println.? The fact that input has to be validated is a fact >>>> of life; we can treat validation separately from IO (and we >>>> should), and it gets simpler when you do. >>>> ??????? >>> >>>> ??????? >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>>> ??????? >>>> I would like to comment on the simplicity of >>>> https://openjdk.org/jeps/8323335 for beginning students. >>>> ??????? >>>> >>>> ??????? >>>> I am the author of college texts for introductory >>>> programming. Like other authors, I introduce the Scanner class >>>> (and not Console) for reading user input. Given that students >>>> already know about System.out, it is simpler to call >>>> ??????? >>>> >>>> ??????? >>>> System.out.print("How old are you? "); >>>> ??????? >>>> int x = in.nextInt(); // in is a Scanner >>>> ??????? >>>> >>>> ??????? >>>> than >>>> ??????? >>>> >>>> ??????? >>>> int x = Integer.parseInt(console.readLine("How old >>>> are you? ")); >>>> ??????? >>>> >>>> ??????? >>>> or with the JEP draft: >>>> ??????? >>>> >>>> ??????? >>>> int x = Integer.parseInt(input("How old are you? ")); >>>> ??????? >>>> >>>> ??????? >>>> Then again, having a prompt string is nice too, so >>>> I could imagine using the Console API with Integer.parseInt and >>>> Double.parseDouble, instead of Scanner.nextInt/nextDouble. >>>> ??????? >>>> >>>> ??????? >>>> But why have a third API, i.e. "input"? >>>> ??????? >>>> >>>> ??????? >>>> I think there are two feasible directions. Either >>>> embrace the Scanner API and next/nextInt/nextDouble/nextLine, >>>> or the Console API and readLine. Adding "input" into the mix is >>>> just clutter, and ambiguous clutter at that. At least readLine >>>> makes it clear that the entire line is consumed. >>>> ??????? >>>> >>>> ??????? >>>> Cheers, >>>> ??????? >>>> >>>> ??????? >>>> Cay >>>> ??????? >>>> >>>> ??????? >>>> -- >>>> ??????? >>>> >>>> ??????? >>>> Cay S. Horstmann | >>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>>> | mailto:cay at horstmann.com >>>> ??????? >>> >>>> ??????? >> >>>> ??????? > >>>> >>>> ??????? -- >>>> ??????? -- >>>> >>>> ??????? Cay S. Horstmann | >>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$ >>>> >>>> >>>> | mailto:cay at horstmann.com >>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From anhmdq at gmail.com Tue Feb 20 15:21:44 2024 From: anhmdq at gmail.com (=?UTF-8?Q?Qu=C3=A2n_Anh_Mai?=) Date: Tue, 20 Feb 2024 22:21:44 +0700 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> Message-ID: There are some points that seem not right to me. > C starts with a simple and principled answer, which is that the IO primitive is getchar() and putchar(). For the purpose of learning, in C we do `scanf("%d", &n)` and in C++ we do `std::cin >> n`. I believe no one uses `getchar()` and `putchar()` to read integral or floating-point values. In fact, most beginner problem requires parsing of integral or floating-point inputs. The simplest problem that anyone starts learning to code will probably be adding 2 integers, when the learners have not even known what a `String` is. At that point, they simply do not have adequate knowledge to start understanding what `Integer::parseInt` does so it is just some magical characters that needs to be there. > Scanner was very well intentioned, and was not written by children, and yet none of us want to use it. Beginners use `Scanner` all the time, if you find `read an int java` on Google most of the results will use `Scanner`. And personally when learning to code I only did not use `Scanner` when doing competitive programming (due to its terrible performance). Cheers, Quan Anh On Tue, 20 Feb 2024 at 00:07, Brian Goetz wrote: > There's a reason there are so many opinions here: because the goals are in > conflict. Everyone wants simplicity, but people don't agree on what > "simple" means. (Cue the jokes about "I would simply not write programs > with bugs.") > > Yes, getting numbers from the user is a basic task. But it is not, in any > way, simple! Because reading numbers from the input is invariably > complected with discarding things that are "acceptably non-numbery" (e.g., > whitespace), which is neither simple nor usually terribly well documented. > We've all encountered the problem in many language runtimes where reading a > number using the "friendly way" leaves the input in a state that requires > fixing or yields surprises for the next operation. > > This is because reading a number from an input stream is not any sort of > primitive; it is the composite of reading from the input, deciding what to > skip, deciding when to stop reading, converting to another type, deciding > what state to leave the input stream in, and deciding what to do if no > number could be found (or if the number was too big to fit into an int, > etc.) This is not^3 simple! > > C starts with a simple and principled answer, which is that the IO > primitive is getchar() and putchar(). Reading or writing one character is > unquestionably a primitive. (But also, unless you are writing `cat`, no > one wants to program with getchar and putchar, because it's too > primitive.) > > One can make a reasonable case for "write a line / read a line" being > sensible primitives. They are simple enough: no parsing, no deciding what > to throw away, no possible errors other than EOF, it is clear what state > you leave the stream in. These may not be what the student wants, but they > are primitives a student can deal with without having to understand parsing > and error handling and statefulness yet. > > String s = getALine(); > printALine(s); > > is a program every student can reason about. > > But, it is true that dealing in strings, while honest and simple, is not > always what the student wants. But herein lies the strongest argument for > not trying to reinvent Scanner here: the ability to read numbers makes the > complexity of the problem, and hence of the API, much much bigger. > (Scanner was very well intentioned, and was not written by children, and > yet none of us want to use it. That's a sign that a one-size-fits-all > magic input processing system is harder than it looks, and for something > that is explicitly aimed at beginners, is a double warning sign.) > > I could imagine someone suggesting "why don't you just add > `readLineAsInt`". But what would happen next? Well, there would be a > million requests (including from folks like Cay) of "you should add X", and > then the result is a mishmash jumble of an API (that's already terrible), > but worse, it's an onramp that leads to nowhere. Once the user's needs are > slightly more complicated, they are nowhere. > > Remi has it absolutely right (yes, I really said that) with > > The classical program is: > input -> strings -> objects -> strings -> output > > > We do not do users a favor by blurring the distinction between "input -> > string" and "string -> object", and because the latter is so much more > open-ended than the former, the latter infects the former with its > complexity if we try. > > Is this simple API the most wonderful, be-all of APIs? Of course not. > But it is a sensible set of primitives that users can understand and *build > on* in a transparent way. > > Some teachers may immediately reach for teaching Integer::parseInt; that's > a reasonable strategy, it exposes students to the questions of "what > happens when preconditions fail", and the two compose just fine. But maybe > you don't like Integer::parseInt for some reason. Another way to teach > this is to have them write it themselves. This will expose them to all > sorts of interesting questions (what about whitespace? what about double > negatives?), but of course is also throwing in the deep end of the pool. > But SimpleIO::readMeALinePlease is agnostic; it works with both > approaches. > > Could the JDK use some better tools for parsing? Sure; pattern matching > has a role to play here, a `String::unformat` would be really cool, and I > love parser combinators. All of this can happen in the future, and none > have the effect of making this API look like yet another white elephant > like Scanner. Because it focused purely on the basics. > > > On 2/19/2024 7:25 AM, Remi Forax wrote: > > I agree with Brian here, > as a teacher, you have to talk about parsing and formatting, those should > not be hidden. > > The classical program is: > input -> strings -> objects -> strings -> output > > R?mi > > ------------------------------ > > *From: *"Tagir Valeev" > *To: *"Cay Horstmann" > *Cc: *"Brian Goetz" , > "amber-dev" > *Sent: *Monday, February 19, 2024 10:09:35 AM > *Subject: *Re: SimpleIO in JEP draft 8323335 > > I agree that simple methods to get numeric input are essential for > beginners. They should not be distracted with a complex ceremony. Instead, > they should be able to learn control flow statements and simple algorithms > as soon as possible, having a simple way to get numbers from the user. > With best regards, > Tagir Valeev. > > On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann wrote: > >> Yes, that's what I am saying. If scanners live in vain, stick with a >> subset of the Console methods. Use its readLine. Make it so that SimpleIO >> uses System.console(). And add print and println to Console. >> >> The JEP talks about being able to start programming without having to >> know about static methods. How does a beginner read a number? With >> Integer.parseInt(readLine(prompt))? >> >> What about locales? Is print/println localized? Console.printf is. If so, >> how are beginners from around the world supposed to read localized numbers? >> With NumberFormat.getInstance().parse(readLine(prompt))? >> >> Adding localized readInt/readDouble to SimpleIO might do the trick. Do >> they consume the trailing newline? (The equivalent Scanner methods don't, >> which is definitely a sharp edge for beginners.) >> >> On 18/02/2024 23.08, Brian Goetz wrote: >> > OK, so is this really just that that you are bikeshedding the name? >> Renaming `input` to `readLine`? >> > >> > This is a perfectly reasonable naming choice, of course, but also, not >> what you suggested the first time around: >> > >> > > ... "a third API" ... >> > >> > > ... "there are two feasible directions" ... >> > >> > So what exactly are you suggesting? >> > >> > >> > >> > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >> >> Like I said, either the scanner methods or the console methods are >> fine. >> >> >> >> I am of course aware of the utility/complexity of Scanner, and can >> understand the motivation to have a simpler/feebler behavior in SimpleIO. >> Like the one in Console. >> >> >> >> You don't have to "get a console". A SimpleIO.readLine method can just >> invoke readLine on the system console. >> >> >> >> My objection is to add yet another "input" method into the mix. >> "input" is weak. Does it read a token or the entire line? Does it consume >> the newline? And if it does just what readLine does, why another method >> name? Because "input" is three characters fewer? Let's not count characters. >> >> >> >> On 18/02/2024 22.43, Brian Goetz wrote: >> >>> I think you are counting characters and not counting concepts. >> >>> >> >>> Scanner has a ton of complexity in it that can easily trip up >> beginners. The main sin (though there are others) is that input and >> parsing are complected (e.g., nextInt), which only causes more problems >> (e.g., end of line issues.) Reading from the console is clearly a () -> >> String operation. The input() method does one thing, which is get a line >> of text. That's simple. >> >>> >> >>> Integer.parseInt (or, soon, patterns that match against string and >> bind an int) also does one thing: convert a string from int. It may seem >> verbose to have to do both explicitly, but it allows each of these >> operations to be simple, and it is perfectly obvious what is going on. On >> the other hand, Scanner is a world of complexity on its own. >> >>> >> >>> Console::readLine is nice, but first you have to get a Console. ("Why >> can I print something without having to get some magic helper object, but I >> can't do the same for reading?") What we're optimizing for here is >> conceptual simplicity; the simplest possible input method is the inverse of >> println. The fact that input has to be validated is a fact of life; we can >> treat validation separately from IO (and we should), and it gets simpler >> when you do. >> >>> >> >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >> >>>> I would like to comment on the simplicity of >> https://openjdk.org/jeps/8323335 for beginning students. >> >>>> >> >>>> I am the author of college texts for introductory programming. Like >> other authors, I introduce the Scanner class (and not Console) for reading >> user input. Given that students already know about System.out, it is >> simpler to call >> >>>> >> >>>> System.out.print("How old are you? "); >> >>>> int x = in.nextInt(); // in is a Scanner >> >>>> >> >>>> than >> >>>> >> >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >> >>>> >> >>>> or with the JEP draft: >> >>>> >> >>>> int x = Integer.parseInt(input("How old are you? ")); >> >>>> >> >>>> Then again, having a prompt string is nice too, so I could imagine >> using the Console API with Integer.parseInt and Double.parseDouble, instead >> of Scanner.nextInt/nextDouble. >> >>>> >> >>>> But why have a third API, i.e. "input"? >> >>>> >> >>>> I think there are two feasible directions. Either embrace the >> Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and >> readLine. Adding "input" into the mix is just clutter, and ambiguous >> clutter at that. At least readLine makes it clear that the entire line is >> consumed. >> >>>> >> >>>> Cheers, >> >>>> >> >>>> Cay >> >>>> >> >>>> -- >> >>>> >> >>>> Cay S. Horstmann | >> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >> | mailto:cay at horstmann.com >> >>> >> >> >> > >> >> -- >> >> -- >> >> Cay S. Horstmann | http://horstmann.com >> >> | mailto:cay at horstmann.com >> > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cay.horstmann at gmail.com Tue Feb 20 15:41:55 2024 From: cay.horstmann at gmail.com (Cay Horstmann) Date: Tue, 20 Feb 2024 16:41:55 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> Message-ID: <4c93ef42-7f1b-4377-9165-c4c1f4c91139@gmail.com> Actually, that's not quite what I am saying. What I am saying is: If you give something for beginning programmers (which is, according to the JEP, the purpose of SimpleIO), and it adds additional complexity to the programming model, then it better be compelling enough for beginners to use, and for teachers to adopt. Otherwise, it is better to give nothing at all. On 20/02/2024 15.34, Brian Goetz wrote: > What you're really saying is "I want more than you're giving me."? And there's nothing wrong with wanting more.? You seem to have mostly accepted that the primitive is "read a line of input as a string", but it leaves you with a problem: you don't want to read strings, you want to read numbers.? That's all fine. > > But the flip side of "this isn't good enough, give us more" is that if there isn't a "more" that is good enough to meet the the bar, you're going to get ... nothing.? It's a foundational design principle for Java (thanks James!) that if you don't know the right thing to do, then don't do anything (yet).? The alternatives that have been proposed (all of which we already went through before they came around again here) did not meet the bar.? This is what meets the bar.? It may not be as much as you want, but it is something, and it combines with all the other possible next steps. > > As a teacher, you have many choices.? You can keep doing what you've been doing, teaching Scanner; many teachers will.? Or you could distribute your own library of convenience methods -- many teachers do.? Or you could teach Integer::parseInt, which is messy, but has the benefit of being exactly as messy as the problem is -- which is also a useful lesson.? Or, or, or, or. > > And if you don't like the magic static import, don't use it!? Tell your students to use `SimpleIO::readAStringPlease`.? We are not trying to create a beginners dialect here. > > All of this is to say: we are not trying to put out a One True Only Way To Teach Java.? We're smoothing out the path in a way that admits many teaching paths, including ignoring all this stuff.? Is there more that could be done?? Of course.? And when we have a *good* candidate for what the next hundred feet of onramp looks like, we will proceed.? And I am confident that it will not conflict with these first hundred feet, because -- how could it? > > > > > > On 2/20/2024 6:44 AM, Cay Horstmann wrote: >> I am one of the people who writes books for beginners. I have a whole bunch of example programs that involve reading numbers. Professors adopting my books have a ton of exercises that involve reading numbers. I can't ignore reading numbers. >> >> I agree that input and println are reasonable primitives for beginners, and that number parsing can be done in a separate step. But if that parsing step is not simple for beginners, I don't think input will find much use for beginners either. >> >> For my books, I need to decide what to do in the (n + 1)st edition. Should I stick with >> >> Scanner in = new Scanner(System.in); >> ... >> System.out.print("How old are you? "); >> int age = in.nextInt(); >> >> or switch to >> >> println("How old are you?"); >> int age = in.nextInt(); >> >> or go all the way to >> >> int age = Integer.parseInt(input("How old are you")); >> >> I have no conceptual problem with in.nextInt(). I need to explain method calls early on, so that students can work with strings. >> >> With the new way, I have a different problem. Now I need to explain to students that they can call an unqualified input, but parseInt needs to be qualified. And I have to accelerate the coverage of static methods. >> >> As Brian says, there are too many conflicting goals. >> >> If the goal is simplicity and consistency, it would be more useful not to use a magic static import. If SimpleIO.input is too long, it could be IO.in, with IO in java.lang. >> >> If the goal is convenience, it would be better to have more magically statically imported methods, in particular parseInt, parseDouble. Or readAnInt, readADouble... >> >> Cheers, >> >> Cay >> >> >> On 19/02/2024 18.06, Brian Goetz wrote: >>> There's a reason there are so many opinions here: because the goals are in conflict.? Everyone wants simplicity, but people don't agree on what "simple" means.? (Cue the jokes about "I would simply not write programs with bugs.") >>> >>> Yes, getting numbers from the user is a basic task.? But it is not, in any way, simple!? Because reading numbers from the input is invariably complected with discarding things that are "acceptably non-numbery" (e.g., whitespace), which is neither simple nor usually terribly well documented.? We've all encountered the problem in many language runtimes where reading a number using the "friendly way" leaves the input in a state that requires fixing or yields surprises for the next operation. >>> >>> This is because reading a number from an input stream is not any sort of primitive; it is the composite of reading from the input, deciding what to skip, deciding when to stop reading, converting to another type, deciding what state to leave the input stream in, and deciding what to do if no number could be found (or if the number was too big to fit into an int, etc.) This is not^3 simple! >>> >>> C starts with a simple and principled answer, which is that the IO primitive is getchar() and putchar().? Reading or writing one character is unquestionably a primitive.? (But also, unless you are writing `cat`, no one wants to program with getchar and putchar, because it's too primitive.) >>> >>> One can make a reasonable case for "write a line / read a line" being sensible primitives.? They are simple enough: no parsing, no deciding what to throw away, no possible errors other than EOF, it is clear what state you leave the stream in.? These may not be what the student wants, but they are primitives a student can deal with without having to understand parsing and error handling and statefulness yet. >>> >>> ???? String s = getALine(); >>> ???? printALine(s); >>> >>> is a program every student can reason about. >>> >>> But, it is true that dealing in strings, while honest and simple, is not always what the student wants.? But herein lies the strongest argument for not trying to reinvent Scanner here: the ability to read numbers makes the complexity of the problem, and hence of the API, much much bigger.? (Scanner was very well intentioned, and was not written by children, and yet none of us want to use it.? That's a sign that a one-size-fits-all magic input processing system is harder than it looks, and for something that is explicitly aimed at beginners, is a double warning sign.) >>> >>> I could imagine someone suggesting "why don't you just add `readLineAsInt`".? But what would happen next?? Well, there would be a million requests (including from folks like Cay) of "you should add X", and then the result is a mishmash jumble of an API (that's already terrible), but worse, it's an onramp that leads to nowhere.? Once the user's needs are slightly more complicated, they are nowhere. >>> >>> Remi has it absolutely right (yes, I really said that) with >>> >>>> The classical program is: >>>> ?? input -> strings -> objects -> strings -> output >>> >>> We do not do users a favor by blurring the distinction between "input -> string" and "string -> object", and because the latter is so much more open-ended than the former, the latter infects the former with its complexity if we try. >>> >>> Is this simple API the most wonderful, be-all of APIs?? Of course not.? But it is a sensible set of primitives that users can understand and *build on* in a transparent way. >>> >>> Some teachers may immediately reach for teaching Integer::parseInt; that's a reasonable strategy, it exposes students to the questions of "what happens when preconditions fail", and the two compose just fine.? But maybe you don't like Integer::parseInt for some reason.? Another way to teach this is to have them write it themselves.? This will expose them to all sorts of interesting questions (what about whitespace? what about double negatives?), but of course is also throwing in the deep end of the pool.? But SimpleIO::readMeALinePlease is agnostic; it works with both approaches. >>> >>> Could the JDK use some better tools for parsing?? Sure; pattern matching has a role to play here, a `String::unformat` would be really cool, and I love parser combinators.? All of this can happen in the future, and none have the effect of making this API look like yet another white elephant like Scanner.? Because it focused purely on the basics. >>> >>> >>> On 2/19/2024 7:25 AM, Remi Forax wrote: >>>> I agree with Brian here, >>>> as a teacher, you have to talk about parsing and formatting, those should not be hidden. >>>> >>>> The classical program is: >>>> ?? input -> strings -> objects -> strings -> output >>>> >>>> R?mi >>>> >>>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >>>> >>>> ??? *From: *"Tagir Valeev" >>>> ??? *To: *"Cay Horstmann" >>>> ??? *Cc: *"Brian Goetz" , "amber-dev" >>>> ??? *Sent: *Monday, February 19, 2024 10:09:35 AM >>>> ??? *Subject: *Re: SimpleIO in JEP draft 8323335 >>>> >>>> ??? I agree that simple methods to get numeric input are essential for beginners. They should not be distracted with a complex ceremony. Instead, they should be able to learn control flow statements and simple algorithms as soon as possible, having a simple way to get numbers from the user. >>>> ??? With best?regards, >>>> ??? Tagir Valeev. >>>> >>>> ??? On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann wrote: >>>> >>>> ??????? Yes, that's what I am saying. If scanners live in vain, stick with a subset of the Console methods. Use its readLine. Make it so that SimpleIO uses System.console(). And add print and println to Console. >>>> >>>> ??????? The JEP talks about being able to start programming without having to know about static methods. How does a beginner read a number? With Integer.parseInt(readLine(prompt))? >>>> >>>> ??????? What about locales? Is print/println localized? Console.printf is. If so, how are beginners from around the world supposed to read localized numbers? With NumberFormat.getInstance().parse(readLine(prompt))? >>>> >>>> ??????? Adding localized readInt/readDouble to SimpleIO might do the trick. Do they consume the trailing newline? (The equivalent Scanner methods don't, which is definitely a sharp edge for beginners.) >>>> >>>> ??????? On 18/02/2024 23.08, Brian Goetz wrote: >>>> ??????? > OK, so is this really just that that you are bikeshedding the name?? Renaming `input` to `readLine`? >>>> ??????? > >>>> ??????? > This is a perfectly reasonable naming choice, of course, but also, not what you suggested the first time around: >>>> ??????? > >>>> ??????? >? > ... "a third API" ... >>>> ??????? > >>>> ??????? >? > ... "there are two feasible directions" ... >>>> ??????? > >>>> ??????? > So what exactly are you suggesting? >>>> ??????? > >>>> ??????? > >>>> ??????? > >>>> ??????? > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >>>> ??????? >> Like I said, either the scanner methods or the console methods are fine. >>>> ??????? >> >>>> ??????? >> I am of course aware of the utility/complexity of Scanner, and can understand the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in Console. >>>> ??????? >> >>>> ??????? >> You don't have to "get a console". A SimpleIO.readLine method can just invoke readLine on the system console. >>>> ??????? >> >>>> ??????? >> My objection is to add yet another "input" method into the mix. "input" is weak. Does it read a token or the entire line? Does it consume the newline? And if it does just what readLine does, why another method name? Because "input" is three characters fewer? Let's not count characters. >>>> ??????? >> >>>> ??????? >> On 18/02/2024 22.43, Brian Goetz wrote: >>>> ??????? >>> I think you are counting characters and not counting concepts. >>>> ??????? >>> >>>> ??????? >>> Scanner has a ton of complexity in it that can easily trip up beginners.? The main sin (though there are others) is that input and parsing are complected (e.g., nextInt), which only causes more problems (e.g., end of line issues.)?? Reading from the console is clearly a () -> String operation.? The input() method does one thing, which is get a line of text.? That's simple. >>>> ??????? >>> >>>> ??????? >>> Integer.parseInt (or, soon, patterns that match against string and bind an int) also does one thing: convert a string from int.? It may seem verbose to have to do both explicitly, but it allows each of these operations to be simple, and it is perfectly obvious what is going on. On the other hand, Scanner is a world of complexity on its own. >>>> ??????? >>> >>>> ??????? >>> Console::readLine is nice, but first you have to get a Console. ("Why can I print something without having to get some magic helper object, but I can't do the same for reading?")? What we're optimizing for here is conceptual simplicity; the simplest possible input method is the inverse of println.? The fact that input has to be validated is a fact of life; we can treat validation separately from IO (and we should), and it gets simpler when you do. >>>> ??????? >>> >>>> ??????? >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>>> ??????? >>>> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 for beginning students. >>>> ??????? >>>> >>>> ??????? >>>> I am the author of college texts for introductory programming. Like other authors, I introduce the Scanner class (and not Console) for reading user input. Given that students already know about System.out, it is simpler to call >>>> ??????? >>>> >>>> ??????? >>>> System.out.print("How old are you? "); >>>> ??????? >>>> int x = in.nextInt(); // in is a Scanner >>>> ??????? >>>> >>>> ??????? >>>> than >>>> ??????? >>>> >>>> ??????? >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >>>> ??????? >>>> >>>> ??????? >>>> or with the JEP draft: >>>> ??????? >>>> >>>> ??????? >>>> int x = Integer.parseInt(input("How old are you? ")); >>>> ??????? >>>> >>>> ??????? >>>> Then again, having a prompt string is nice too, so I could imagine using the Console API with Integer.parseInt and Double.parseDouble, instead of Scanner.nextInt/nextDouble. >>>> ??????? >>>> >>>> ??????? >>>> But why have a third API, i.e. "input"? >>>> ??????? >>>> >>>> ??????? >>>> I think there are two feasible directions. Either embrace the Scanner API and next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding "input" into the mix is just clutter, and ambiguous clutter at that. At least readLine makes it clear that the entire line is consumed. >>>> ??????? >>>> >>>> ??????? >>>> Cheers, >>>> ??????? >>>> >>>> ??????? >>>> Cay >>>> ??????? >>>> >>>> ??????? >>>> -- >>>> ??????? >>>> >>>> ??????? >>>> Cay S. Horstmann | https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ | mailto:cay at horstmann.com >>>> ??????? >>> >>>> ??????? >> >>>> ??????? > >>>> >>>> ??????? -- >>>> ??????? -- >>>> >>>> ??????? Cay S. Horstmann | https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$ | mailto:cay at horstmann.com >>>> >>>> >>> >> > -- -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From brian.goetz at oracle.com Tue Feb 20 15:46:06 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 20 Feb 2024 10:46:06 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <4c93ef42-7f1b-4377-9165-c4c1f4c91139@gmail.com> References: <07b25e28-2646-472c-8480-25a050051da7@gmail.com> <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <8cab88b3-fbda-474a-86fa-aadb1d3752fb@oracle.com> <4c93ef42-7f1b-4377-9165-c4c1f4c91139@gmail.com> Message-ID: <45276274-5e05-40da-83d7-bc24bf05c1f5@oracle.com> Your vote for "let's not do this at all" is hereby recorded! On 2/20/2024 10:41 AM, Cay Horstmann wrote: > Actually, that's not quite what I am saying. > > What I am saying is: If you give something for beginning programmers > (which is, according to the JEP, the purpose of SimpleIO), and it adds > additional complexity to the programming model, then it better be > compelling enough for beginners to use, and for teachers to adopt. > Otherwise, it is better to give nothing at all. > > On 20/02/2024 15.34, Brian Goetz wrote: >> What you're really saying is "I want more than you're giving me."? >> And there's nothing wrong with wanting more.? You seem to have mostly >> accepted that the primitive is "read a line of input as a string", >> but it leaves you with a problem: you don't want to read strings, you >> want to read numbers.? That's all fine. >> >> But the flip side of "this isn't good enough, give us more" is that >> if there isn't a "more" that is good enough to meet the the bar, >> you're going to get ... nothing.? It's a foundational design >> principle for Java (thanks James!) that if you don't know the right >> thing to do, then don't do anything (yet).? The alternatives that >> have been proposed (all of which we already went through before they >> came around again here) did not meet the bar.? This is what meets the >> bar.? It may not be as much as you want, but it is something, and it >> combines with all the other possible next steps. >> >> As a teacher, you have many choices.? You can keep doing what you've >> been doing, teaching Scanner; many teachers will.? Or you could >> distribute your own library of convenience methods -- many teachers >> do.? Or you could teach Integer::parseInt, which is messy, but has >> the benefit of being exactly as messy as the problem is -- which is >> also a useful lesson.? Or, or, or, or. >> >> And if you don't like the magic static import, don't use it! Tell >> your students to use `SimpleIO::readAStringPlease`.? We are not >> trying to create a beginners dialect here. >> >> All of this is to say: we are not trying to put out a One True Only >> Way To Teach Java.? We're smoothing out the path in a way that admits >> many teaching paths, including ignoring all this stuff.? Is there >> more that could be done?? Of course.? And when we have a *good* >> candidate for what the next hundred feet of onramp looks like, we >> will proceed.? And I am confident that it will not conflict with >> these first hundred feet, because -- how could it? >> >> >> >> >> >> On 2/20/2024 6:44 AM, Cay Horstmann wrote: >>> I am one of the people who writes books for beginners. I have a >>> whole bunch of example programs that involve reading numbers. >>> Professors adopting my books have a ton of exercises that involve >>> reading numbers. I can't ignore reading numbers. >>> >>> I agree that input and println are reasonable primitives for >>> beginners, and that number parsing can be done in a separate step. >>> But if that parsing step is not simple for beginners, I don't think >>> input will find much use for beginners either. >>> >>> For my books, I need to decide what to do in the (n + 1)st edition. >>> Should I stick with >>> >>> Scanner in = new Scanner(System.in); >>> ... >>> System.out.print("How old are you? "); >>> int age = in.nextInt(); >>> >>> or switch to >>> >>> println("How old are you?"); >>> int age = in.nextInt(); >>> >>> or go all the way to >>> >>> int age = Integer.parseInt(input("How old are you")); >>> >>> I have no conceptual problem with in.nextInt(). I need to explain >>> method calls early on, so that students can work with strings. >>> >>> With the new way, I have a different problem. Now I need to explain >>> to students that they can call an unqualified input, but parseInt >>> needs to be qualified. And I have to accelerate the coverage of >>> static methods. >>> >>> As Brian says, there are too many conflicting goals. >>> >>> If the goal is simplicity and consistency, it would be more useful >>> not to use a magic static import. If SimpleIO.input is too long, it >>> could be IO.in, with IO in java.lang. >>> >>> If the goal is convenience, it would be better to have more >>> magically statically imported methods, in particular parseInt, >>> parseDouble. Or readAnInt, readADouble... >>> >>> Cheers, >>> >>> Cay >>> >>> >>> On 19/02/2024 18.06, Brian Goetz wrote: >>>> There's a reason there are so many opinions here: because the goals >>>> are in conflict.? Everyone wants simplicity, but people don't agree >>>> on what "simple" means.? (Cue the jokes about "I would simply not >>>> write programs with bugs.") >>>> >>>> Yes, getting numbers from the user is a basic task.? But it is not, >>>> in any way, simple!? Because reading numbers from the input is >>>> invariably complected with discarding things that are "acceptably >>>> non-numbery" (e.g., whitespace), which is neither simple nor >>>> usually terribly well documented. We've all encountered the problem >>>> in many language runtimes where reading a number using the >>>> "friendly way" leaves the input in a state that requires fixing or >>>> yields surprises for the next operation. >>>> >>>> This is because reading a number from an input stream is not any >>>> sort of primitive; it is the composite of reading from the input, >>>> deciding what to skip, deciding when to stop reading, converting to >>>> another type, deciding what state to leave the input stream in, and >>>> deciding what to do if no number could be found (or if the number >>>> was too big to fit into an int, etc.) This is not^3 simple! >>>> >>>> C starts with a simple and principled answer, which is that the IO >>>> primitive is getchar() and putchar().? Reading or writing one >>>> character is unquestionably a primitive.? (But also, unless you are >>>> writing `cat`, no one wants to program with getchar and putchar, >>>> because it's too primitive.) >>>> >>>> One can make a reasonable case for "write a line / read a line" >>>> being sensible primitives.? They are simple enough: no parsing, no >>>> deciding what to throw away, no possible errors other than EOF, it >>>> is clear what state you leave the stream in.? These may not be what >>>> the student wants, but they are primitives a student can deal with >>>> without having to understand parsing and error handling and >>>> statefulness yet. >>>> >>>> ???? String s = getALine(); >>>> ???? printALine(s); >>>> >>>> is a program every student can reason about. >>>> >>>> But, it is true that dealing in strings, while honest and simple, >>>> is not always what the student wants.? But herein lies the >>>> strongest argument for not trying to reinvent Scanner here: the >>>> ability to read numbers makes the complexity of the problem, and >>>> hence of the API, much much bigger.? (Scanner was very well >>>> intentioned, and was not written by children, and yet none of us >>>> want to use it. That's a sign that a one-size-fits-all magic input >>>> processing system is harder than it looks, and for something that >>>> is explicitly aimed at beginners, is a double warning sign.) >>>> >>>> I could imagine someone suggesting "why don't you just add >>>> `readLineAsInt`".? But what would happen next?? Well, there would >>>> be a million requests (including from folks like Cay) of "you >>>> should add X", and then the result is a mishmash jumble of an API >>>> (that's already terrible), but worse, it's an onramp that leads to >>>> nowhere.? Once the user's needs are slightly more complicated, they >>>> are nowhere. >>>> >>>> Remi has it absolutely right (yes, I really said that) with >>>> >>>>> The classical program is: >>>>> ?? input -> strings -> objects -> strings -> output >>>> >>>> We do not do users a favor by blurring the distinction between >>>> "input -> string" and "string -> object", and because the latter is >>>> so much more open-ended than the former, the latter infects the >>>> former with its complexity if we try. >>>> >>>> Is this simple API the most wonderful, be-all of APIs?? Of course >>>> not.? But it is a sensible set of primitives that users can >>>> understand and *build on* in a transparent way. >>>> >>>> Some teachers may immediately reach for teaching Integer::parseInt; >>>> that's a reasonable strategy, it exposes students to the questions >>>> of "what happens when preconditions fail", and the two compose just >>>> fine.? But maybe you don't like Integer::parseInt for some reason. >>>> Another way to teach this is to have them write it themselves.? >>>> This will expose them to all sorts of interesting questions (what >>>> about whitespace? what about double negatives?), but of course is >>>> also throwing in the deep end of the pool.? But >>>> SimpleIO::readMeALinePlease is agnostic; it works with both >>>> approaches. >>>> >>>> Could the JDK use some better tools for parsing?? Sure; pattern >>>> matching has a role to play here, a `String::unformat` would be >>>> really cool, and I love parser combinators.? All of this can happen >>>> in the future, and none have the effect of making this API look >>>> like yet another white elephant like Scanner.? Because it focused >>>> purely on the basics. >>>> >>>> >>>> On 2/19/2024 7:25 AM, Remi Forax wrote: >>>>> I agree with Brian here, >>>>> as a teacher, you have to talk about parsing and formatting, those >>>>> should not be hidden. >>>>> >>>>> The classical program is: >>>>> ?? input -> strings -> objects -> strings -> output >>>>> >>>>> R?mi >>>>> >>>>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >>>>> >>>>> >>>>> ??? *From: *"Tagir Valeev" >>>>> ??? *To: *"Cay Horstmann" >>>>> ??? *Cc: *"Brian Goetz" , "amber-dev" >>>>> >>>>> ??? *Sent: *Monday, February 19, 2024 10:09:35 AM >>>>> ??? *Subject: *Re: SimpleIO in JEP draft 8323335 >>>>> >>>>> ??? I agree that simple methods to get numeric input are essential >>>>> for beginners. They should not be distracted with a complex >>>>> ceremony. Instead, they should be able to learn control flow >>>>> statements and simple algorithms as soon as possible, having a >>>>> simple way to get numbers from the user. >>>>> ??? With best?regards, >>>>> ??? Tagir Valeev. >>>>> >>>>> ??? On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann >>>>> wrote: >>>>> >>>>> ??????? Yes, that's what I am saying. If scanners live in vain, >>>>> stick with a subset of the Console methods. Use its readLine. Make >>>>> it so that SimpleIO uses System.console(). And add print and >>>>> println to Console. >>>>> >>>>> ??????? The JEP talks about being able to start programming >>>>> without having to know about static methods. How does a beginner >>>>> read a number? With Integer.parseInt(readLine(prompt))? >>>>> >>>>> ??????? What about locales? Is print/println localized? >>>>> Console.printf is. If so, how are beginners from around the world >>>>> supposed to read localized numbers? With >>>>> NumberFormat.getInstance().parse(readLine(prompt))? >>>>> >>>>> ??????? Adding localized readInt/readDouble to SimpleIO might do >>>>> the trick. Do they consume the trailing newline? (The equivalent >>>>> Scanner methods don't, which is definitely a sharp edge for >>>>> beginners.) >>>>> >>>>> ??????? On 18/02/2024 23.08, Brian Goetz wrote: >>>>> ??????? > OK, so is this really just that that you are >>>>> bikeshedding the name?? Renaming `input` to `readLine`? >>>>> ??????? > >>>>> ??????? > This is a perfectly reasonable naming choice, of course, >>>>> but also, not what you suggested the first time around: >>>>> ??????? > >>>>> ??????? >? > ... "a third API" ... >>>>> ??????? > >>>>> ??????? >? > ... "there are two feasible directions" ... >>>>> ??????? > >>>>> ??????? > So what exactly are you suggesting? >>>>> ??????? > >>>>> ??????? > >>>>> ??????? > >>>>> ??????? > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >>>>> ??????? >> Like I said, either the scanner methods or the console >>>>> methods are fine. >>>>> ??????? >> >>>>> ??????? >> I am of course aware of the utility/complexity of >>>>> Scanner, and can understand the motivation to have a >>>>> simpler/feebler behavior in SimpleIO. Like the one in Console. >>>>> ??????? >> >>>>> ??????? >> You don't have to "get a console". A SimpleIO.readLine >>>>> method can just invoke readLine on the system console. >>>>> ??????? >> >>>>> ??????? >> My objection is to add yet another "input" method into >>>>> the mix. "input" is weak. Does it read a token or the entire line? >>>>> Does it consume the newline? And if it does just what readLine >>>>> does, why another method name? Because "input" is three characters >>>>> fewer? Let's not count characters. >>>>> ??????? >> >>>>> ??????? >> On 18/02/2024 22.43, Brian Goetz wrote: >>>>> ??????? >>> I think you are counting characters and not counting >>>>> concepts. >>>>> ??????? >>> >>>>> ??????? >>> Scanner has a ton of complexity in it that can easily >>>>> trip up beginners.? The main sin (though there are others) is that >>>>> input and parsing are complected (e.g., nextInt), which only >>>>> causes more problems (e.g., end of line issues.)?? Reading from >>>>> the console is clearly a () -> String operation.? The input() >>>>> method does one thing, which is get a line of text.? That's simple. >>>>> ??????? >>> >>>>> ??????? >>> Integer.parseInt (or, soon, patterns that match >>>>> against string and bind an int) also does one thing: convert a >>>>> string from int.? It may seem verbose to have to do both >>>>> explicitly, but it allows each of these operations to be simple, >>>>> and it is perfectly obvious what is going on. On the other hand, >>>>> Scanner is a world of complexity on its own. >>>>> ??????? >>> >>>>> ??????? >>> Console::readLine is nice, but first you have to get a >>>>> Console. ("Why can I print something without having to get some >>>>> magic helper object, but I can't do the same for reading?")? What >>>>> we're optimizing for here is conceptual simplicity; the simplest >>>>> possible input method is the inverse of println.? The fact that >>>>> input has to be validated is a fact of life; we can treat >>>>> validation separately from IO (and we should), and it gets simpler >>>>> when you do. >>>>> ??????? >>> >>>>> ??????? >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>>>> ??????? >>>> I would like to comment on the simplicity of >>>>> https://openjdk.org/jeps/8323335 for beginning students. >>>>> ??????? >>>> >>>>> ??????? >>>> I am the author of college texts for introductory >>>>> programming. Like other authors, I introduce the Scanner class >>>>> (and not Console) for reading user input. Given that students >>>>> already know about System.out, it is simpler to call >>>>> ??????? >>>> >>>>> ??????? >>>> System.out.print("How old are you? "); >>>>> ??????? >>>> int x = in.nextInt(); // in is a Scanner >>>>> ??????? >>>> >>>>> ??????? >>>> than >>>>> ??????? >>>> >>>>> ??????? >>>> int x = Integer.parseInt(console.readLine("How old >>>>> are you? ")); >>>>> ??????? >>>> >>>>> ??????? >>>> or with the JEP draft: >>>>> ??????? >>>> >>>>> ??????? >>>> int x = Integer.parseInt(input("How old are you? ")); >>>>> ??????? >>>> >>>>> ??????? >>>> Then again, having a prompt string is nice too, so I >>>>> could imagine using the Console API with Integer.parseInt and >>>>> Double.parseDouble, instead of Scanner.nextInt/nextDouble. >>>>> ??????? >>>> >>>>> ??????? >>>> But why have a third API, i.e. "input"? >>>>> ??????? >>>> >>>>> ??????? >>>> I think there are two feasible directions. Either >>>>> embrace the Scanner API and next/nextInt/nextDouble/nextLine, or >>>>> the Console API and readLine. Adding "input" into the mix is just >>>>> clutter, and ambiguous clutter at that. At least readLine makes it >>>>> clear that the entire line is consumed. >>>>> ??????? >>>> >>>>> ??????? >>>> Cheers, >>>>> ??????? >>>> >>>>> ??????? >>>> Cay >>>>> ??????? >>>> >>>>> ??????? >>>> -- >>>>> ??????? >>>> >>>>> ??????? >>>> Cay S. Horstmann | >>>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>>>> | mailto:cay at horstmann.com >>>>> ??????? >>> >>>>> ??????? >> >>>>> ??????? > >>>>> >>>>> ??????? -- >>>>> ??????? -- >>>>> >>>>> ??????? Cay S. Horstmann | >>>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$ >>>>> >>>>> | mailto:cay at horstmann.com >>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eirbjo at gmail.com Tue Feb 20 17:39:53 2024 From: eirbjo at gmail.com (=?UTF-8?B?RWlyaWsgQmrDuHJzbsO4cw==?=) Date: Tue, 20 Feb 2024 18:39:53 +0100 Subject: Simple is as simple does (JEP draft 8323335) Message-ID: Hi, I acknowledge the following is easy to dismiss as just bikeshedding, but please hang with me: Is labeling something as "simple" an effective naming practice, especially in a pedagogical context like we are faced with in this JEP? simple: adjective > 1. easily understood or done; presenting no difficulty. > "a simple solution" First, let me be bold and claim that nothing in programming is "easily understood or done; presenting no difficulty". Anyone claiming so has clearly lost empathy with the beginning learner! ;-) Second, the lable "simple" suggest something about the things not fitting into the "simple" bucket. If not simple, what are those things? Difficult? Third, "easily understood" very much depends on who is trying to understand. It may change over time as the learner gains understanding and experience. Simple to Alice might not be simple to Bob. ... As any complainer, I'm also too lazy to do the work to find a better alternative. But perhaps "basic" could be a starting point: basic: adjective > 1. forming an essential foundation or starting point; fundamental. This seems more stable to time, context and experience. Something fundamental can be trusted to stay fundamental for a while. Thanks (any sorry!), Eirik. -------------- next part -------------- An HTML attachment was scrubbed... URL: From eirbjo at gmail.com Tue Feb 20 17:51:56 2024 From: eirbjo at gmail.com (=?UTF-8?B?RWlyaWsgQmrDuHJzbsO4cw==?=) Date: Tue, 20 Feb 2024 18:51:56 +0100 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: References: Message-ID: On Tue, Feb 20, 2024 at 6:39?PM Eirik Bj?rsn?s wrote: > Is labeling something as "simple" an effective naming practice, especially > in a pedagogical context like we are faced with in this JEP? > Just to clarify: I was specifically thinking about "java.io.SimpleIO" here, not the general use of the word "simple" in the JEP. Since the static methods of this class are implicitly imported, the target user will initially probably not see or care much about the name. But someone will. Cheers, Eirik. -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Tue Feb 20 17:59:28 2024 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 20 Feb 2024 18:59:28 +0100 (CET) Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> Message-ID: <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> Hello Cay, ----- Original Message ----- > From: "Cay Horstmann" > To: "Brian Goetz" , "Remi Forax" , "Tagir Valeev" > Cc: "amber-dev" > Sent: Tuesday, February 20, 2024 12:44:53 PM > Subject: Re: SimpleIO in JEP draft 8323335 > I am one of the people who writes books for beginners. I have a whole bunch of > example programs that involve reading numbers. Professors adopting my books > have a ton of exercises that involve reading numbers. I can't ignore reading > numbers. > > I agree that input and println are reasonable primitives for beginners, and that > number parsing can be done in a separate step. But if that parsing step is not > simple for beginners, I don't think input will find much use for beginners > either. > > For my books, I need to decide what to do in the (n + 1)st edition. Should I > stick with > > Scanner in = new Scanner(System.in); > ... > System.out.print("How old are you? "); > int age = in.nextInt(); > > or switch to > > println("How old are you?"); > int age = in.nextInt(); > > or go all the way to > > int age = Integer.parseInt(input("How old are you")); Showing my age, you can also a version with a StringTokenizer :) > > I have no conceptual problem with in.nextInt(). I need to explain method calls > early on, so that students can work with strings. Scanner requires quite a lot concepts, you need to explain "import" (it's in java.util), "new" and instance method calls. > > With the new way, I have a different problem. Now I need to explain to students > that they can call an unqualified input, but parseInt needs to be qualified. > And I have to accelerate the coverage of static methods. Using a static method is quite different than declaring a static method. To use a static method, you just need to explain that functions in Java belong to a name, it's not sin() but Math.sin(), it's not parseInt() but Integer.parseInt(). > > As Brian says, there are too many conflicting goals. > > If the goal is simplicity and consistency, it would be more useful not to use a > magic static import. If SimpleIO.input is too long, it could be IO.in, with IO > in java.lang. You can have both. You can start by using println() and readln() and works with functions. Then explain that in fact, println() is SimpleIO.println() when you introduce Math.sin() and Integer.parseInt(). Exactly like later, when you explain import, you explain that String is in fact java.lang.String. > > If the goal is convenience, it would be better to have more magically statically > imported methods, in particular parseInt, parseDouble. Or readAnInt, > readADouble... It looks like a false dichotomy to me. > > Cheers, > > Cay R?mi > > > On 19/02/2024 18.06, Brian Goetz wrote: >> There's a reason there are so many opinions here: because the goals are in >> conflict.? Everyone wants simplicity, but people don't agree on what "simple" >> means.? (Cue the jokes about "I would simply not write programs with bugs.") >> >> Yes, getting numbers from the user is a basic task.? But it is not, in any way, >> simple!? Because reading numbers from the input is invariably complected with >> discarding things that are "acceptably non-numbery" (e.g., whitespace), which >> is neither simple nor usually terribly well documented.? We've all encountered >> the problem in many language runtimes where reading a number using the >> "friendly way" leaves the input in a state that requires fixing or yields >> surprises for the next operation. >> >> This is because reading a number from an input stream is not any sort of >> primitive; it is the composite of reading from the input, deciding what to >> skip, deciding when to stop reading, converting to another type, deciding what >> state to leave the input stream in, and deciding what to do if no number could >> be found (or if the number was too big to fit into an int, etc.)? This is not^3 >> simple! >> >> C starts with a simple and principled answer, which is that the IO primitive is >> getchar() and putchar().? Reading or writing one character is unquestionably a >> primitive.? (But also, unless you are writing `cat`, no one wants to program >> with getchar and putchar, because it's too primitive.) >> >> One can make a reasonable case for "write a line / read a line" being sensible >> primitives.? They are simple enough: no parsing, no deciding what to throw >> away, no possible errors other than EOF, it is clear what state you leave the >> stream in.? These may not be what the student wants, but they are primitives a >> student can deal with without having to understand parsing and error handling >> and statefulness yet. >> >> ??? String s = getALine(); >> ??? printALine(s); >> >> is a program every student can reason about. >> >> But, it is true that dealing in strings, while honest and simple, is not always >> what the student wants.? But herein lies the strongest argument for not trying >> to reinvent Scanner here: the ability to read numbers makes the complexity of >> the problem, and hence of the API, much much bigger.? (Scanner was very well >> intentioned, and was not written by children, and yet none of us want to use >> it.? That's a sign that a one-size-fits-all magic input processing system is >> harder than it looks, and for something that is explicitly aimed at beginners, >> is a double warning sign.) >> >> I could imagine someone suggesting "why don't you just add `readLineAsInt`". >> ? But what would happen next?? Well, there would be a million requests >> (including from folks like Cay) of "you should add X", and then the result is a >> mishmash jumble of an API (that's already terrible), but worse, it's an onramp >> that leads to nowhere.? Once the user's needs are slightly more complicated, >> they are nowhere. >> >> Remi has it absolutely right (yes, I really said that) with >> >>> The classical program is: >>> ?? input -> strings -> objects -> strings -> output >> >> We do not do users a favor by blurring the distinction between "input -> string" >> and "string -> object", and because the latter is so much more open-ended than >> the former, the latter infects the former with its complexity if we try. >> >> Is this simple API the most wonderful, be-all of APIs?? Of course not.? But it >> is a sensible set of primitives that users can understand and *build on* in a >> transparent way. >> >> Some teachers may immediately reach for teaching Integer::parseInt; that's a >> reasonable strategy, it exposes students to the questions of "what happens when >> preconditions fail", and the two compose just fine.? But maybe you don't like >> Integer::parseInt for some reason.? Another way to teach this is to have them >> write it themselves.? This will expose them to all sorts of interesting >> questions (what about whitespace? what about double negatives?), but of course >> is also throwing in the deep end of the pool.? But SimpleIO::readMeALinePlease >> is agnostic; it works with both approaches. >> >> Could the JDK use some better tools for parsing?? Sure; pattern matching has a >> role to play here, a `String::unformat` would be really cool, and I love parser >> combinators.? All of this can happen in the future, and none have the effect of >> making this API look like yet another white elephant like Scanner.? Because it >> focused purely on the basics. >> >> >> On 2/19/2024 7:25 AM, Remi Forax wrote: >>> I agree with Brian here, >>> as a teacher, you have to talk about parsing and formatting, those should not be >>> hidden. >>> >>> The classical program is: >>> ?? input -> strings -> objects -> strings -> output >>> >>> R?mi >>> >>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >>> >>> *From: *"Tagir Valeev" >>> *To: *"Cay Horstmann" >>> *Cc: *"Brian Goetz" , "amber-dev" >>> >>> *Sent: *Monday, February 19, 2024 10:09:35 AM >>> *Subject: *Re: SimpleIO in JEP draft 8323335 >>> >>> I agree that simple methods to get numeric input are essential for beginners. >>> They should not be distracted with a complex ceremony. Instead, they should be >>> able to learn control flow statements and simple algorithms as soon as >>> possible, having a simple way to get numbers from the user. >>> With best?regards, >>> Tagir Valeev. >>> >>> On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann wrote: >>> >>> Yes, that's what I am saying. If scanners live in vain, stick with a subset of >>> the Console methods. Use its readLine. Make it so that SimpleIO uses >>> System.console(). And add print and println to Console. >>> >>> The JEP talks about being able to start programming without having to know about >>> static methods. How does a beginner read a number? With >>> Integer.parseInt(readLine(prompt))? >>> >>> What about locales? Is print/println localized? Console.printf is. If so, how >>> are beginners from around the world supposed to read localized numbers? With >>> NumberFormat.getInstance().parse(readLine(prompt))? >>> >>> Adding localized readInt/readDouble to SimpleIO might do the trick. Do they >>> consume the trailing newline? (The equivalent Scanner methods don't, which is >>> definitely a sharp edge for beginners.) >>> >>> On 18/02/2024 23.08, Brian Goetz wrote: >>> > OK, so is this really just that that you are bikeshedding the name?? Renaming >>> > `input` to `readLine`? >>> > >>> > This is a perfectly reasonable naming choice, of course, but also, not what you >>> > suggested the first time around: >>> > >>> >? > ... "a third API" ... >>> > >>> >? > ... "there are two feasible directions" ... >>> > >>> > So what exactly are you suggesting? >>> > >>> > >>> > >>> > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >>> >> Like I said, either the scanner methods or the console methods are fine. >>> >> >>> >> I am of course aware of the utility/complexity of Scanner, and can understand >>> >> the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in >>> >> Console. >>> >> >>> >> You don't have to "get a console". A SimpleIO.readLine method can just invoke >>> >> readLine on the system console. >>> >> >>> >> My objection is to add yet another "input" method into the mix. "input" is weak. >>> >> Does it read a token or the entire line? Does it consume the newline? And if it >>> >> does just what readLine does, why another method name? Because "input" is three >>> >> characters fewer? Let's not count characters. >>> >> >>> >> On 18/02/2024 22.43, Brian Goetz wrote: >>> >>> I think you are counting characters and not counting concepts. >>> >>> >>> >>> Scanner has a ton of complexity in it that can easily trip up beginners.? The >>> >>> main sin (though there are others) is that input and parsing are complected >>> >>> (e.g., nextInt), which only causes more problems (e.g., end of line issues.) >>> >>> ?? Reading from the console is clearly a () -> String operation.? The input() >>> >>> method does one thing, which is get a line of text.? That's simple. >>> >>> >>> >>> Integer.parseInt (or, soon, patterns that match against string and bind an int) >>> >>> also does one thing: convert a string from int.? It may seem verbose to have to >>> >>> do both explicitly, but it allows each of these operations to be simple, and it >>> >>> is perfectly obvious what is going on. On the other hand, Scanner is a world of >>> >>> complexity on its own. >>> >>> >>> >>> Console::readLine is nice, but first you have to get a Console. ("Why can I >>> >>> print something without having to get some magic helper object, but I can't do >>> >>> the same for reading?")? What we're optimizing for here is conceptual >>> >>> simplicity; the simplest possible input method is the inverse of println.? The >>> >>> fact that input has to be validated is a fact of life; we can treat validation >>> >>> separately from IO (and we should), and it gets simpler when you do. >>> >>> >>> >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>> >>>> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 >>> >>>> for beginning students. >>> >>>> >>> >>>> I am the author of college texts for introductory programming. Like other >>> >>>> authors, I introduce the Scanner class (and not Console) for reading user >>> >>>> input. Given that students already know about System.out, it is simpler to call >>> >>>> >>> >>>> System.out.print("How old are you? "); >>> >>>> int x = in.nextInt(); // in is a Scanner >>> >>>> >>> >>>> than >>> >>>> >>> >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >>> >>>> >>> >>>> or with the JEP draft: >>> >>>> >>> >>>> int x = Integer.parseInt(input("How old are you? ")); >>> >>>> >>> >>>> Then again, having a prompt string is nice too, so I could imagine using the >>> >>>> Console API with Integer.parseInt and Double.parseDouble, instead of >>> >>>> Scanner.nextInt/nextDouble. >>> >>>> >>> >>>> But why have a third API, i.e. "input"? >>> >>>> >>> >>>> I think there are two feasible directions. Either embrace the Scanner API and >>> >>>> next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding >>> >>>> "input" into the mix is just clutter, and ambiguous clutter at that. At least >>> >>>> readLine makes it clear that the entire line is consumed. >>> >>>> >>> >>>> Cheers, >>> >>>> >>> >>>> Cay >>> >>>> >>> >>>> -- >>> >>>> >>> >>>> Cay S. Horstmann | >>> >>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>> >>>> | mailto:cay at horstmann.com >>> >>> >>> >> >>> > >>> >>> -- >>> >>> -- >>> >>> Cay S. Horstmann | http://horstmann.com >>> >>> | mailto:cay at horstmann.com >>> >>> >> > > -- > > -- > > Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From cay at horstmann.com Tue Feb 20 19:31:47 2024 From: cay at horstmann.com (Cay Horstmann) Date: Tue, 20 Feb 2024 20:31:47 +0100 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> References: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Hi R?mi, I am not bothered by the concepts that Scanner needs, because for me they are reasonable investments. As you point out, they are: * instance methods * new * import I would switch to a different approach if it (a) didn't introduce yet another fiddly special case (magic static import) and (b) wasn't unreasonably verbose. I would find this too painful: import java.util.SimpleIO; int age = Integer.parseInt(SimpleIO.input("How old are you? ")); I could embrace the magic static import if it was sufficiently general and useful to pay for the complexity. Hence my suggestion int age = parseInt(input("How old are you? ")); Or int age = readInt("How old are you? "); I need to make these decisions for the books and activities that I produce. As it is in the JEP today, I'd stick with Scanner. I would put in a note, just to signal that I know what is happening, that as of Java 25 (?), you can also use input, but that it relies on another fiddly rule, and it doesn't transfer to file I/O, so why bother... My sentiment is just a data point. I understand that the cost/benefit model is different for everyone. Cheers, Cay PS. I'd like to register a forceful pushback on "parsing numbers is so crazily complex that we can't possibly deal with it". What does print/println produce for numbers? Is it the crazily complex localized number format? No--only printf applies localization. The print/println methods format numbers as Java literals. That's a settled issue. It's been like that since Java 1.0. Not crazily complex. A readInt/readDouble (or whatever it is called) in SimpleIO can surely be the canonical inverse of print/println. On 20/02/2024 18.59, forax at univ-mlv.fr wrote: > Hello Cay, > > ----- Original Message ----- >> From: "Cay Horstmann" >> To: "Brian Goetz" , "Remi Forax" , "Tagir Valeev" >> Cc: "amber-dev" >> Sent: Tuesday, February 20, 2024 12:44:53 PM >> Subject: Re: SimpleIO in JEP draft 8323335 > >> I am one of the people who writes books for beginners. I have a whole bunch of >> example programs that involve reading numbers. Professors adopting my books >> have a ton of exercises that involve reading numbers. I can't ignore reading >> numbers. >> >> I agree that input and println are reasonable primitives for beginners, and that >> number parsing can be done in a separate step. But if that parsing step is not >> simple for beginners, I don't think input will find much use for beginners >> either. >> >> For my books, I need to decide what to do in the (n + 1)st edition. Should I >> stick with >> >> Scanner in = new Scanner(System.in); >> ... >> System.out.print("How old are you? "); >> int age = in.nextInt(); >> >> or switch to >> >> println("How old are you?"); >> int age = in.nextInt(); >> >> or go all the way to >> >> int age = Integer.parseInt(input("How old are you")); > > > Showing my age, you can also a version with a StringTokenizer :) > > >> >> I have no conceptual problem with in.nextInt(). I need to explain method calls >> early on, so that students can work with strings. > > Scanner requires quite a lot concepts, you need to explain "import" (it's in java.util), "new" and instance method calls. > >> >> With the new way, I have a different problem. Now I need to explain to students >> that they can call an unqualified input, but parseInt needs to be qualified. >> And I have to accelerate the coverage of static methods. > > Using a static method is quite different than declaring a static method. > > To use a static method, you just need to explain that functions in Java belong to a name, > it's not sin() but Math.sin(), it's not parseInt() but Integer.parseInt(). > >> >> As Brian says, there are too many conflicting goals. >> >> If the goal is simplicity and consistency, it would be more useful not to use a >> magic static import. If SimpleIO.input is too long, it could be IO.in, with IO >> in java.lang. > > You can have both. You can start by using println() and readln() and works with functions. > Then explain that in fact, println() is SimpleIO.println() when you introduce Math.sin() and Integer.parseInt(). > > Exactly like later, when you explain import, you explain that String is in fact java.lang.String. > >> >> If the goal is convenience, it would be better to have more magically statically >> imported methods, in particular parseInt, parseDouble. Or readAnInt, >> readADouble... > > It looks like a false dichotomy to me. > >> >> Cheers, >> >> Cay > > R?mi > >> >> >> On 19/02/2024 18.06, Brian Goetz wrote: >>> There's a reason there are so many opinions here: because the goals are in >>> conflict.? Everyone wants simplicity, but people don't agree on what "simple" >>> means.? (Cue the jokes about "I would simply not write programs with bugs.") >>> >>> Yes, getting numbers from the user is a basic task.? But it is not, in any way, >>> simple!? Because reading numbers from the input is invariably complected with >>> discarding things that are "acceptably non-numbery" (e.g., whitespace), which >>> is neither simple nor usually terribly well documented.? We've all encountered >>> the problem in many language runtimes where reading a number using the >>> "friendly way" leaves the input in a state that requires fixing or yields >>> surprises for the next operation. >>> >>> This is because reading a number from an input stream is not any sort of >>> primitive; it is the composite of reading from the input, deciding what to >>> skip, deciding when to stop reading, converting to another type, deciding what >>> state to leave the input stream in, and deciding what to do if no number could >>> be found (or if the number was too big to fit into an int, etc.)? This is not^3 >>> simple! >>> >>> C starts with a simple and principled answer, which is that the IO primitive is >>> getchar() and putchar().? Reading or writing one character is unquestionably a >>> primitive.? (But also, unless you are writing `cat`, no one wants to program >>> with getchar and putchar, because it's too primitive.) >>> >>> One can make a reasonable case for "write a line / read a line" being sensible >>> primitives.? They are simple enough: no parsing, no deciding what to throw >>> away, no possible errors other than EOF, it is clear what state you leave the >>> stream in.? These may not be what the student wants, but they are primitives a >>> student can deal with without having to understand parsing and error handling >>> and statefulness yet. >>> >>> ??? String s = getALine(); >>> ??? printALine(s); >>> >>> is a program every student can reason about. >>> >>> But, it is true that dealing in strings, while honest and simple, is not always >>> what the student wants.? But herein lies the strongest argument for not trying >>> to reinvent Scanner here: the ability to read numbers makes the complexity of >>> the problem, and hence of the API, much much bigger.? (Scanner was very well >>> intentioned, and was not written by children, and yet none of us want to use >>> it.? That's a sign that a one-size-fits-all magic input processing system is >>> harder than it looks, and for something that is explicitly aimed at beginners, >>> is a double warning sign.) >>> >>> I could imagine someone suggesting "why don't you just add `readLineAsInt`". >>> ? But what would happen next?? Well, there would be a million requests >>> (including from folks like Cay) of "you should add X", and then the result is a >>> mishmash jumble of an API (that's already terrible), but worse, it's an onramp >>> that leads to nowhere.? Once the user's needs are slightly more complicated, >>> they are nowhere. >>> >>> Remi has it absolutely right (yes, I really said that) with >>> >>>> The classical program is: >>>> ?? input -> strings -> objects -> strings -> output >>> >>> We do not do users a favor by blurring the distinction between "input -> string" >>> and "string -> object", and because the latter is so much more open-ended than >>> the former, the latter infects the former with its complexity if we try. >>> >>> Is this simple API the most wonderful, be-all of APIs?? Of course not.? But it >>> is a sensible set of primitives that users can understand and *build on* in a >>> transparent way. >>> >>> Some teachers may immediately reach for teaching Integer::parseInt; that's a >>> reasonable strategy, it exposes students to the questions of "what happens when >>> preconditions fail", and the two compose just fine.? But maybe you don't like >>> Integer::parseInt for some reason.? Another way to teach this is to have them >>> write it themselves.? This will expose them to all sorts of interesting >>> questions (what about whitespace? what about double negatives?), but of course >>> is also throwing in the deep end of the pool.? But SimpleIO::readMeALinePlease >>> is agnostic; it works with both approaches. >>> >>> Could the JDK use some better tools for parsing?? Sure; pattern matching has a >>> role to play here, a `String::unformat` would be really cool, and I love parser >>> combinators.? All of this can happen in the future, and none have the effect of >>> making this API look like yet another white elephant like Scanner.? Because it >>> focused purely on the basics. >>> >>> >>> On 2/19/2024 7:25 AM, Remi Forax wrote: >>>> I agree with Brian here, >>>> as a teacher, you have to talk about parsing and formatting, those should not be >>>> hidden. >>>> >>>> The classical program is: >>>> ?? input -> strings -> objects -> strings -> output >>>> >>>> R?mi >>>> >>>> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ >>>> >>>> *From: *"Tagir Valeev" >>>> *To: *"Cay Horstmann" >>>> *Cc: *"Brian Goetz" , "amber-dev" >>>> >>>> *Sent: *Monday, February 19, 2024 10:09:35 AM >>>> *Subject: *Re: SimpleIO in JEP draft 8323335 >>>> >>>> I agree that simple methods to get numeric input are essential for beginners. >>>> They should not be distracted with a complex ceremony. Instead, they should be >>>> able to learn control flow statements and simple algorithms as soon as >>>> possible, having a simple way to get numbers from the user. >>>> With best?regards, >>>> Tagir Valeev. >>>> >>>> On Mon, Feb 19, 2024 at 9:10?AM Cay Horstmann wrote: >>>> >>>> Yes, that's what I am saying. If scanners live in vain, stick with a subset of >>>> the Console methods. Use its readLine. Make it so that SimpleIO uses >>>> System.console(). And add print and println to Console. >>>> >>>> The JEP talks about being able to start programming without having to know about >>>> static methods. How does a beginner read a number? With >>>> Integer.parseInt(readLine(prompt))? >>>> >>>> What about locales? Is print/println localized? Console.printf is. If so, how >>>> are beginners from around the world supposed to read localized numbers? With >>>> NumberFormat.getInstance().parse(readLine(prompt))? >>>> >>>> Adding localized readInt/readDouble to SimpleIO might do the trick. Do they >>>> consume the trailing newline? (The equivalent Scanner methods don't, which is >>>> definitely a sharp edge for beginners.) >>>> >>>> On 18/02/2024 23.08, Brian Goetz wrote: >>>> > OK, so is this really just that that you are bikeshedding the name?? Renaming >>>> > `input` to `readLine`? >>>> > >>>> > This is a perfectly reasonable naming choice, of course, but also, not what you >>>> > suggested the first time around: >>>> > >>>> >? > ... "a third API" ... >>>> > >>>> >? > ... "there are two feasible directions" ... >>>> > >>>> > So what exactly are you suggesting? >>>> > >>>> > >>>> > >>>> > On 2/18/2024 5:03 PM, Cay Horstmann wrote: >>>> >> Like I said, either the scanner methods or the console methods are fine. >>>> >> >>>> >> I am of course aware of the utility/complexity of Scanner, and can understand >>>> >> the motivation to have a simpler/feebler behavior in SimpleIO. Like the one in >>>> >> Console. >>>> >> >>>> >> You don't have to "get a console". A SimpleIO.readLine method can just invoke >>>> >> readLine on the system console. >>>> >> >>>> >> My objection is to add yet another "input" method into the mix. "input" is weak. >>>> >> Does it read a token or the entire line? Does it consume the newline? And if it >>>> >> does just what readLine does, why another method name? Because "input" is three >>>> >> characters fewer? Let's not count characters. >>>> >> >>>> >> On 18/02/2024 22.43, Brian Goetz wrote: >>>> >>> I think you are counting characters and not counting concepts. >>>> >>> >>>> >>> Scanner has a ton of complexity in it that can easily trip up beginners.? The >>>> >>> main sin (though there are others) is that input and parsing are complected >>>> >>> (e.g., nextInt), which only causes more problems (e.g., end of line issues.) >>>> >>> ?? Reading from the console is clearly a () -> String operation.? The input() >>>> >>> method does one thing, which is get a line of text.? That's simple. >>>> >>> >>>> >>> Integer.parseInt (or, soon, patterns that match against string and bind an int) >>>> >>> also does one thing: convert a string from int.? It may seem verbose to have to >>>> >>> do both explicitly, but it allows each of these operations to be simple, and it >>>> >>> is perfectly obvious what is going on. On the other hand, Scanner is a world of >>>> >>> complexity on its own. >>>> >>> >>>> >>> Console::readLine is nice, but first you have to get a Console. ("Why can I >>>> >>> print something without having to get some magic helper object, but I can't do >>>> >>> the same for reading?")? What we're optimizing for here is conceptual >>>> >>> simplicity; the simplest possible input method is the inverse of println.? The >>>> >>> fact that input has to be validated is a fact of life; we can treat validation >>>> >>> separately from IO (and we should), and it gets simpler when you do. >>>> >>> >>>> >>> On 2/18/2024 4:12 PM, Cay Horstmann wrote: >>>> >>>> I would like to comment on the simplicity of https://openjdk.org/jeps/8323335 >>>> >>>> for beginning students. >>>> >>>> >>>> >>>> I am the author of college texts for introductory programming. Like other >>>> >>>> authors, I introduce the Scanner class (and not Console) for reading user >>>> >>>> input. Given that students already know about System.out, it is simpler to call >>>> >>>> >>>> >>>> System.out.print("How old are you? "); >>>> >>>> int x = in.nextInt(); // in is a Scanner >>>> >>>> >>>> >>>> than >>>> >>>> >>>> >>>> int x = Integer.parseInt(console.readLine("How old are you? ")); >>>> >>>> >>>> >>>> or with the JEP draft: >>>> >>>> >>>> >>>> int x = Integer.parseInt(input("How old are you? ")); >>>> >>>> >>>> >>>> Then again, having a prompt string is nice too, so I could imagine using the >>>> >>>> Console API with Integer.parseInt and Double.parseDouble, instead of >>>> >>>> Scanner.nextInt/nextDouble. >>>> >>>> >>>> >>>> But why have a third API, i.e. "input"? >>>> >>>> >>>> >>>> I think there are two feasible directions. Either embrace the Scanner API and >>>> >>>> next/nextInt/nextDouble/nextLine, or the Console API and readLine. Adding >>>> >>>> "input" into the mix is just clutter, and ambiguous clutter at that. At least >>>> >>>> readLine makes it clear that the entire line is consumed. >>>> >>>> >>>> >>>> Cheers, >>>> >>>> >>>> >>>> Cay >>>> >>>> >>>> >>>> -- >>>> >>>> >>>> >>>> Cay S. Horstmann | >>>> >>>> https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$ >>>> >>>> | mailto:cay at horstmann.com >>>> >>> >>>> >> >>>> > >>>> >>>> -- >>>> >>>> -- >>>> >>>> Cay S. Horstmann | http://horstmann.com >>>> >>>> | mailto:cay at horstmann.com >>>> >>>> >>> >> >> -- >> >> -- >> >> Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com -- -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From brian.goetz at oracle.com Tue Feb 20 21:00:41 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 20 Feb 2024 16:00:41 -0500 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: References: Message-ID: I was all ready to dismiss this as just bikeshedding, but your clever up-front disclaimer convinced me to hang with you :) I think what you are saying here is that we've set a trap for ourselves by claiming the word "simple", which, as we've seen, is subject to "everyone interprets it in a way to support their own preference."? Fair point; naming matters, especially when setting direction. I am not as optimistic as you that if we called this "BasicIO", whether we wouldn't get the same arguments, but your point is taken: the goal here is not simplicity, it is about putting in place some very basic IO primitives which can be built upon, which do not depend on either other library abstractions (Scanner, Console, StringTokenizer), which are reasonably symmetric with respect to input and output, and which do not require explanation of static fields in order to use for the first time. These characteristics serve both students and "scripts", in that they address the most basic console IO needs without ancillary abstractions. On 2/20/2024 12:39 PM, Eirik Bj?rsn?s wrote: > Hi, > > I acknowledge the following is easy to dismiss as just bikeshedding, > but please hang with me: > > Is labeling something as "simple" an effective naming practice, > especially in a pedagogical context like we are faced with in this JEP? > > simple: adjective > 1. easily understood or done; presenting no difficulty. > "a simple solution" > > > First, let me be bold and claim that nothing in programming is "easily > understood or done; presenting no difficulty". Anyone claiming so has > clearly lost empathy with the beginning learner! ;-) > > Second, the lable "simple" suggest something about the things not > fitting into the "simple" bucket. If not simple, what are those > things? Difficult? > > Third, "easily understood" very much depends on who is trying to > understand. It may change over time as the learner gains understanding > and experience. Simple to Alice might not be simple to Bob. > > ... > > As any complainer, I'm also too lazy to do the work to find a better > alternative. But perhaps "basic" could be a starting point: > > basic: adjective > 1. forming an essential foundation or starting point; fundamental. > > > This seems more stable to time, context and experience. Something > fundamental can be trusted to stay fundamental for a while. > > Thanks (any sorry!), > Eirik. -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Tue Feb 20 22:49:01 2024 From: john.r.rose at oracle.com (John Rose) Date: Tue, 20 Feb 2024 14:49:01 -0800 Subject: "case catch" instead of "case throws"? In-Reply-To: References: Message-ID: <810B3B48-1E36-47B9-93AE-B8D40FC6BF8A@oracle.com> On 19 Feb 2024, at 10:09, Patrick Doyle wrote: > This would be the first time where > "throws" introduces a syntax construct that does not throw the exception in > question. Maybe, but it is not the first time that the way an expression produces its result serves as a label of a case. The syntax of case labels is intentionally similar to the syntax of expressions which could produce values that could match those case labels. (Similar, not identical.) Put another way, patterns have a surface syntax which suggests ?expressions in reverse?. If you made a box of a string as /new Box("foo")/ then a matching case label might have a similar syntax /case Box("foo"):/. So an expression like /throw new Foo()/ might have a matching case label with a similar shape /case throws Foo:/. From scolebourne at joda.org Wed Feb 21 08:45:51 2024 From: scolebourne at joda.org (Stephen Colebourne) Date: Wed, 21 Feb 2024 08:45:51 +0000 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: References: Message-ID: I do agree that "Simple" isn't the best prefix here, and "Basic" is a bit better, But I personally prefer SystemIO, as it (a) links the concept to the existing System class, which they will likely see or have seen by Googling (b) introduces the concept of the "system" that the code is running on ie. I think "System" is a better on-ramp name as it actually leads to the "real thing" Yours bikeshedderly, Stephen On Tue, 20 Feb 2024 at 21:01, Brian Goetz wrote: > > I was all ready to dismiss this as just bikeshedding, but your clever up-front disclaimer convinced me to hang with you :) > > I think what you are saying here is that we've set a trap for ourselves by claiming the word "simple", which, as we've seen, is subject to "everyone interprets it in a way to support their own preference." Fair point; naming matters, especially when setting direction. > > I am not as optimistic as you that if we called this "BasicIO", whether we wouldn't get the same arguments, but your point is taken: the goal here is not simplicity, it is about putting in place some very basic IO primitives which can be built upon, which do not depend on either other library abstractions (Scanner, Console, StringTokenizer), which are reasonably symmetric with respect to input and output, and which do not require explanation of static fields in order to use for the first time. > > These characteristics serve both students and "scripts", in that they address the most basic console IO needs without ancillary abstractions. > > > > On 2/20/2024 12:39 PM, Eirik Bj?rsn?s wrote: > > Hi, > > I acknowledge the following is easy to dismiss as just bikeshedding, but please hang with me: > > Is labeling something as "simple" an effective naming practice, especially in a pedagogical context like we are faced with in this JEP? > >> simple: adjective >> 1. easily understood or done; presenting no difficulty. >> "a simple solution" > > > First, let me be bold and claim that nothing in programming is "easily understood or done; presenting no difficulty". Anyone claiming so has clearly lost empathy with the beginning learner! ;-) > > Second, the lable "simple" suggest something about the things not fitting into the "simple" bucket. If not simple, what are those things? Difficult? > > Third, "easily understood" very much depends on who is trying to understand. It may change over time as the learner gains understanding and experience. Simple to Alice might not be simple to Bob. > > ... > > As any complainer, I'm also too lazy to do the work to find a better alternative. But perhaps "basic" could be a starting point: > >> basic: adjective >> 1. forming an essential foundation or starting point; fundamental. > > > This seems more stable to time, context and experience. Something fundamental can be trusted to stay fundamental for a while. > > Thanks (any sorry!), > Eirik. > > > From pavel.rappo at oracle.com Wed Feb 21 12:14:07 2024 From: pavel.rappo at oracle.com (Pavel Rappo) Date: Wed, 21 Feb 2024 12:14:07 +0000 Subject: Anonymous classes of enum constants and var In-Reply-To: References: Message-ID: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> >From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing list is not suitable for questions like this. I'm not sure which mailing list is *the most* suitable, but the following one is surely more suitable: https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). I believe, the reasons why the first snippet of yours works, but the second doesn't, is covered here: * https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 (like you said) * https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 I would be surprised if that could change to allow your second snippet. That said, if that functionality is truly required, you can provide it yourself. The design of enums allows you to declare a method on an enum class and then override it in a particular constant. Alternatively, you can switch on an enum constant to provide constant-specific behaviour "externally". -Pavel > On 21 Feb 2024, at 10:08, Red IO wrote: > > I recently tinkered a bit with java enums. While I was researching edge features enums support I came across a stackoverflow post referencing the JLS 8.9 saying that the optional body of an enum constant is an anonymous class declaration. > As for some time now methods declared in an anonymous class assigned to a var variable are accessible I tried to do the same for the enum constant. > > var anonymous = new Object() { > public void test() {} > } > anonymous.test(); //works > > > enum Test { > A { > public void test() {} > } > } > var enumConstant = Test.A; > enumConstant.test(); // doesn't work > > I have a clue to why this doesn't work. It's likely that the type of the constant A is the type of the enum and not of the anonymous class. > > There are some usecases where exclusive methods on enum constants might be useful. So it would be nice if this would work. > > Great regards > RedIODev > > > > From amaembo at gmail.com Wed Feb 21 13:05:34 2024 From: amaembo at gmail.com (Tagir Valeev) Date: Wed, 21 Feb 2024 14:05:34 +0100 Subject: Anonymous classes of enum constants and var In-Reply-To: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> References: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> Message-ID: There's a withdrawn JEP 301 which tried to address this issue, among other things (see "Sharper typing of enum constants" section): https://openjdk.org/jeps/301 Unfortunately, this was never implemented due to issues in the part that suggested making enums generic. I'm not aware of issues in "sharper typing" alone (without the "generic" feature). Probably it could be done separately, but likely nobody wants to invest resources in this. With best regards, Tagir Valeev. On Wed, Feb 21, 2024 at 1:14?PM Pavel Rappo wrote: > From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing list > is not suitable for questions like this. I'm not sure which mailing list is > *the most* suitable, but the following one is surely more suitable: > https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). > > I believe, the reasons why the first snippet of yours works, but the > second doesn't, is covered here: > > * > https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 > (like you said) > * > https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 > > I would be surprised if that could change to allow your second snippet. > That said, if that functionality is truly required, you can provide it > yourself. > > The design of enums allows you to declare a method on an enum class and > then override it in a particular constant. Alternatively, you can switch on > an enum constant to provide constant-specific behaviour "externally". > > -Pavel > > > On 21 Feb 2024, at 10:08, Red IO wrote: > > > > I recently tinkered a bit with java enums. While I was researching edge > features enums support I came across a stackoverflow post referencing the > JLS 8.9 saying that the optional body of an enum constant is an anonymous > class declaration. > > As for some time now methods declared in an anonymous class assigned to > a var variable are accessible I tried to do the same for the enum constant. > > > > var anonymous = new Object() { > > public void test() {} > > } > > anonymous.test(); //works > > > > > > enum Test { > > A { > > public void test() {} > > } > > } > > var enumConstant = Test.A; > > enumConstant.test(); // doesn't work > > > > I have a clue to why this doesn't work. It's likely that the type of the > constant A is the type of the enum and not of the anonymous class. > > > > There are some usecases where exclusive methods on enum constants might > be useful. So it would be nice if this would work. > > > > Great regards > > RedIODev > > > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 13:32:57 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 08:32:57 -0500 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: References: Message-ID: SystemIO is the best suggestion thus far. If you ever do add anything to this class, you don't tie yourself down to the beginner-like name. If one day a useful primitive comes to light that is not so Simple, this class might still be the best place to put it. Really, this class is at it's best when it's a bucket of useful primitives, especially ones that complement each other. Not opening the can of worms for "what", as we've gone fairly off topic from the original threads intent. On Wed, Feb 21, 2024, 3:47?AM Stephen Colebourne wrote: > I do agree that "Simple" isn't the best prefix here, and "Basic" is a > bit better, > > But I personally prefer SystemIO, as it > (a) links the concept to the existing System class, which they will > likely see or have seen by Googling > (b) introduces the concept of the "system" that the code is running on > > ie. I think "System" is a better on-ramp name as it actually leads to > the "real thing" > > Yours bikeshedderly, > Stephen > > > On Tue, 20 Feb 2024 at 21:01, Brian Goetz wrote: > > > > I was all ready to dismiss this as just bikeshedding, but your clever > up-front disclaimer convinced me to hang with you :) > > > > I think what you are saying here is that we've set a trap for ourselves > by claiming the word "simple", which, as we've seen, is subject to > "everyone interprets it in a way to support their own preference." Fair > point; naming matters, especially when setting direction. > > > > I am not as optimistic as you that if we called this "BasicIO", whether > we wouldn't get the same arguments, but your point is taken: the goal here > is not simplicity, it is about putting in place some very basic IO > primitives which can be built upon, which do not depend on either other > library abstractions (Scanner, Console, StringTokenizer), which are > reasonably symmetric with respect to input and output, and which do not > require explanation of static fields in order to use for the first time. > > > > These characteristics serve both students and "scripts", in that they > address the most basic console IO needs without ancillary abstractions. > > > > > > > > On 2/20/2024 12:39 PM, Eirik Bj?rsn?s wrote: > > > > Hi, > > > > I acknowledge the following is easy to dismiss as just bikeshedding, but > please hang with me: > > > > Is labeling something as "simple" an effective naming practice, > especially in a pedagogical context like we are faced with in this JEP? > > > >> simple: adjective > >> 1. easily understood or done; presenting no difficulty. > >> "a simple solution" > > > > > > First, let me be bold and claim that nothing in programming is "easily > understood or done; presenting no difficulty". Anyone claiming so has > clearly lost empathy with the beginning learner! ;-) > > > > Second, the lable "simple" suggest something about the things not > fitting into the "simple" bucket. If not simple, what are those things? > Difficult? > > > > Third, "easily understood" very much depends on who is trying to > understand. It may change over time as the learner gains understanding and > experience. Simple to Alice might not be simple to Bob. > > > > ... > > > > As any complainer, I'm also too lazy to do the work to find a better > alternative. But perhaps "basic" could be a starting point: > > > >> basic: adjective > >> 1. forming an essential foundation or starting point; fundamental. > > > > > > This seems more stable to time, context and experience. Something > fundamental can be trusted to stay fundamental for a while. > > > > Thanks (any sorry!), > > Eirik. > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 13:48:50 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 08:48:50 -0500 Subject: Anonymous classes of enum constants and var In-Reply-To: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> References: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> Message-ID: Idk which is the right group, but I choose amber. I just want to add a couple of clarifications on the various different forms (I spend a LOT of my time woth enums). - You can use an abstract method like so. It has the benefit of forcing every enum value to provide their own implementation of the abstract method. Think of it like a switch with no default clause. enum Blah { VALUE1 { void method() { println("blah"); } }, ; abstract void method(); } - Alternatively, you can provide an implementation of the method. This is more like a switch with a default clause. enum Blah { VALUE1 { void method() { println("blah"); } }, ; void method() { println("default"); } } - And of course, you could model this externally via a switch case. Both of the above bullets are modelable as switch expressions (as explained already). The benefit is that they can keep the enum simple, but the cost is that you must explicitly know the implementation you want instead of having one provided for you. On Wed, Feb 21, 2024, 7:14?AM Pavel Rappo wrote: > From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing list > is not suitable for questions like this. I'm not sure which mailing list is > *the most* suitable, but the following one is surely more suitable: > https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). > > I believe, the reasons why the first snippet of yours works, but the > second doesn't, is covered here: > > * > https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 > (like you said) > * > https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 > > I would be surprised if that could change to allow your second snippet. > That said, if that functionality is truly required, you can provide it > yourself. > > The design of enums allows you to declare a method on an enum class and > then override it in a particular constant. Alternatively, you can switch on > an enum constant to provide constant-specific behaviour "externally". > > -Pavel > > > On 21 Feb 2024, at 10:08, Red IO wrote: > > > > I recently tinkered a bit with java enums. While I was researching edge > features enums support I came across a stackoverflow post referencing the > JLS 8.9 saying that the optional body of an enum constant is an anonymous > class declaration. > > As for some time now methods declared in an anonymous class assigned to > a var variable are accessible I tried to do the same for the enum constant. > > > > var anonymous = new Object() { > > public void test() {} > > } > > anonymous.test(); //works > > > > > > enum Test { > > A { > > public void test() {} > > } > > } > > var enumConstant = Test.A; > > enumConstant.test(); // doesn't work > > > > I have a clue to why this doesn't work. It's likely that the type of the > constant A is the type of the enum and not of the anonymous class. > > > > There are some usecases where exclusive methods on enum constants might > be useful. So it would be nice if this would work. > > > > Great regards > > RedIODev > > > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Feb 21 14:41:10 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 21 Feb 2024 09:41:10 -0500 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: References: Message-ID: <9946d71d-77e5-48e8-bc6b-ca7a8ab7b6da@oracle.com> Agree this is a better name. As to the "bucket of what" question, we had a very deliberate target in mind: we did *not* want this to become the catch-all "statically imported" bucket (which would rapidly become an attractive nuisance), so we chose a targeted name to make it clear that this was about a narrow set of things that are useful to the specific situation of IO from simple programs. > SystemIO is the best suggestion thus far. If you ever do add anything > to this class, you don't tie yourself down to the beginner-like name. > If one day a useful primitive comes to light that is not so Simple, > this class might still be the best place to put it. Really, this class > is at it's best when it's a bucket of useful primitives, especially > ones that complement each other. Not opening the can of worms for > "what", as we've gone fairly off topic from the original threads intent. > > On Wed, Feb 21, 2024, 3:47?AM Stephen Colebourne > wrote: > > I do agree that "Simple" isn't the best prefix here, and "Basic" is a > bit better, > > But I personally prefer SystemIO, as it > (a) links the concept to the existing System class, which they will > likely see or have seen by Googling > (b) introduces the concept of the "system" that the code is running on > > ie. I think "System" is a better on-ramp name as it actually leads to > the "real thing" > > Yours bikeshedderly, > Stephen > > > On Tue, 20 Feb 2024 at 21:01, Brian Goetz > wrote: > > > > I was all ready to dismiss this as just bikeshedding, but your > clever up-front disclaimer convinced me to hang with you :) > > > > I think what you are saying here is that we've set a trap for > ourselves by claiming the word "simple", which, as we've seen, is > subject to "everyone interprets it in a way to support their own > preference."? Fair point; naming matters, especially when setting > direction. > > > > I am not as optimistic as you that if we called this "BasicIO", > whether we wouldn't get the same arguments, but your point is > taken: the goal here is not simplicity, it is about putting in > place some very basic IO primitives which can be built upon, which > do not depend on either other library abstractions (Scanner, > Console, StringTokenizer), which are reasonably symmetric with > respect to input and output, and which do not require explanation > of static fields in order to use for the first time. > > > > These characteristics serve both students and "scripts", in that > they address the most basic console IO needs without ancillary > abstractions. > > > > > > > > On 2/20/2024 12:39 PM, Eirik Bj?rsn?s wrote: > > > > Hi, > > > > I acknowledge the following is easy to dismiss as just > bikeshedding, but please hang with me: > > > > Is labeling something as "simple" an effective naming practice, > especially in a pedagogical context like we are faced with in this > JEP? > > > >> simple: adjective > >> 1. easily understood or done; presenting no difficulty. > >> "a simple solution" > > > > > > First, let me be bold and claim that nothing in programming is > "easily understood or done; presenting no difficulty". Anyone > claiming so has clearly lost empathy with the beginning learner! ;-) > > > > Second, the lable "simple" suggest something about the things > not fitting into the "simple" bucket. If not simple, what are > those things? Difficult? > > > > Third, "easily understood" very much depends on who is trying to > understand. It may change over time as the learner gains > understanding and experience. Simple to Alice might not be simple > to Bob. > > > > ... > > > > As any complainer, I'm also too lazy to do the work to find a > better alternative. But perhaps "basic" could be a starting point: > > > >> basic: adjective > >> 1. forming an essential foundation or starting point; fundamental. > > > > > > This seems more stable to time, context and experience. > Something fundamental can be trusted to stay fundamental for a while. > > > > Thanks (any sorry!), > > Eirik. > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From eirbjo at gmail.com Wed Feb 21 14:49:05 2024 From: eirbjo at gmail.com (=?UTF-8?B?RWlyaWsgQmrDuHJzbsO4cw==?=) Date: Wed, 21 Feb 2024 15:49:05 +0100 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: References: Message-ID: On Wed, Feb 21, 2024 at 9:47?AM Stephen Colebourne wrote: > ie. I think "System" is a better on-ramp name as it actually leads to > the "real thing" > To pull this string a bit more, perhaps we could even tuck this away as a static class IO in System? import static java.lang.System.IO.*; // Implicit println("Hello"); System.IO.println("Goodbye"); // Explicit That would free the java.io.* namespace of the burden of having a name for this thing which seems a bit out of place and awkward outside the context of implicit classes. (Disclaimer: I'm casually throwing out a thought here without much thought, that's what bikeshedding is all about, right! :) Eirik. -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Wed Feb 21 18:02:04 2024 From: redio.development at gmail.com (Red IO) Date: Wed, 21 Feb 2024 19:02:04 +0100 Subject: Anonymous classes of enum constants and var In-Reply-To: References: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> Message-ID: This is nice and well. But it isn't the same thing. Sure this works well if every varient does exactly the same thing. But say you have a enum having varients that share a feature but have their own unique properties. Like a rule set to initialize something and an associated constants or operation that only makes sense for 1 varient. Currently you need to define both public constants and public methods in the enum associating it with the whole enum instead of the varient that works with it. In methods that gets even worse as you need to provide a default operation that either does nothing or throws for incompatible varients. By simply typing the enum constant to the anonymous class this would become possible. Great regards RedIODev On Wed, Feb 21, 2024, 14:49 David Alayachew wrote: > Idk which is the right group, but I choose amber. > > I just want to add a couple of clarifications on the various different > forms (I spend a LOT of my time woth enums). > > > - You can use an abstract method like so. It has the benefit of > forcing every enum value to provide their own implementation of the > abstract method. Think of it like a switch with no default clause. > > > enum Blah > { > > VALUE1 > { > > void method() > { > > println("blah"); > > } > > }, > ; > > abstract void method(); > > } > > > - Alternatively, you can provide an implementation of the method. This > is more like a switch with a default clause. > > > enum Blah > { > > VALUE1 > { > > void method() > { > > println("blah"); > > } > > }, > ; > > void method() > { > > println("default"); > > } > > } > > > - And of course, you could model this externally via a switch case. > Both of the above bullets are modelable as switch expressions (as explained > already). The benefit is that they can keep the enum simple, but the cost > is that you must explicitly know the implementation you want instead of > having one provided for you. > > > > > On Wed, Feb 21, 2024, 7:14?AM Pavel Rappo wrote: > >> From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing >> list is not suitable for questions like this. I'm not sure which mailing >> list is *the most* suitable, but the following one is surely more suitable: >> https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). >> >> I believe, the reasons why the first snippet of yours works, but the >> second doesn't, is covered here: >> >> * >> https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 >> (like you said) >> * >> https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 >> >> I would be surprised if that could change to allow your second snippet. >> That said, if that functionality is truly required, you can provide it >> yourself. >> >> The design of enums allows you to declare a method on an enum class and >> then override it in a particular constant. Alternatively, you can switch on >> an enum constant to provide constant-specific behaviour "externally". >> >> -Pavel >> >> > On 21 Feb 2024, at 10:08, Red IO wrote: >> > >> > I recently tinkered a bit with java enums. While I was researching edge >> features enums support I came across a stackoverflow post referencing the >> JLS 8.9 saying that the optional body of an enum constant is an anonymous >> class declaration. >> > As for some time now methods declared in an anonymous class assigned to >> a var variable are accessible I tried to do the same for the enum constant. >> > >> > var anonymous = new Object() { >> > public void test() {} >> > } >> > anonymous.test(); //works >> > >> > >> > enum Test { >> > A { >> > public void test() {} >> > } >> > } >> > var enumConstant = Test.A; >> > enumConstant.test(); // doesn't work >> > >> > I have a clue to why this doesn't work. It's likely that the type of >> the constant A is the type of the enum and not of the anonymous class. >> > >> > There are some usecases where exclusive methods on enum constants might >> be useful. So it would be nice if this would work. >> > >> > Great regards >> > RedIODev >> > >> > >> > >> > >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 18:55:41 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 13:55:41 -0500 Subject: Anonymous classes of enum constants and var In-Reply-To: References: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> Message-ID: Hold on, I thought this was the entire purpose of refactoring an enum into a class? If all of the values do NOT have the same method, then by definition, they are not of the same type. The nature of an anonymous class is to, effectively, announce that you are making a new type that, if they are in the same scope, can use these new things you are defining on the anonymous type. But, because it is anonymous, then by definition,they have no way to access this UNLESS THOSE WISHING TO ACCESS ARE IN THE SAME COMPILATION UNIT. This is scope access. I think you are complecting the scope access with what abilities the anonymous class grants you. The anonymous class does not have the ability to effectively add to its public api. The fact that you can add a public method to an anonymous class is a very sharp edge that cuts a lot of developers. Yes, you can put a public method there, but it is almost entirely redundant. You cannot reference that public method because the only way to reference that public method is by having the type name. Since it is anonymous, then by definition, you can't. You must associate that method to a named type (for example, an interface) in order to be able to use your new public method. But by that point, it's not your anonymous class that added to the public api, it's the interface. Very sharp edge that should be removed in my firm opinion. At best, anonymous classes can modify the implementation of its public api, potentially. However, being in the same compilation unit/scope allows you to view fields and methods that you add to that anonymous class. Let me know if that doesn't make sense. But by definition, the thing you are trying to do is not attainable by anonymous classes alone. It would require some other mechanism to be introduced or used to introduce your method name into scope. And at that point, it would not be the anonymous class making this possible. But maybe I am completely wrong. I spent a couple frustrated months trying to do exactly what you are doing. Maybe something was added in the past few releases that made this now possible. On Wed, Feb 21, 2024, 1:02?PM Red IO wrote: > This is nice and well. But it isn't the same thing. Sure this works well > if every varient does exactly the same thing. But say you have a enum > having varients that share a feature but have their own unique properties. > Like a rule set to initialize something and an associated constants or > operation that only makes sense for 1 varient. Currently you need to define > both public constants and public methods in the enum associating it with > the whole enum instead of the varient that works with it. In methods that > gets even worse as you need to provide a default operation that either does > nothing or throws for incompatible varients. By simply typing the enum > constant to the anonymous class this would become possible. > > Great regards > RedIODev > > On Wed, Feb 21, 2024, 14:49 David Alayachew > wrote: > >> Idk which is the right group, but I choose amber. >> >> I just want to add a couple of clarifications on the various different >> forms (I spend a LOT of my time woth enums). >> >> >> - You can use an abstract method like so. It has the benefit of >> forcing every enum value to provide their own implementation of the >> abstract method. Think of it like a switch with no default clause. >> >> >> enum Blah >> { >> >> VALUE1 >> { >> >> void method() >> { >> >> println("blah"); >> >> } >> >> }, >> ; >> >> abstract void method(); >> >> } >> >> >> - Alternatively, you can provide an implementation of the method. >> This is more like a switch with a default clause. >> >> >> enum Blah >> { >> >> VALUE1 >> { >> >> void method() >> { >> >> println("blah"); >> >> } >> >> }, >> ; >> >> void method() >> { >> >> println("default"); >> >> } >> >> } >> >> >> - And of course, you could model this externally via a switch case. >> Both of the above bullets are modelable as switch expressions (as explained >> already). The benefit is that they can keep the enum simple, but the cost >> is that you must explicitly know the implementation you want instead of >> having one provided for you. >> >> >> >> >> On Wed, Feb 21, 2024, 7:14?AM Pavel Rappo wrote: >> >>> From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing >>> list is not suitable for questions like this. I'm not sure which mailing >>> list is *the most* suitable, but the following one is surely more suitable: >>> https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). >>> >>> I believe, the reasons why the first snippet of yours works, but the >>> second doesn't, is covered here: >>> >>> * >>> https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 >>> (like you said) >>> * >>> https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 >>> >>> I would be surprised if that could change to allow your second snippet. >>> That said, if that functionality is truly required, you can provide it >>> yourself. >>> >>> The design of enums allows you to declare a method on an enum class and >>> then override it in a particular constant. Alternatively, you can switch on >>> an enum constant to provide constant-specific behaviour "externally". >>> >>> -Pavel >>> >>> > On 21 Feb 2024, at 10:08, Red IO wrote: >>> > >>> > I recently tinkered a bit with java enums. While I was researching >>> edge features enums support I came across a stackoverflow post referencing >>> the JLS 8.9 saying that the optional body of an enum constant is an >>> anonymous class declaration. >>> > As for some time now methods declared in an anonymous class assigned >>> to a var variable are accessible I tried to do the same for the enum >>> constant. >>> > >>> > var anonymous = new Object() { >>> > public void test() {} >>> > } >>> > anonymous.test(); //works >>> > >>> > >>> > enum Test { >>> > A { >>> > public void test() {} >>> > } >>> > } >>> > var enumConstant = Test.A; >>> > enumConstant.test(); // doesn't work >>> > >>> > I have a clue to why this doesn't work. It's likely that the type of >>> the constant A is the type of the enum and not of the anonymous class. >>> > >>> > There are some usecases where exclusive methods on enum constants >>> might be useful. So it would be nice if this would work. >>> > >>> > Great regards >>> > RedIODev >>> > >>> > >>> > >>> > >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 18:59:28 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 13:59:28 -0500 Subject: Anonymous classes of enum constants and var In-Reply-To: References: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> Message-ID: And minor correction/clarification/consolidation on the intent of anonymous class. In short, an anonymous class allows you to change the insides (implementation) while leaving the outside (api) untouched. But due to the rules of scoping and access permissions, if your anonymous class happens to be in the same compilation unit or scope, then fellow members of that compilation unit or scope have access to not just your api, BUT YOUR IMPLEMENTATION. That is why anonymous classes can have their newly introduced public methoss called, even they are effectively unreachable from anywhere else besides the sane compilation unit or scope. On Wed, Feb 21, 2024, 1:55?PM David Alayachew wrote: > Hold on, I thought this was the entire purpose of refactoring an enum into > a class? > > If all of the values do NOT have the same method, then by definition, they > are not of the same type. The nature of an anonymous class is to, > effectively, announce that you are making a new type that, if they are in > the same scope, can use these new things you are defining on the anonymous > type. But, because it is anonymous, then by definition,they have no way to > access this UNLESS THOSE WISHING TO ACCESS ARE IN THE SAME COMPILATION > UNIT. This is scope access. > > I think you are complecting the scope access with what abilities the > anonymous class grants you. The anonymous class does not have the ability > to effectively add to its public api. The fact that you can add a public > method to an anonymous class is a very sharp edge that cuts a lot of > developers. Yes, you can put a public method there, but it is almost > entirely redundant. You cannot reference that public method because the > only way to reference that public method is by having the type name. Since > it is anonymous, then by definition, you can't. You must associate that > method to a named type (for example, an interface) in order to be able to > use your new public method. But by that point, it's not your anonymous > class that added to the public api, it's the interface. Very sharp edge > that should be removed in my firm opinion. > > At best, anonymous classes can modify the implementation of its public > api, potentially. However, being in the same compilation unit/scope allows > you to view fields and methods that you add to that anonymous class. > > Let me know if that doesn't make sense. But by definition, the thing you > are trying to do is not attainable by anonymous classes alone. It would > require some other mechanism to be introduced or used to introduce your > method name into scope. And at that point, it would not be the anonymous > class making this possible. > > But maybe I am completely wrong. I spent a couple frustrated months trying > to do exactly what you are doing. Maybe something was added in the past few > releases that made this now possible. > > On Wed, Feb 21, 2024, 1:02?PM Red IO wrote: > >> This is nice and well. But it isn't the same thing. Sure this works well >> if every varient does exactly the same thing. But say you have a enum >> having varients that share a feature but have their own unique properties. >> Like a rule set to initialize something and an associated constants or >> operation that only makes sense for 1 varient. Currently you need to define >> both public constants and public methods in the enum associating it with >> the whole enum instead of the varient that works with it. In methods that >> gets even worse as you need to provide a default operation that either does >> nothing or throws for incompatible varients. By simply typing the enum >> constant to the anonymous class this would become possible. >> >> Great regards >> RedIODev >> >> On Wed, Feb 21, 2024, 14:49 David Alayachew >> wrote: >> >>> Idk which is the right group, but I choose amber. >>> >>> I just want to add a couple of clarifications on the various different >>> forms (I spend a LOT of my time woth enums). >>> >>> >>> - You can use an abstract method like so. It has the benefit of >>> forcing every enum value to provide their own implementation of the >>> abstract method. Think of it like a switch with no default clause. >>> >>> >>> enum Blah >>> { >>> >>> VALUE1 >>> { >>> >>> void method() >>> { >>> >>> println("blah"); >>> >>> } >>> >>> }, >>> ; >>> >>> abstract void method(); >>> >>> } >>> >>> >>> - Alternatively, you can provide an implementation of the method. >>> This is more like a switch with a default clause. >>> >>> >>> enum Blah >>> { >>> >>> VALUE1 >>> { >>> >>> void method() >>> { >>> >>> println("blah"); >>> >>> } >>> >>> }, >>> ; >>> >>> void method() >>> { >>> >>> println("default"); >>> >>> } >>> >>> } >>> >>> >>> - And of course, you could model this externally via a switch case. >>> Both of the above bullets are modelable as switch expressions (as explained >>> already). The benefit is that they can keep the enum simple, but the cost >>> is that you must explicitly know the implementation you want instead of >>> having one provided for you. >>> >>> >>> >>> >>> On Wed, Feb 21, 2024, 7:14?AM Pavel Rappo >>> wrote: >>> >>>> From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing >>>> list is not suitable for questions like this. I'm not sure which mailing >>>> list is *the most* suitable, but the following one is surely more suitable: >>>> https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). >>>> >>>> I believe, the reasons why the first snippet of yours works, but the >>>> second doesn't, is covered here: >>>> >>>> * >>>> https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 >>>> (like you said) >>>> * >>>> https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 >>>> >>>> I would be surprised if that could change to allow your second snippet. >>>> That said, if that functionality is truly required, you can provide it >>>> yourself. >>>> >>>> The design of enums allows you to declare a method on an enum class and >>>> then override it in a particular constant. Alternatively, you can switch on >>>> an enum constant to provide constant-specific behaviour "externally". >>>> >>>> -Pavel >>>> >>>> > On 21 Feb 2024, at 10:08, Red IO wrote: >>>> > >>>> > I recently tinkered a bit with java enums. While I was researching >>>> edge features enums support I came across a stackoverflow post referencing >>>> the JLS 8.9 saying that the optional body of an enum constant is an >>>> anonymous class declaration. >>>> > As for some time now methods declared in an anonymous class assigned >>>> to a var variable are accessible I tried to do the same for the enum >>>> constant. >>>> > >>>> > var anonymous = new Object() { >>>> > public void test() {} >>>> > } >>>> > anonymous.test(); //works >>>> > >>>> > >>>> > enum Test { >>>> > A { >>>> > public void test() {} >>>> > } >>>> > } >>>> > var enumConstant = Test.A; >>>> > enumConstant.test(); // doesn't work >>>> > >>>> > I have a clue to why this doesn't work. It's likely that the type of >>>> the constant A is the type of the enum and not of the anonymous class. >>>> > >>>> > There are some usecases where exclusive methods on enum constants >>>> might be useful. So it would be nice if this would work. >>>> > >>>> > Great regards >>>> > RedIODev >>>> > >>>> > >>>> > >>>> > >>>> >>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 19:20:05 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 14:20:05 -0500 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: <9946d71d-77e5-48e8-bc6b-ca7a8ab7b6da@oracle.com> References: <9946d71d-77e5-48e8-bc6b-ca7a8ab7b6da@oracle.com> Message-ID: ? David reacted via Gmail On Wed, Feb 21, 2024, 9:41?AM Brian Goetz wrote: > Agree this is a better name. > > As to the "bucket of what" question, we had a very deliberate target in > mind: we did *not* want this to become the catch-all "statically imported" > bucket (which would rapidly become an attractive nuisance), so we chose a > targeted name to make it clear that this was about a narrow set of things > that are useful to the specific situation of IO from simple programs. > > SystemIO is the best suggestion thus far. If you ever do add anything to > this class, you don't tie yourself down to the beginner-like name. If one > day a useful primitive comes to light that is not so Simple, this class > might still be the best place to put it. Really, this class is at it's best > when it's a bucket of useful primitives, especially ones that complement > each other. Not opening the can of worms for "what", as we've gone fairly > off topic from the original threads intent. > > On Wed, Feb 21, 2024, 3:47?AM Stephen Colebourne > wrote: > >> I do agree that "Simple" isn't the best prefix here, and "Basic" is a >> bit better, >> >> But I personally prefer SystemIO, as it >> (a) links the concept to the existing System class, which they will >> likely see or have seen by Googling >> (b) introduces the concept of the "system" that the code is running on >> >> ie. I think "System" is a better on-ramp name as it actually leads to >> the "real thing" >> >> Yours bikeshedderly, >> Stephen >> >> >> On Tue, 20 Feb 2024 at 21:01, Brian Goetz wrote: >> > >> > I was all ready to dismiss this as just bikeshedding, but your clever >> up-front disclaimer convinced me to hang with you :) >> > >> > I think what you are saying here is that we've set a trap for ourselves >> by claiming the word "simple", which, as we've seen, is subject to >> "everyone interprets it in a way to support their own preference." Fair >> point; naming matters, especially when setting direction. >> > >> > I am not as optimistic as you that if we called this "BasicIO", whether >> we wouldn't get the same arguments, but your point is taken: the goal here >> is not simplicity, it is about putting in place some very basic IO >> primitives which can be built upon, which do not depend on either other >> library abstractions (Scanner, Console, StringTokenizer), which are >> reasonably symmetric with respect to input and output, and which do not >> require explanation of static fields in order to use for the first time. >> > >> > These characteristics serve both students and "scripts", in that they >> address the most basic console IO needs without ancillary abstractions. >> > >> > >> > >> > On 2/20/2024 12:39 PM, Eirik Bj?rsn?s wrote: >> > >> > Hi, >> > >> > I acknowledge the following is easy to dismiss as just bikeshedding, >> but please hang with me: >> > >> > Is labeling something as "simple" an effective naming practice, >> especially in a pedagogical context like we are faced with in this JEP? >> > >> >> simple: adjective >> >> 1. easily understood or done; presenting no difficulty. >> >> "a simple solution" >> > >> > >> > First, let me be bold and claim that nothing in programming is "easily >> understood or done; presenting no difficulty". Anyone claiming so has >> clearly lost empathy with the beginning learner! ;-) >> > >> > Second, the lable "simple" suggest something about the things not >> fitting into the "simple" bucket. If not simple, what are those things? >> Difficult? >> > >> > Third, "easily understood" very much depends on who is trying to >> understand. It may change over time as the learner gains understanding and >> experience. Simple to Alice might not be simple to Bob. >> > >> > ... >> > >> > As any complainer, I'm also too lazy to do the work to find a better >> alternative. But perhaps "basic" could be a starting point: >> > >> >> basic: adjective >> >> 1. forming an essential foundation or starting point; fundamental. >> > >> > >> > This seems more stable to time, context and experience. Something >> fundamental can be trusted to stay fundamental for a while. >> > >> > Thanks (any sorry!), >> > Eirik. >> > >> > >> > >> > > -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: text/vnd.google.email-reaction+json Size: 37 bytes Desc: not available URL: -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 19:24:12 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 14:24:12 -0500 Subject: Simple is as simple does (JEP draft 8323335) In-Reply-To: <9946d71d-77e5-48e8-bc6b-ca7a8ab7b6da@oracle.com> References: <9946d71d-77e5-48e8-bc6b-ca7a8ab7b6da@oracle.com> Message-ID: Touche. This class is strictly IO focused, and basic IO at that. And even within that, the bar should be extremely high for what goes in this class. But let me ask -- if many things meet that bar, do you feel there should be a limit for how many enter the class? On Wed, Feb 21, 2024, 9:41?AM Brian Goetz wrote: > Agree this is a better name. > > As to the "bucket of what" question, we had a very deliberate target in > mind: we did *not* want this to become the catch-all "statically imported" > bucket (which would rapidly become an attractive nuisance), so we chose a > targeted name to make it clear that this was about a narrow set of things > that are useful to the specific situation of IO from simple programs. > > SystemIO is the best suggestion thus far. If you ever do add anything to > this class, you don't tie yourself down to the beginner-like name. If one > day a useful primitive comes to light that is not so Simple, this class > might still be the best place to put it. Really, this class is at it's best > when it's a bucket of useful primitives, especially ones that complement > each other. Not opening the can of worms for "what", as we've gone fairly > off topic from the original threads intent. > > On Wed, Feb 21, 2024, 3:47?AM Stephen Colebourne > wrote: > >> I do agree that "Simple" isn't the best prefix here, and "Basic" is a >> bit better, >> >> But I personally prefer SystemIO, as it >> (a) links the concept to the existing System class, which they will >> likely see or have seen by Googling >> (b) introduces the concept of the "system" that the code is running on >> >> ie. I think "System" is a better on-ramp name as it actually leads to >> the "real thing" >> >> Yours bikeshedderly, >> Stephen >> >> >> On Tue, 20 Feb 2024 at 21:01, Brian Goetz wrote: >> > >> > I was all ready to dismiss this as just bikeshedding, but your clever >> up-front disclaimer convinced me to hang with you :) >> > >> > I think what you are saying here is that we've set a trap for ourselves >> by claiming the word "simple", which, as we've seen, is subject to >> "everyone interprets it in a way to support their own preference." Fair >> point; naming matters, especially when setting direction. >> > >> > I am not as optimistic as you that if we called this "BasicIO", whether >> we wouldn't get the same arguments, but your point is taken: the goal here >> is not simplicity, it is about putting in place some very basic IO >> primitives which can be built upon, which do not depend on either other >> library abstractions (Scanner, Console, StringTokenizer), which are >> reasonably symmetric with respect to input and output, and which do not >> require explanation of static fields in order to use for the first time. >> > >> > These characteristics serve both students and "scripts", in that they >> address the most basic console IO needs without ancillary abstractions. >> > >> > >> > >> > On 2/20/2024 12:39 PM, Eirik Bj?rsn?s wrote: >> > >> > Hi, >> > >> > I acknowledge the following is easy to dismiss as just bikeshedding, >> but please hang with me: >> > >> > Is labeling something as "simple" an effective naming practice, >> especially in a pedagogical context like we are faced with in this JEP? >> > >> >> simple: adjective >> >> 1. easily understood or done; presenting no difficulty. >> >> "a simple solution" >> > >> > >> > First, let me be bold and claim that nothing in programming is "easily >> understood or done; presenting no difficulty". Anyone claiming so has >> clearly lost empathy with the beginning learner! ;-) >> > >> > Second, the lable "simple" suggest something about the things not >> fitting into the "simple" bucket. If not simple, what are those things? >> Difficult? >> > >> > Third, "easily understood" very much depends on who is trying to >> understand. It may change over time as the learner gains understanding and >> experience. Simple to Alice might not be simple to Bob. >> > >> > ... >> > >> > As any complainer, I'm also too lazy to do the work to find a better >> alternative. But perhaps "basic" could be a starting point: >> > >> >> basic: adjective >> >> 1. forming an essential foundation or starting point; fundamental. >> > >> > >> > This seems more stable to time, context and experience. Something >> fundamental can be trusted to stay fundamental for a while. >> > >> > Thanks (any sorry!), >> > Eirik. >> > >> > >> > >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 19:38:27 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 14:38:27 -0500 Subject: Anonymous classes of enum constants and var In-Reply-To: References: <1506A73B-8202-432A-862F-DD7ED3F91F6C@oracle.com> Message-ID: I was extremely extremely sad when they said no JEP 301. ? Enums would be literally perfect if we had that feature. And Java enums are so much better than literally any other non-JVM languages enums, so part of me also wishes we could widen the gap further lol. And to clarify, when I say the word enum, I am referring to an enumerated set of VALUES, not TYPES. Rust and friends like to use enums to do types, which is not the same thing. That's more like our sealed types. But as far as enum of values, we are uncontested, save for other JVM languages. On Wed, Feb 21, 2024, 9:27?AM Tagir Valeev wrote: > There's a withdrawn JEP 301 which tried to address this issue, among other > things (see "Sharper typing of enum constants" section): > https://openjdk.org/jeps/301 > > Unfortunately, this was never implemented due to issues in the part that > suggested making enums generic. I'm not aware of issues in "sharper typing" > alone (without the "generic" feature). Probably it could be done > separately, but likely nobody wants to invest resources in this. > > With best regards, > Tagir Valeev. > > On Wed, Feb 21, 2024 at 1:14?PM Pavel Rappo > wrote: > >> From https://mail.openjdk.org/mailman/listinfo/discuss, this mailing >> list is not suitable for questions like this. I'm not sure which mailing >> list is *the most* suitable, but the following one is surely more suitable: >> https://mail.openjdk.org/pipermail/amber-dev/ (CC'ed). >> >> I believe, the reasons why the first snippet of yours works, but the >> second doesn't, is covered here: >> >> * >> https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-8.9.1 >> (like you said) >> * >> https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.4.1 >> >> I would be surprised if that could change to allow your second snippet. >> That said, if that functionality is truly required, you can provide it >> yourself. >> >> The design of enums allows you to declare a method on an enum class and >> then override it in a particular constant. Alternatively, you can switch on >> an enum constant to provide constant-specific behaviour "externally". >> >> -Pavel >> >> > On 21 Feb 2024, at 10:08, Red IO wrote: >> > >> > I recently tinkered a bit with java enums. While I was researching edge >> features enums support I came across a stackoverflow post referencing the >> JLS 8.9 saying that the optional body of an enum constant is an anonymous >> class declaration. >> > As for some time now methods declared in an anonymous class assigned to >> a var variable are accessible I tried to do the same for the enum constant. >> > >> > var anonymous = new Object() { >> > public void test() {} >> > } >> > anonymous.test(); //works >> > >> > >> > enum Test { >> > A { >> > public void test() {} >> > } >> > } >> > var enumConstant = Test.A; >> > enumConstant.test(); // doesn't work >> > >> > I have a clue to why this doesn't work. It's likely that the type of >> the constant A is the type of the enum and not of the anonymous class. >> > >> > There are some usecases where exclusive methods on enum constants might >> be useful. So it would be nice if this would work. >> > >> > Great regards >> > RedIODev >> > >> > >> > >> > >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From scolebourne at joda.org Wed Feb 21 22:04:48 2024 From: scolebourne at joda.org (Stephen Colebourne) Date: Wed, 21 Feb 2024 22:04:48 +0000 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> Message-ID: I'd like to express basic agreement that reading and writing a string (and not more) is a good first API. But I also agree that it is potentially an on-ramp to nowhere. I'm also not at all happy with `input("How old are you? ")` which is doing two unrelated things (printing and reading a line) I'd like to throw out a left-field idea to the educators here - transformation via method reference. printLine("Enter your age"); int age = readLine(Integer::parseInt); Obviously a method reference lambda is not a simple thing to explain fully, but it is short and direct. Perhaps in the initial learning stages you can get away without explaining exactly how Integer::parseInt operates? Suggested API: public final class SystemIO { public static void printLine(Object obj) ... public static void print(Object obj) ... public static String readLine() throws UncheckedIOException ... public static T readLine(Function transformer) throws UncheckedIOException ... } Stephen On Tue, 20 Feb 2024 at 19:32, Cay Horstmann wrote: > > Hi R?mi, > > I am not bothered by the concepts that Scanner needs, because for me they are reasonable investments. As you point out, they are: > > * instance methods > * new > * import > > I would switch to a different approach if it (a) didn't introduce yet another fiddly special case (magic static import) and (b) wasn't unreasonably verbose. I would find this too painful: > > import java.util.SimpleIO; > > int age = Integer.parseInt(SimpleIO.input("How old are you? ")); > > I could embrace the magic static import if it was sufficiently general and useful to pay for the complexity. Hence my suggestion > > int age = parseInt(input("How old are you? ")); > > Or > > int age = readInt("How old are you? "); > > I need to make these decisions for the books and activities that I produce. As it is in the JEP today, I'd stick with Scanner. I would put in a note, just to signal that I know what is happening, that as of Java 25 (?), you can also use input, but that it relies on another fiddly rule, and it doesn't transfer to file I/O, so why bother... > > My sentiment is just a data point. I understand that the cost/benefit model is different for everyone. > > Cheers, > > Cay > > PS. I'd like to register a forceful pushback on "parsing numbers is so crazily complex that we can't possibly deal with it". What does print/println produce for numbers? Is it the crazily complex localized number format? No--only printf applies localization. The print/println methods format numbers as Java literals. That's a settled issue. It's been like that since Java 1.0. Not crazily complex. A readInt/readDouble (or whatever it is called) in SimpleIO can surely be the canonical inverse of print/println. From davidalayachew at gmail.com Wed Feb 21 22:34:27 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 17:34:27 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> Message-ID: I can agree with separating the 2 in input. It really helps separate everything down to its primitives. I have confusion about the method reference. I tutored 100's of kids from middle schoolers up to post graduate college students. Long story short, most post grads had only heard of method references. Not a single college student I have ever tutored in college has ever been taught about method references, let alone used it in a course. At best, a student who is clearly leading the class decides to do it for fun, since they aren't learning anything to begin with I am not saying the kids are the final say. I am saying that they are the biggest portion of our target audience. And a vast majority of them will not be able to make use of this. Putting aside the kids then, the new Java devs that are using this (who also happen to know method references?) are likely not going to gain much from the inclusion of this. At the end of the day, you are swapping a method call with a method reference. What does the method reference give you that you wouldn't get with a method call? On Wed, Feb 21, 2024, 5:05?PM Stephen Colebourne wrote: > I'd like to express basic agreement that reading and writing a string > (and not more) is a good first API. But I also agree that it is > potentially an on-ramp to nowhere. > > I'm also not at all happy with `input("How old are you? ")` which is > doing two unrelated things (printing and reading a line) > > > I'd like to throw out a left-field idea to the educators here - > transformation via method reference. > > printLine("Enter your age"); > int age = readLine(Integer::parseInt); > > Obviously a method reference lambda is not a simple thing to explain > fully, but it is short and direct. Perhaps in the initial learning > stages you can get away without explaining exactly how > Integer::parseInt operates? > > Suggested API: > public final class SystemIO { > public static void printLine(Object obj) ... > public static void print(Object obj) ... > public static String readLine() throws UncheckedIOException ... > public static T readLine(Function transformer) > throws UncheckedIOException ... > } > > Stephen > > > On Tue, 20 Feb 2024 at 19:32, Cay Horstmann wrote: > > > > Hi R?mi, > > > > I am not bothered by the concepts that Scanner needs, because for me > they are reasonable investments. As you point out, they are: > > > > * instance methods > > * new > > * import > > > > I would switch to a different approach if it (a) didn't introduce yet > another fiddly special case (magic static import) and (b) wasn't > unreasonably verbose. I would find this too painful: > > > > import java.util.SimpleIO; > > > > int age = Integer.parseInt(SimpleIO.input("How old are you? ")); > > > > I could embrace the magic static import if it was sufficiently general > and useful to pay for the complexity. Hence my suggestion > > > > int age = parseInt(input("How old are you? ")); > > > > Or > > > > int age = readInt("How old are you? "); > > > > I need to make these decisions for the books and activities that I > produce. As it is in the JEP today, I'd stick with Scanner. I would put in > a note, just to signal that I know what is happening, that as of Java 25 > (?), you can also use input, but that it relies on another fiddly rule, and > it doesn't transfer to file I/O, so why bother... > > > > My sentiment is just a data point. I understand that the cost/benefit > model is different for everyone. > > > > Cheers, > > > > Cay > > > > PS. I'd like to register a forceful pushback on "parsing numbers is so > crazily complex that we can't possibly deal with it". What does > print/println produce for numbers? Is it the crazily complex localized > number format? No--only printf applies localization. The print/println > methods format numbers as Java literals. That's a settled issue. It's been > like that since Java 1.0. Not crazily complex. A readInt/readDouble (or > whatever it is called) in SimpleIO can surely be the canonical inverse of > print/println. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Feb 21 22:39:45 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 21 Feb 2024 17:39:45 -0500 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> Message-ID: I will say, if we really want the input method, then it might make more sense if it was called prompt. And then, we can use input to just read a line from the user, and prompt to do the combination of writing a line and then reading a line. On Wed, Feb 21, 2024, 5:34?PM David Alayachew wrote: > I can agree with separating the 2 in input. It really helps separate > everything down to its primitives. > > I have confusion about the method reference. > > I tutored 100's of kids from middle schoolers up to post graduate college > students. Long story short, most post grads had only heard of method > references. Not a single college student I have ever tutored in college has > ever been taught about method references, let alone used it in a course. At > best, a student who is clearly leading the class decides to do it for fun, > since they aren't learning anything to begin with > > I am not saying the kids are the final say. I am saying that they are the > biggest portion of our target audience. And a vast majority of them will > not be able to make use of this. > > Putting aside the kids then, the new Java devs that are using this (who > also happen to know method references?) are likely not going to gain much > from the inclusion of this. At the end of the day, you are swapping a > method call with a method reference. What does the method reference give > you that you wouldn't get with a method call? > > > On Wed, Feb 21, 2024, 5:05?PM Stephen Colebourne > wrote: > >> I'd like to express basic agreement that reading and writing a string >> (and not more) is a good first API. But I also agree that it is >> potentially an on-ramp to nowhere. >> >> I'm also not at all happy with `input("How old are you? ")` which is >> doing two unrelated things (printing and reading a line) >> >> >> I'd like to throw out a left-field idea to the educators here - >> transformation via method reference. >> >> printLine("Enter your age"); >> int age = readLine(Integer::parseInt); >> >> Obviously a method reference lambda is not a simple thing to explain >> fully, but it is short and direct. Perhaps in the initial learning >> stages you can get away without explaining exactly how >> Integer::parseInt operates? >> >> Suggested API: >> public final class SystemIO { >> public static void printLine(Object obj) ... >> public static void print(Object obj) ... >> public static String readLine() throws UncheckedIOException ... >> public static T readLine(Function transformer) >> throws UncheckedIOException ... >> } >> >> Stephen >> >> >> On Tue, 20 Feb 2024 at 19:32, Cay Horstmann wrote: >> > >> > Hi R?mi, >> > >> > I am not bothered by the concepts that Scanner needs, because for me >> they are reasonable investments. As you point out, they are: >> > >> > * instance methods >> > * new >> > * import >> > >> > I would switch to a different approach if it (a) didn't introduce yet >> another fiddly special case (magic static import) and (b) wasn't >> unreasonably verbose. I would find this too painful: >> > >> > import java.util.SimpleIO; >> > >> > int age = Integer.parseInt(SimpleIO.input("How old are you? ")); >> > >> > I could embrace the magic static import if it was sufficiently general >> and useful to pay for the complexity. Hence my suggestion >> > >> > int age = parseInt(input("How old are you? ")); >> > >> > Or >> > >> > int age = readInt("How old are you? "); >> > >> > I need to make these decisions for the books and activities that I >> produce. As it is in the JEP today, I'd stick with Scanner. I would put in >> a note, just to signal that I know what is happening, that as of Java 25 >> (?), you can also use input, but that it relies on another fiddly rule, and >> it doesn't transfer to file I/O, so why bother... >> > >> > My sentiment is just a data point. I understand that the cost/benefit >> model is different for everyone. >> > >> > Cheers, >> > >> > Cay >> > >> > PS. I'd like to register a forceful pushback on "parsing numbers is so >> crazily complex that we can't possibly deal with it". What does >> print/println produce for numbers? Is it the crazily complex localized >> number format? No--only printf applies localization. The print/println >> methods format numbers as Java literals. That's a settled issue. It's been >> like that since Java 1.0. Not crazily complex. A readInt/readDouble (or >> whatever it is called) in SimpleIO can surely be the canonical inverse of >> print/println. >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hjohn at xs4all.nl Wed Feb 21 23:50:07 2024 From: hjohn at xs4all.nl (John Hendrikx) Date: Wed, 21 Feb 2024 23:50:07 +0000 Subject: SimpleIO in JEP draft 8323335 In-Reply-To: References: <69a5c417-4f37-4a94-a460-abedb2743791@horstmann.com> <80340842.10020329.1708345550943.JavaMail.zimbra@univ-eiffel.fr> <4da3d66f-69da-4f61-ac49-681d0b23766c@oracle.com> <2125294143.11242469.1708451968873.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Hopefully not overstepping bounds, but as naming goes, I think `SystemIO` is a bit too ambitious a name. For a class that interacts with the standard in and out streams, `StandardIO` seems a closer fit (although just like "System", "Simple" and "Basic", "Standard" is a very generic term that could mean almost anything). If purely intended for on-ramp without much use cases beyond that, then I would go with `BasicIO` to indicate it provides only basic functionality which you will grow out of. --John ------ Original Message ------ >From "Stephen Colebourne" To "amber-dev" Date 21/02/2024 23:04:48 Subject Re: SimpleIO in JEP draft 8323335 >I'd like to express basic agreement that reading and writing a string >(and not more) is a good first API. But I also agree that it is >potentially an on-ramp to nowhere. > >I'm also not at all happy with `input("How old are you? ")` which is >doing two unrelated things (printing and reading a line) > > >I'd like to throw out a left-field idea to the educators here - >transformation via method reference. > > printLine("Enter your age"); > int age = readLine(Integer::parseInt); > >Obviously a method reference lambda is not a simple thing to explain >fully, but it is short and direct. Perhaps in the initial learning >stages you can get away without explaining exactly how >Integer::parseInt operates? > >Suggested API: >public final class SystemIO { > public static void printLine(Object obj) ... > public static void print(Object obj) ... > public static String readLine() throws UncheckedIOException ... > public static T readLine(Function transformer) >throws UncheckedIOException ... >} > >Stephen > > >On Tue, 20 Feb 2024 at 19:32, Cay Horstmann wrote: >> >>Hi R?mi, >> >>I am not bothered by the concepts that Scanner needs, because for me they are reasonable investments. As you point out, they are: >> >>* instance methods >>* new >>* import >> >>I would switch to a different approach if it (a) didn't introduce yet another fiddly special case (magic static import) and (b) wasn't unreasonably verbose. I would find this too painful: >> >>import java.util.SimpleIO; >> >>int age = Integer.parseInt(SimpleIO.input("How old are you? ")); >> >>I could embrace the magic static import if it was sufficiently general and useful to pay for the complexity. Hence my suggestion >> >>int age = parseInt(input("How old are you? ")); >> >>Or >> >>int age = readInt("How old are you? "); >> >>I need to make these decisions for the books and activities that I produce. As it is in the JEP today, I'd stick with Scanner. I would put in a note, just to signal that I know what is happening, that as of Java 25 (?), you can also use input, but that it relies on another fiddly rule, and it doesn't transfer to file I/O, so why bother... >> >>My sentiment is just a data point. I understand that the cost/benefit model is different for everyone. >> >>Cheers, >> >>Cay >> >>PS. I'd like to register a forceful pushback on "parsing numbers is so crazily complex that we can't possibly deal with it". What does print/println produce for numbers? Is it the crazily complex localized number format? No--only printf applies localization. The print/println methods format numbers as Java literals. That's a settled issue. It's been like that since Java 1.0. Not crazily complex. A readInt/readDouble (or whatever it is called) in SimpleIO can surely be the canonical inverse of print/println. > From davidalayachew at gmail.com Sat Feb 24 06:52:55 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Sat, 24 Feb 2024 01:52:55 -0500 Subject: For JEP 330/458, is there anyway to separate output of compilation vs run? Message-ID: Hello Compiler/Amber Dev Team, For JEP 330 and 458 (Running Single and Multi file source code programs), is there any way to separate the output of compilation from the output of the run? And as a side question, how would one go about executing single/multi file source code programs programmatically? Thank you for your time and help! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Sun Feb 25 20:53:17 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Sun, 25 Feb 2024 15:53:17 -0500 Subject: For JEP 330/458, is there anyway to separate output of compilation vs run? In-Reply-To: References: Message-ID: I think I answered half of my question. It apoears that the way to do anything programmatically in Java is via ProcessBuilder (in the worst case), and then a handful of tools (jar, jlink, jpackage, etc.) have dedicated modules in the standard library provided via a ToolPprpvider that allow you to get a slightly more ergonomic grasp of the tool. Once you have that, executing the tasks programmatically is not hard. However, I don't see how to separate the compile text from the runtime text. Is that just something I miss out on by otpting into this feature? If so, I accept that, but would appreciate some confirmation so that I know that this is a dead end. On Sat, Feb 24, 2024, 1:52?AM David Alayachew wrote: > Hello Compiler/Amber Dev Team, > > For JEP 330 and 458 (Running Single and Multi file source code programs), > is there any way to separate the output of compilation from the output of > the run? > > And as a side question, how would one go about executing single/multi file > source code programs programmatically? > > Thank you for your time and help! > David Alayachew > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark.reinhold at oracle.com Wed Feb 28 20:04:05 2024 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Wed, 28 Feb 2024 20:04:05 +0000 Subject: New candidate JEP: 468: Derived Record Creation (Preview) Message-ID: <20240228200401.D42EB6C2F78@eggemoggin.niobe.net> https://openjdk.org/jeps/468 Summary: Enhance the Java language with derived creation for records. Records are immutable objects, so developers frequently create new records from old records to model new data. Derived creation streamlines code by deriving a new record from an existing record, specifying only the components that are different. This is a preview language feature. - Mark From sarma.swaranga at gmail.com Thu Feb 29 21:34:18 2024 From: sarma.swaranga at gmail.com (Swaranga Sarma) Date: Thu, 29 Feb 2024 13:34:18 -0800 Subject: Scope for JEP 468: Derived record creation Message-ID: The JEP looks really promising. However I am wondering if there will be a separate JEP for creating new records from scratch with similar syntax. The current JEP states that its goals are to enable creating records from an existing record and for that it seems sufficient. But I would also love to be able to create new records from scratch using the same syntax. Something like: var circle = new Circle with { radius = 0.5f; center = new Center with { x = 0; y = -1; z = 8; }; }; Originally I had asked Brian Goetz about record literals and they seemed like a possibility but withers seem like a more general feature so I am hoping something like this would be supported in the future. Regards Swaranga Sarma -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Feb 29 23:11:32 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 29 Feb 2024 18:11:32 -0500 Subject: Scope for JEP 468: Derived record creation In-Reply-To: References: Message-ID: <1e81bd77-6417-4018-8c23-1cef01f2e1f7@oracle.com> While such a feature is possible, I am not particularly excited about it for several reasons.? If the goal is "I want to construct using named instead of position arguments" (which I think is your goal), it's a pretty verbose syntax; a better one would be ??? new R(a: 1, b: 2) But that's a much smaller concern.? The bigger one is that I don't think the language is improved by having a named parameter mechanism for records, but for nothing else (not for instantiating class instances, not for invoking methods.)? While it might seem "better than nothing", having two different ways to do something, but one of them only works in narrow situations, is as likely to be frustrating than beneficial.? If the payoff is big enough, then it might be a possibility, but "invocation by parameter name" is nowhere near that bar. Finally, if it works for records but not for classes, it makes it harder to refactor from records to classes, since there will be use sites that have to be adjusted. So I think for the time being, the answer is "no", though if we run out of things to work on, we might reconsider. On 2/29/2024 4:34 PM, Swaranga Sarma wrote: > The JEP looks really promising. However I am wondering if there will > be a separate JEP for creating new records from scratch with similar > syntax. > > The current JEP states that its goals are to enable creating records > from an existing record and for that it seems sufficient. But I would > also love to be able to create new records from scratch using the same > syntax. Something like: > > var circle = new Circle with { > ? radius = 0.5f; > ? center = new Center with { > ??? x = 0; > ??? y = -1; > ??? z = 8; > ? }; > }; > > Originally I had asked Brian Goetz about record literals and they > seemed like a possibility but withers seem like a more general feature > so I am hoping something like this would be supported in the future. > > Regards > Swaranga Sarma -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Thu Feb 29 23:53:34 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Thu, 29 Feb 2024 18:53:34 -0500 Subject: Scope for JEP 468: Derived record creation In-Reply-To: <1e81bd77-6417-4018-8c23-1cef01f2e1f7@oracle.com> References: <1e81bd77-6417-4018-8c23-1cef01f2e1f7@oracle.com> Message-ID: This makes a lot of sense. Follow-up question - at one point, there was talks about letting mutable classes (even enums!) have a similar semantics to records, but not immutable. In the potential future where both are released, does this feature make more sense, potentially to reach escape velocity? And let me add that I promise this is not a solution looking for a problem, I am just trying to gauge the likeliness of a potential future. Out of curiosity. On Thu, Feb 29, 2024, 6:37?PM Brian Goetz wrote: > While such a feature is possible, I am not particularly excited about it > for several reasons. If the goal is "I want to construct using named > instead of position arguments" (which I think is your goal), it's a pretty > verbose syntax; a better one would be > > new R(a: 1, b: 2) > > But that's a much smaller concern. The bigger one is that I don't think > the language is improved by having a named parameter mechanism for records, > but for nothing else (not for instantiating class instances, not for > invoking methods.) While it might seem "better than nothing", having two > different ways to do something, but one of them only works in narrow > situations, is as likely to be frustrating than beneficial. If the payoff > is big enough, then it might be a possibility, but "invocation by parameter > name" is nowhere near that bar. > > Finally, if it works for records but not for classes, it makes it harder > to refactor from records to classes, since there will be use sites that > have to be adjusted. > > So I think for the time being, the answer is "no", though if we run out of > things to work on, we might reconsider. > > > On 2/29/2024 4:34 PM, Swaranga Sarma wrote: > > The JEP looks really promising. However I am wondering if there will be a > separate JEP for creating new records from scratch with similar syntax. > > The current JEP states that its goals are to enable creating records from > an existing record and for that it seems sufficient. But I would also love > to be able to create new records from scratch using the same syntax. > Something like: > > var circle = new Circle with { > radius = 0.5f; > center = new Center with { > x = 0; > y = -1; > z = 8; > }; > }; > > Originally I had asked Brian Goetz about record literals and they seemed > like a possibility but withers seem like a more general feature so I am > hoping something like this would be supported in the future. > > Regards > Swaranga Sarma > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: