<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4" face="monospace">Your vote for "let's not do this at
      all" is hereby recorded!<br>
    </font><br>
    <div class="moz-cite-prefix">On 2/20/2024 10:41 AM, Cay Horstmann
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:4c93ef42-7f1b-4377-9165-c4c1f4c91139@gmail.com">Actually,
      that's not quite what I am saying.
      <br>
      <br>
      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.
      <br>
      <br>
      On 20/02/2024 15.34, Brian Goetz wrote:
      <br>
      <blockquote type="cite">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.
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
        <br>
        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.
        <br>
        <br>
        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?
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        On 2/20/2024 6:44 AM, Cay Horstmann wrote:
        <br>
        <blockquote type="cite">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.
          <br>
          <br>
          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.
          <br>
          <br>
          For my books, I need to decide what to do in the (n + 1)st
          edition. Should I stick with
          <br>
          <br>
          Scanner in = new Scanner(System.in);
          <br>
          ...
          <br>
          System.out.print("How old are you? ");
          <br>
          int age = in.nextInt();
          <br>
          <br>
          or switch to
          <br>
          <br>
          println("How old are you?");
          <br>
          int age = in.nextInt();
          <br>
          <br>
          or go all the way to
          <br>
          <br>
          int age = Integer.parseInt(input("How old are you"));
          <br>
          <br>
          I have no conceptual problem with in.nextInt(). I need to
          explain method calls early on, so that students can work with
          strings.
          <br>
          <br>
          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.
          <br>
          <br>
          As Brian says, there are too many conflicting goals.
          <br>
          <br>
          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.
          <br>
          <br>
          If the goal is convenience, it would be better to have more
          magically statically imported methods, in particular parseInt,
          parseDouble. Or readAnInt, readADouble...
          <br>
          <br>
          Cheers,
          <br>
          <br>
          Cay
          <br>
          <br>
          <br>
          On 19/02/2024 18.06, Brian Goetz wrote:
          <br>
          <blockquote type="cite">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.")
            <br>
            <br>
            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.
            <br>
            <br>
            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!
            <br>
            <br>
            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.)
            <br>
            <br>
            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.
            <br>
            <br>
                 String s = getALine();
            <br>
                 printALine(s);
            <br>
            <br>
            is a program every student can reason about.
            <br>
            <br>
            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.)
            <br>
            <br>
            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.
            <br>
            <br>
            Remi has it absolutely right (yes, I really said that) with
            <br>
            <br>
            <blockquote type="cite">The classical program is:
              <br>
                 input -> strings -> objects -> strings ->
              output
              <br>
            </blockquote>
            <br>
            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.
            <br>
            <br>
            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.
            <br>
            <br>
            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.
            <br>
            <br>
            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.
            <br>
            <br>
            <br>
            On 2/19/2024 7:25 AM, Remi Forax wrote:
            <br>
            <blockquote type="cite">I agree with Brian here,
              <br>
              as a teacher, you have to talk about parsing and
              formatting, those should not be hidden.
              <br>
              <br>
              The classical program is:
              <br>
                 input -> strings -> objects -> strings ->
              output
              <br>
              <br>
              Rémi
              <br>
              <br>
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
              <br>
              <br>
                  *From: *"Tagir Valeev" <a class="moz-txt-link-rfc2396E" href="mailto:amaembo@gmail.com"><amaembo@gmail.com></a>
              <br>
                  *To: *"Cay Horstmann" <a class="moz-txt-link-rfc2396E" href="mailto:cay@horstmann.com"><cay@horstmann.com></a>
              <br>
                  *Cc: *"Brian Goetz" <a class="moz-txt-link-rfc2396E" href="mailto:brian.goetz@oracle.com"><brian.goetz@oracle.com></a>,
              "amber-dev" <a class="moz-txt-link-rfc2396E" href="mailto:amber-dev@openjdk.org"><amber-dev@openjdk.org></a>
              <br>
                  *Sent: *Monday, February 19, 2024 10:09:35 AM
              <br>
                  *Subject: *Re: SimpleIO in JEP draft 8323335
              <br>
              <br>
                  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.
              <br>
                  With best regards,
              <br>
                  Tagir Valeev.
              <br>
              <br>
                  On Mon, Feb 19, 2024 at 9:10 AM Cay Horstmann
              <a class="moz-txt-link-rfc2396E" href="mailto:cay@horstmann.com"><cay@horstmann.com></a> wrote:
              <br>
              <br>
                      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.
              <br>
              <br>
                      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))?
              <br>
              <br>
                      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))?
              <br>
              <br>
                      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.)
              <br>
              <br>
                      On 18/02/2024 23.08, Brian Goetz wrote:
              <br>
                      > OK, so is this really just that that you are
              bikeshedding the name?  Renaming `input` to `readLine`?
              <br>
                      >
              <br>
                      > This is a perfectly reasonable naming choice,
              of course, but also, not what you suggested the first time
              around:
              <br>
                      >
              <br>
                      >  > ... "a third API" ...
              <br>
                      >
              <br>
                      >  > ... "there are two feasible directions"
              ...
              <br>
                      >
              <br>
                      > So what exactly are you suggesting?
              <br>
                      >
              <br>
                      >
              <br>
                      >
              <br>
                      > On 2/18/2024 5:03 PM, Cay Horstmann wrote:
              <br>
                      >> Like I said, either the scanner methods
              or the console methods are fine.
              <br>
                      >>
              <br>
                      >> 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.
              <br>
                      >>
              <br>
                      >> You don't have to "get a console". A
              SimpleIO.readLine method can just invoke readLine on the
              system console.
              <br>
                      >>
              <br>
                      >> 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.
              <br>
                      >>
              <br>
                      >> On 18/02/2024 22.43, Brian Goetz wrote:
              <br>
                      >>> I think you are counting characters
              and not counting concepts.
              <br>
                      >>>
              <br>
                      >>> 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.
              <br>
                      >>>
              <br>
                      >>> 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.
              <br>
                      >>>
              <br>
                      >>> 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.
              <br>
                      >>>
              <br>
                      >>> On 2/18/2024 4:12 PM, Cay Horstmann
              wrote:
              <br>
                      >>>> I would like to comment on the
              simplicity of <a class="moz-txt-link-freetext" href="https://openjdk.org/jeps/8323335">https://openjdk.org/jeps/8323335</a> for
              beginning students.
              <br>
                      >>>>
              <br>
                      >>>> 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
              <br>
                      >>>>
              <br>
                      >>>> System.out.print("How old are
              you? ");
              <br>
                      >>>> int x = in.nextInt(); // in is a
              Scanner
              <br>
                      >>>>
              <br>
                      >>>> than
              <br>
                      >>>>
              <br>
                      >>>> int x =
              Integer.parseInt(console.readLine("How old are you? "));
              <br>
                      >>>>
              <br>
                      >>>> or with the JEP draft:
              <br>
                      >>>>
              <br>
                      >>>> int x =
              Integer.parseInt(input("How old are you? "));
              <br>
                      >>>>
              <br>
                      >>>> 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.
              <br>
                      >>>>
              <br>
                      >>>> But why have a third API, i.e.
              "input"?
              <br>
                      >>>>
              <br>
                      >>>> 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.
              <br>
                      >>>>
              <br>
                      >>>> Cheers,
              <br>
                      >>>>
              <br>
                      >>>> Cay
              <br>
                      >>>>
              <br>
                      >>>> --
              <br>
                      >>>>
              <br>
                      >>>> Cay S. Horstmann |
<a class="moz-txt-link-freetext" href="https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$">https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IuXZk_tqIH8rEw1bD3uYb8UcIZF-nnoeFT3UG17pMO5EVXIYVRaAKi7XCq_T02HwnAek1wuV8Wed08w$</a>
              | <a class="moz-txt-link-freetext" href="mailto:cay@horstmann.com">mailto:cay@horstmann.com</a>
              <br>
                      >>>
              <br>
                      >>
              <br>
                      >
              <br>
              <br>
                      --
              <br>
                      --
              <br>
              <br>
                      Cay S. Horstmann |
<a class="moz-txt-link-freetext" href="https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$">https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!JDq2P0DR423V62MvLF-CBrjfMSFshyy9lkQdQQPt5aEojp3WbQriYDtG-00NepYgsFay4aXHAQFHA24$</a>
<a class="moz-txt-link-rfc2396E" href="https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IZrLgaQxOHBjUURoC5mWbfsijev257bb4C0DMamUDpoGqS5JMACpaMKsbUNQlWcGds7fifmS9sARC6aKMHEf$"><https://urldefense.com/v3/__http://horstmann.com__;!!ACWV5N9M2RV99hQ!IZrLgaQxOHBjUURoC5mWbfsijev257bb4C0DMamUDpoGqS5JMACpaMKsbUNQlWcGds7fifmS9sARC6aKMHEf$></a>
              | <a class="moz-txt-link-freetext" href="mailto:cay@horstmann.com">mailto:cay@horstmann.com</a>
              <br>
              <br>
              <br>
            </blockquote>
            <br>
          </blockquote>
          <br>
        </blockquote>
        <br>
      </blockquote>
      <br>
    </blockquote>
    <br>
  </body>
</html>