- 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.
I think we're saying the same thing; main need not be public.
- 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?
Currently, the treatment of methods called "main" is "and also"; it is a
valid method, *and also* (if it has the right shape) can be used as a
main entry point. Making this an error would take some valid programs
and make them invalid, which seems a shift in the interpretation of the
magic name "main". A warning is probably reasonable though.
- 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.
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?
John likes to say "static has messed up every job we've ever given it",
and while that seems an exaggeration at first, often turns out to be
surprisingly accurate. One subtle thing it messes up here is that one
cannot effectively inherit a main() method. But inheriting main() is
super useful! Consider a TestCase class in a test framework, or an
AbstractService class in a services framework. If the abstract class
can provide the main() method, then every test case or service _is also
a program_, one which runs that test case or service.
But, there is cheese-moving here. In the old model, "main" is just a
disembodied method, which only accidentally lives in a class, and drags
the class along for the ride. In this model, main-ness moves up the
stack, becoming a property of a class, not just something a class has.
This tension is evident in JLS 12, which defines the interaction with
main. It is full of wiggle words, because it is trying to pretend that
Java has no concept of "program", just classes, but at the same time,
there has to be a way to get the computation started. The JLS tries to
pretend that "program" is defined almost extralinguistically (by appeal
to an unspcified launcher program that exists outside of the language),
but nearly trips over its own feet trying to have it both ways.
The debate among educators about whether main should be allowed to do
anything it wants, or should only instantiate an object and call a
single method, illustrates this tension. So what is really going on
here is bringing the notion of "program" to classes in a less
nailed-on-the-side way.
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.
Considered this (since C lets you do this.) Since Java doesn't let you
overload on return types, we have the option to do this later without
making the search order any more complicated, so I left it out.