Paving the on-ramp
Jim Laskey
james.laskey at oracle.com
Thu Sep 29 16:53:42 UTC 2022
Another safer approach we are playing with is to synthesize a public static void main method in an unnamed class when missing. The contents of that method would then invoke the user's main.
Cheers,
— Jim
On Sep 28, 2022, at 4:49 PM, Kevin Bourrillion <kevinb at google.com<mailto:kevinb at google.com>> wrote:
Virtuous.
The quips about horses having fled the barn are coming, but whether they did is irrelevant; let's just make Java better now.
On Wed, Sep 28, 2022 at 10:57 AM Brian Goetz <brian.goetz at oracle.com<mailto:brian.goetz at oracle.com>> wrote:
## Concept overload
I like that the focus is not just on boilerplate but on the offense of forcing learners to encounter concepts they *will* need to care about but don't yet.
- Relax the requirement that the class, and `main` method, be public. Public
accessibility is only relevant when access crosses packages; simple programs
live in the unnamed package, so cannot be accessed from any other package
anyway. For a program whose main class is in the unnamed package, we can
drop the requirement that the class or its `main` method be public,
effectively treating the `java` launcher as if it too resided in the unnamed
package.
Alternative: drop the requirement altogether. Most main methods have no desire to make themselves publicly callable as `TheClass.main(args)`, but today they are forced to expose that API anyway. I feel like it would still be conceptually clean to say that `public` is really about whether other *code* can access it, not whether a VM can get to it at all.
- Make the "args" parameter to `main` optional, by allowing the `java` launcher to
first look for a main method with the traditional `main(String[])`
signature, and then (if not found) for a main method with no arguments.
This seems to leave users vulnerable to some surprises, where the code they think is being called isn't. Why not make it a compile-time error to provide both forms?
- Make the `static` modifier on `main` optional, by allowing the `java` launcher to
invoke an instance `main` method (of either signature) by instantiating an
instance using an accessible no-arg constructor and then invoking the `main`
method on it.
I'll give the problems I see with this, without a judgement on what should be done.
What's the whole idea of main? Well, it's the entry point into the program. But now it's not really the entry point; finding the entry point is more subtle. (Okay, I concede that static initializers are run first either way; that undercuts *some* of the strength of my argument here.)
Even if this is okay when I'm writing my own new program, understanding it as I go, then suppose someone else reads my program. That person has the burden of remembering to check whether `main` is static or not, and remembering that some constructor code is happening first if it's not. Classes that have both main and a constructor will be a mixture of some that call them in one order and some in the other. That's just, like, messy.
And is it even clear, then, why the VM shouldn't be passing `args` to the constructor, only hoarding it until calling `main`?
On a deep conceptual level... I'd insist that main() *is static*. It is *the* single entry point into the program; what could be more static than that? But thinking about our learner, who wrote some `main`s before learning about static. The instant they learn `static` is a keyword a method can have, they'll "know" one thing about it already: this is going to be something new that's *not* true of main(). But then they hear an explanation that fits `main` perfectly?
Because excessive use of `static` is considered a code smell, many
educators encourage the pattern of "all the static `main` method does is
instantiate an instance and call an instance `main` method" anyway.
Heavy groan. In my opinion, some ideas are too misguided to take seriously.
The value in that practice is if instance `main` accepts parameters like `PrintStream` and `Console`, and static main passes in `System.out` and `System.console()`. That makes all your actual program logic unit-testable. Great! This actually strikes directly at the heart of what the entire problem with `static` is! But this isn't the case you're addressing.
Static methods are not a code smell! Static methods that ought to be overrideable by one of their argument types (Collections.sort()), sure. Static mutable state is a code smell, definitely -- but a method that touches that state is equally problematic whether it itself is static or not. There are some code smells around `static`, but `static` itself is fresh and flowery.
(Further, allowing the `main` method to be an instance method
means that it could be inherited from a superclass, which is useful for simple
frameworks such as test runners or service frameworks.)
This does not give me a happy feeling. Going into it is a deep discussion though.
Rest of the response coming soon, I hope.
Just to mention one additional idea. We could permit `main` to optionally return `int`, becoming the default exit status if `exit` is never called. Seems elegant for the rare cases where you care about exit status, but (a) would this feature get in the way in *any* sense for the vast majority of cases that don't care, or (b) are the cases that care just way too rare for us to worry about?
I'm not sure about (a). But (b) kinda seems like a yes.
--
Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com<mailto:kevinb at google.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20220929/535bee65/attachment-0001.htm>
More information about the amber-spec-observers
mailing list