JDK-8331610 : Implement java.io.IO
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.io
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 23
  • Submitted: 2024-05-02
  • Updated: 2024-06-18
  • Resolved: 2024-05-21
Related Reports
CSR :  
Relates :  
Description
Summary
-------

Create a class containing static methods, suitable for static import, that provide a convenient way to perform I/O operations.

Problem
-------

Printing a line requires the code `System.out.println` which is somewhat verbose and which raises a bunch of questions from beginning programmers. A simple method invocation like `println` would be preferable.

Reading a line of input from the user is considerably more painful. It requires wrapping `System.in` inside an `InputStreamReader` within a `BufferedReader`, and it also requires exception handling. Using `java.io.Console` avoids some of this, but it raises other issues. For example,  the console can be `null`, so this case needs to be handled. Again, it would be preferable to have a simple method invocation such as `readln`. In addition, this method should allow prompting the user for input, and it should allow advanced editing (cursor navigation and character insertion and deletion at locations other than the end of the current line).

See [JEP 477](https://openjdk.org/jeps/477) for more discussion and context regarding automatic static import for implicit classes.

Solution
--------

Create a new public class `java.io.IO` that contains the following methods:

    public static void println(Object obj)
    public static void print(Object obj)
    public static String readln(String prompt)

These methods invoke the corresponding instance methods on the Console instance returned by `System.console()`, or else they throw `IOError` if `System.console()` returns `null`.

Add the following instance methods to the `java.io.Console` class:

    public Console println(Object obj)
    public Console print(Object obj)
    public String readln(String prompt)

The `print` and `println` methods do the straightforward thing of printing the String representation of the argument, obtained as if by `String.valueOf(obj)`, with or without printing a trailing newline, respectively. The `readln` method writes the prompt string to the console and then reads a line of input from the console. The `Console` class already has existing methods that perform similar functions, however, they use string formatting instead of plain strings. Also note that the `Console` printing methods return `Console` whereas the `IO` static methods return `void`, as method chaining isn't useful for static methods.

The `java.io.Console` class is used because prompting and interactive editing require close coordination between the input and output. Reading prompted input includes flushing at the right time and performing terminal control operations such as cursor motion and character insertion/deletion. This is not possible if independent utility methods were layered on top of `System.in` and `System.out`.

The intent is to introduce `readln` as a common method name for reading a line of text. Retrofitting other classes such as `BufferedReader` that allow line reading will be handled separately.

Specification
-------------

The specification consists of:

 - three new methods added to `java.io.Console`
 - a new class, called `java.io.IO`, with the three wrapper methods around those new `Console` methods

For details see the attached diff.
Comments
Moving updated request to Approved.
21-05-2024

Summary of specifications changes compared to earlier spec drafts (available in the PR). Mostly minor tweaks: - `java.io.IO` is now final - clarify that `null` is allowed in certain places - specify that `Console`'s charset is used for input and output - specify use of `System.lineSeparator()` Moving to Finalized.
14-05-2024

Updated specification by adding diff2.txt
14-05-2024

[~prappo], for future reference, please leave old attachments and add new ones so the CSR can serve as an archive of the evolution of the proposal.
09-05-2024

Updated diff.txt
09-05-2024

There was an extensive discussion about the names to be used for these methods. Considering APIs already in the JDK: there is `println` on a variety of classes, but no `printLine`. It seemed quite sensible to stick with `print` and `println` because their use is already well established in the JDK, and there are no technical problems with adding these convenience methods. For reading, there is no `readln` in the JDK but there are a couple different flavors of `readLine`. Unfortunately the `readLine` methods on things like `BufferedReader` differ from those on `Console` in that the former only reads whereas the latter emits a prompt before reading. Doubly unfortunately, the `Console.readLine` method *formats* its string and additional arguments whereas we want a version that takes a single argument, a simple string, as a prompt. This makes adding a simple-string `readLine` overload to Console unpalatable. An alternative name `input` was proposed but this was rejected as it's without precedent in the JDK, though other platforms use this name. We settled on `readln` because of its symmetry with `println` which already enjoys long-standing use. This symmetry will be especially pleasant in programs written by beginners, which we expect to make extensive use of `println` and `readln`. This new name does set a precedent though, as there is currently no use of `readln` in the JDK. To strengthen this name, we are considering adding `readln` aliases for `readLine` in other places such as `BufferedReader`.
07-05-2024

Naming bikeshed: are names like "`readLine`" and "`printLine`" better for the intended usage the historical "`readln`" and "`println`"? There is some existing usage of "print", "println", and "readln" in the JDK API, but I don't think anything that would conflict under the intended `import` scheme.
07-05-2024

Moving to Provisional, not Approved. The description of the operational semantics of the methods in the IO class would be appropriate for implSpec tags, but has the methods aren't overridable, it doesn't make too much difference. Perhaps usage of implSpec was avoided to keep the displayed javadoc more straightforward? Per forthcoming changes in Console (JDK-8330536), I think having some mention of Locale at the class-level would be appropriate, but perhaps that is being avoided to simplify the presentation.
07-05-2024

Given that the new methods on `java.io.IO` are simply convenience methods around other APIs, it's difficult for their definitions to avoid operational semantics. The main advantage of this is to reuse the specifications from those other methods without repeating them here. We don't want to repeat the specifications here, because if those other methods' specifications are refined, we'll want the `java.io.IO` methods' specifications to track those changes. The `java.io.IO` specifications aren't "implementation specifications" in the same sense as `@implSpec` in that specific logic and method calls aren't required. The specifications use the "as if by" wording to refer to the specifications of other methods (such as `String.valueOf`) without requiring those methods actually to be called. The Locale-based changes to Console (JDK-8330536) apply only to methods that support formatted output, for example, numeric formatting provided by the `%f` conversion. Those considerations don't apply to `java.io.IO`, as the methods here use only plain strings, not formatting. Console itself doesn't have a locale. It has an encoding though, which is revealed by the `Console.encoding()` method. The `java.io.IO` methods implicitly use the same encoding as the system's Console instance. I can add some wording around this if it's helpful.
07-05-2024