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 
<[email protected]<mailto:[email protected]>> 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 
<[email protected]<mailto:[email protected]>> 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. | 
[email protected]<mailto:[email protected]>

Reply via email to