<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<font size="4"><font face="monospace">This was received today on the
-comments list; Stephen has an alternate proposal for the
on-ramp, making "entry points" (programs) a first class
concept. <br>
<br>
This proposal is actually three proposals in one, which are
actually pretty separable: <br>
<br>
- A syntax-heavy proposal for "entrypoints";<br>
- An alternate way to address console IO, with new classes for
SystemOut rather than new static functionality; <br>
- A further evolution on the "instance main" notion to use an
interface to identify the "instance main" entry point, rather
than extending the existing structural recognition.<br>
<br>
I will mostly speak to the first of these. The second is
completely orthogonal (it is not essential to this proposal, and
could be taken separately without dragging in anything else).
This is largely an API design question, and can be discussed
when we get to how to best expose new functionality for console
IO. The third has been mentioned on the EG list already, that
"instance main" is an opportunity to switch to something more
nominal. I'll come back to this later in this mail. <br>
<br>
</font></font><font size="4"><font face="monospace"><br>
To the main part of this proposal, I explored several similar
points in my internal exploration (including also a
method-centric version of the same basic split), prior to
publishing my "On Ramp" document. (Spoiler: ultimately I didn't
feel these approaches carried their weight.)<br>
<br>
In its favor, the proposal is principled: that of all the
concepts that we ask users to confront in Hello World that have
syntactic representations, perhaps the most important one for
the situation at hand -- a *program* -- doesn't even have a
syntactic representation in the program. Java takes the
worse-is-better approach here of saying "a program is just a
class with a main method." This is a pragmatic tradeoff, but it
means that in the big list of concepts that users are confronted
with, we are not able to whittle it down to zero -- users still
have to confront methods (and their affordances such as return
types and parameter lists.) There's still a conceptual gap
here, because these affordances largely support invoking methods
(which the user has not yet learned about), but somehow the
"main" method gets called magically by the launcher. I spent
some time exploring whether we could remove these last things
from the list, but concluded that the juice was not worth the
squeeze. <br>
<br>
Stephen approaches this by a classic "split" move -- split
methods into two kinds: "main" methods and "regular" ones, </font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">giving special syntax</font></font> to the
new thing, and then adopting a similar "unnamed classes"
approach for classes with a main method. This splitting is
motivated by several forces: that a "program" is an important
concept to represent, and that the current treatment of "main"
in the language is frustratingly structural in a language where
nearly everything else is nominal. <br>
<br>
I sympathize with the concern that "main-ness" is too magic;
when I learned Java 25+ years ago, among my first reactions was
"but where's the program". That a Java program is merely a soup
of classes loosely contained by tooling switches or environment
variables, and a program could have as many "main" entry points
as it has classes, does take some getting used to (though less
now than it did then, when linkers roamed the earth.) And I
sympathize with the desire to fix the mistakes of the past. But
I think that the "entrypoint" proposal strikes the wrong
balance. It has way too much new surface syntax, while at the
same time, leaving the existing static main protocol flapping in
the breeze. Given where we are, I don't see it as carrying its
weight. Stephen thinks it is "better bang for buck", but I
disagree, not necessarily because of the bang part, but the buck
part -- it is dramatically more expensive in all the dimensions
(spec, syntax, user perception, implementation cost, etc). <br>
<br>
The two sub-proposals are more compelling, and both are sure to
play into the discussions to come in any case. New classes vs
new static entry points is a totally valid API design discussion
to have. Similarly, with the addition of "instance main", it is
a totally sensible question to ask whether we want to extend the
existing structural recognition of main methods to the new
thing, or break from that and use interfaces. Both approaches
have pros and cons, and we can discuss those. <br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
</font></font>
<div class="moz-forward-container"><br>
<br>
-------- Forwarded Message --------
<table class="moz-email-headers-table" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<th valign="BASELINE" nowrap="nowrap" align="RIGHT">Subject:
</th>
<td>Java on-ramp - Class declaration for Entrypoints</td>
</tr>
<tr>
<th valign="BASELINE" nowrap="nowrap" align="RIGHT">Date: </th>
<td>Thu, 6 Oct 2022 12:27:06 +0100</td>
</tr>
<tr>
<th valign="BASELINE" nowrap="nowrap" align="RIGHT">From: </th>
<td>Stephen Colebourne <a class="moz-txt-link-rfc2396E" href="mailto:scolebourne@joda.org"><scolebourne@joda.org></a></td>
</tr>
<tr>
<th valign="BASELINE" nowrap="nowrap" align="RIGHT">To: </th>
<td><a class="moz-txt-link-abbreviated" href="mailto:amber-spec-comments@openjdk.java.net">amber-spec-comments@openjdk.java.net</a></td>
</tr>
</tbody>
</table>
<br>
<br>
Hi all,<br>
I wrote up my response to the on-ramp discussion as a blog post
having<br>
given it a few days thought:<br>
<br>
<a class="moz-txt-link-freetext" href="https://blog.joda.org/2022/10/fully-defined-entrypoints.html">https://blog.joda.org/2022/10/fully-defined-entrypoints.html</a><br>
<br>
I think what I've come up with is a lot more powerful, more useful
to<br>
experienced developers, and more consistent during the learning<br>
process. It is, of course, a bigger change.<br>
<br>
This email to amber-spec-comments reads the idea into the
legal-world<br>
of OpenJDK..<br>
<br>
thanks<br>
Stephen<br>
<br>
<br>
<h4>Entrypoints</h4><br>
<p><br>
When a Java program starts some kind of class file needs to be
run.<br>
It could be a normal <code>class</code>, but that
isn't ideal as we<br>
don't really want static/instance variables, subclasses, parent<br>
interfaces, access control etc.<br>
One suggestion was for it to be a normal
<code>interface</code>, but<br>
that isn't ideal as we don't want to mark the methods as<br>
<code>default</code> or allow
<code>abstract</code> methods.<br>
</p><br>
<p><br>
I'd like to propose that what Java needs is a <b>new kind of
class<br>
declaration for entrypoints</b>.<br>
</p><br>
<p><br>
I don't think this is overly radical. We already have two
alternate<br>
class declarations - <code>record</code> and
<code>enum</code>. They<br>
have alternate syntax that compiles to a class file without being<br>
explictly a <code>class</code> in source code.<br>
What we need here is a new kind -
<code>entrypoint</code> - that<br>
compiles to a class file but has different syntax rules, just like<br>
<code>record</code> and <code>enum</code>
do.<br>
</p><br>
<p><br>
I believe this is a fundamentally better approach than the minor<br>
tweaks in the official proposal, because it will be useful to<br>
developers of all skill levels, including framework authors.<br>
ie. it has a much better "bang for buck".<br>
</p><br>
<p><br>
The simplest entrypoint would be:<br>
</p><br>
<pre><br>
// MyMain.java<br>
entrypoint {<br>
SystemOut.println("Hello World");<br>
}<br>
</pre><br>
<p><br>
In the source code we have various things:<br>
</p><br>
<ul><br>
<li>Inferred class name from file name, the class file is<br>
<code>MyMain$entrypoint</code></li><br>
<li>Top-level code, no need to discuss methods
initially</li><br>
<li>No access to paraneters</li><br>
<li>New classes <code>SystemOut</code>,
<code>SystemIn</code> and<br>
<code>SystemErr</code></li><br>
<li>No constructor, as a new kind of class declaration it
doesn't need it</li><br>
</ul><br>
<p><br>
The classes like <code>SystemOut</code> may seem like
a small<br>
change, but it would have been much simpler for me from 25 years
ago<br>
to understand.<br>
I don't favour more static imports for them (either here or more<br>
generally), as I think <code>SystemOut.println("Hello
World")</code><br>
is simple enough.<br>
More static imports would be too magical in my opinion.<br>
</p><br>
<p><br>
The next steps when learning Java are for the instructor to expand<br>
the entrypoint.<br>
</p><br>
<ul><br>
<li>Add a named method (always private, any name although<br>
<code>main()</code> would be common)</li><br>
<li>Add parameters to the method (maybe String[], maybe
String...)</li><br>
<li>Add return type to the method (void is default return
type)</li><br>
<li>Group code into a block</li><br>
<li>Add additional methods (always private)</li><br>
</ul><br>
<p><br>
Here are some valid examples. Note that instructors can choose the<br>
order to explain each feature:<br>
</p><br>
<pre><br>
entrypoint {<br>
SystemOut.println("Hello World");<br>
}<br>
entrypoint main() {<br>
SystemOut.println("Hello World");<br>
}<br>
entrypoint main(String[] args) {<br>
SystemOut.println("Hello World");<br>
}<br>
entrypoint {<br>
main() {<br>
SystemOut.println("Hello World");<br>
}<br>
}<br>
entrypoint {<br>
void main(String[] args) {<br>
SystemOut.println("Hello World");<br>
}<br>
}<br>
entrypoint {<br>
main(String[] args) {<br>
output("Hello World");<br>
}<br>
output(String text) {<br>
SystemOut.println(text);<br>
}<br>
}<br>
</pre><br>
<p><br>
Note that there are never any static methods, static variables,<br>
instance variables or access control. If you need any of that you
need<br>
a class.<br>
Thus we have proper separation of concerns for the entrypoint of<br>
systems, which would be Best Practice even for experienced
developers.<br>
</p><br>
<br>
<br>
<h4>Progressing to classes</h4><br>
<p><br>
During initial learning, the entrypoint class declaration and
normal<br>
class declaration would be kept in separate files:<br>
</p><br>
<pre><br>
// MyMain.java<br>
entrypoint {<br>
SystemOut.println(new Person().name());<br>
}<br>
// Person.java<br>
public class Person {<br>
String name() {<br>
return "Bob";<br>
}<br>
}<br>
</pre><br>
<p><br>
However, at some point the instructor would embed an entrypoint
(of<br>
<b>any</b> valid syntax) in a normal
<code>class</code>.<br>
</p><br>
<pre><br>
public class Person {<br>
entrypoint {<br>
SystemOut.println(new Person().name());<br>
}<br>
String name() {<br>
return "Bob";<br>
}<br>
}<br>
</pre><br>
<p><br>
We discover that an <code>entrypoint</code> is
normally wrapped in a<br>
<code>class</code> which then offers the ability to
add<br>
static/instance variables and access control.<br>
</p><br>
<p><br>
Note that since all methods on the entrypoint are private and the<br>
entrypoint is anonymous, there is no way for the rest of the code
to<br>
invoke it without hackery.<br>
Note also that the entrypoint does not get any special favours
like<br>
an instance of the outer class, thus there is no issue with no-arg<br>
constructors - if you want an instance you have to use<br>
<code>new</code> (the alternative is unhelpful magic
that harms<br>
learnability IMO).<br>
</p><br>
<p><br>
Finally, we see that our old-style static main method is revealed
to<br>
be just a normal entrypoint:<br>
</p><br>
<pre><br>
public class Person {<br>
entrypoint public static void main(String[] args) {<br>
SystemOut.println(new Person().name());<br>
}<br>
String name() {<br>
return "Bob";<br>
}<br>
}<br>
</pre><br>
<p><br>
ie. when a method is declared as <code>public static void<br>
main(String[])</code> the keyword
<code>entrypoint</code> is<br>
implicitly added.<br>
</p><br>
<p><br>
What experienced developers gain from this is a clearer way to<br>
express what the entrypoint actually is, and more power in
expressing<br>
whether they want the command line arguments or not.<br>
</p><br>
<br>
<br>
<h4>Full-featured entrypoints</h4><br>
<p><br>
Everything above is what most Java developers would need to know.<br>
But an entrypoint would actually be a whole lot more powerful.<br>
</p><br>
<p><br>
The basic entrypoint would compile to a class something like this:<br>
</p><br>
<pre><br>
// MyMain.java<br>
entrypoint startHere(String[] args) {<br>
SystemOut.println("Hello World");<br>
}<br>
// MyMain$entrypoint.class<br>
public final MyMain$entrypoint implements java.lang.Entrypoint {<br>
@Override<br>
public void main(Runtime runtime) {<br>
runtime.execute(() -> startHere(runtime.args()));<br>
}<br>
private void startHere(String[] args) {<br>
SystemOut.println("Hello World");<br>
}<br>
}<br>
</pre><br>
<p><br>
Note that it is <code>final</code> and methods are
<code>private</code>.<br>
</p><br>
<p><br>
The <code>Entrypoint</code> interface would be:<br>
</p><br>
<pre><br>
public interface java.lang.Entrypoint {<br>
/**<br>
* Invoked by the JVM to launch the program.<br>
* When the method completes, the JDK terminates.<br>
*/<br>
public abstract void main(Runtime runtime);<br>
}<br>
</pre><br>
<p><br>
The <code>Runtime.execute</code> method would be
something like:<br>
</p><br>
<pre><br>
public void execute(ThrowableRunnable runnable) {<br>
try {<br>
runnable.run();<br>
System.exit(0);<br>
} catch (Throwable ex) {<br>
ex.printStackTrace();<br>
System.exit(1);<br>
}<br>
}<br>
</pre><br>
<p><br>
The JVM would do the following:<br>
</p><br>
<ul><br>
<li>Load the class file specified on the command
line</li><br>
<li>If it implements
<code>java.lang.Entrypoint</code> call the<br>
no-args constructor and invoke it</li><br>
<li>Else look for a legacy <code>public static void<br>
main(String[])</code>, and invoke that</li><br>
</ul><br>
<p><br>
Note that <code>java.lang.Entrypoint</code> is a
<b>normal interface<br>
that can be implemented by anyone and do anything</b>!<br>
</p><br>
<p><br>
This last point is critical to enhancing the bang-for-buck. I was<br>
intriguied by things like <a<br>
href=<a class="moz-txt-link-rfc2396E" href="https://www.azul.com/blog/superfast-application-startup-java-on-crac/">"https://www.azul.com/blog/superfast-application-startup-java-on-crac/"</a>>Azul<br>
CRaC</a> which wants to own the whole lifecycle of the JVM
run.<br>
Wouldn't that be more powerful if they could control the whole<br>
lifecycle through <code>Entrypoint</code>.<br>
Another possibile use is to reset the state when an application
has<br>
finished, allowing the same JVM to be reused - a bit like<br>
Function-as-a-Service providers or build system daemons do.<br>
(I suspect it may be possible to enhance the entrypoint concept to<br>
control the shutdown hooks and to catch things like<br>
<code>System.exit</code> but that is beyond the scope
of this blog.)<br>
For example, here is a theoretical application framework
entrypoint:<br>
</p><br>
<pre><br>
// FrameworkApplication.java - an Open Source library<br>
public interface FrameworkApplication extends Entrypoint {<br>
public default main(Runtime runtime) {<br>
// do framework things<br>
start();<br>
// do framework things<br>
}<br>
public abstract start();<br>
}<br>
</pre><br>
<p><br>
Applications just implement this interface, and they can run it by<br>
specifying their own class name on the command line, yet it is a<br>
full-featured framework application!<br>
</p><br>
</div>
</body>
</html>