Do we really need an implicit "import static java.io.IO.*"?

Ethan McCue ethan.mccue at lumanu.com
Sat Jun 1 22:14:08 UTC 2024


Hi all,

I'm following the development of JEP 477[1] and I feel the need to question
the impetus for the implicit static imports.

As of now[2] any program like this

void main() {
    println("Hello, world");
}

Is equivalent to

import static java.io.IO.print;
import static java.io.IO.println;
import static java.io.IO.writeln;

import module java.base;

final class Main {
    void main() {
        println("Hello, world");
    }
}

Where all the methods in java.io.IO delegate to newly added equivalent
methods in java.io.Console.[3]

Aside from muddying that API up (now there is readln and readLine + println and
printLine which...what) I'm still concerned on how those implicit imports
will affect the transition to named classes.

Assume we start a student out here

void main() {
    println("Hello, world");
}

You can get through conditionals, loops, variables, methods, and return
types before touching classes or access specifiers.

int compute() {
    int total = 0;
    for (int i = 0; i < 10; i++) {
        total += i;
    }
    return total;
}

void main() {
    println("Hello: " + compute());
}

You can even talk about records and enums in a hand wavey way. Enums are
"one of these options", Records are "if you want to return two things."

enum Pirate {
   BLACKBEARD,
   OTHER
}

record Pos(int x, int y) {}

Pos treasure(Pirate pirate) {
    switch (pirate) {
        case BLACKBEARD ->
            return new Pos(5, 5);
        case OTHER ->
            return new Pos(0, 0);
    }
}

void main() {
    println(treasure(Pirate.OTHER));
}

So it is reasonable for a student to have made a relatively complex program
before having to get to that point, but I think you do need to explain what
exactly is going on with the anonymous main class when you introduce multi
file programs.

As originally pitched, this transition would have just meant wrapping the
whole program in class Main {}, but now to make the transition from

void main() {
    // Arbitrary code
}

to

class Main {
    void main() {
        // Arbitrary code
    }
}

In a robust way, you need to add those imports to the top. You can skip the
final since the semantics of extension haven't been relevant yet.

import static java.io.IO.*;

import module java.base;

class Main {
    void main() {
        // Arbitrary code
    }
}

My gripe is that the concepts introduced here - static, module, and *
imports  - would have had no place to be introduced earlier.

If you have folks write static methods on inner classes, the metaphor of a
"global field" that otherwise exists in the simple-main world goes away.

// For every program up until this, they could freely access this from
anywhere
int count = 0;

// And they could freely make an instance of any inner class
class Other {}

class Pos {
    static Pos of(int x, int y) {
        // So the rules they are used to don't apply anymore
        // and the explanation as to why really lies *after* they understand
        // what an anonymous main class is and does
        // ...
    }
}

void main() {
   // ...
}

If you have folks *use* static methods that is fine - the hand-waving of
Math.max doesn't seem to trip anyone up - but I can't figure out how to
topologically sort topics such that import static makes any sense before
going through multi-file programs.

I have a similar concern with import module, but that can be hand waved as
"gets you everything from this library" so I am less concerned. Still don't
fully understand the desire to have it be implicit, but less concerned.

Just as a hypothetical, say java.io.IO was java.lang.IO. No new import
rules needed and now IO is available to all programs.

void main() {
    IO.printLine("Hello, world");
}

While this does introduce something not explained - static method access -
it feels easier to hand-wave away than import static java.io.IO.*; would
be. It calls the printLine method, it comes from IO. IO means
"Input/Output". That's a workable metaphor and can be glanced over in the
same way as Math.max

The transition from here to classes can again be "it's the same as if you
had class Main {} around it" instead of "it's the same as if you had class
Main {} around it and these imports. A static import imports a static
method. A static method is a method attached to the class itself instead of
the instance.... etc."

Also, IO. feels like a different kind of unexplained boilerplate than public
static void main(String[] args) {}. There is a lot of ground you need to
cover before access modifiers, static methods, or command line arguments
make any sort of sense. When you have someone write IO they are in that
moment producing output and will soon take input.

What am I overlooking?


[1]: https://openjdk.org/jeps/477
[2]:
https://download.java.net/java/early_access/jdk23/docs/api/java.base/java/io/IO.html
[3]
https://download.java.net/java/early_access/jdk23/docs/api/java.base/java/io/Console.html#print(java.lang.Object)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240601/e06c8687/attachment.htm>


More information about the amber-dev mailing list