<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">At various points, we've
        explored the question of which program elements are most and
        least helpful for students first learning Java.  After
        considering a number of alternatives over the years, I have a
        simple proposal for smoothing the "on ramp" to Java programming,
        while not creating new things to unlearn.  <br>
        <br>
        Markdown source is below, HTML will appear soon at: <br>
        <br>
            <a class="moz-txt-link-freetext" href="https://openjdk.org/projects/amber/design-notes/on-ramp">https://openjdk.org/projects/amber/design-notes/on-ramp</a><br>
        <br>
        <br>
        # Paving the on-ramp<br>
        <br>
        Java is one of the most widely taught programming languages in
        the world.  Tens<br>
        of thousands of educators find that the imperative core of the
        language combined<br>
        with a straightforward standard library is a foundation that
        students can<br>
        comfortably learn on.  Choosing Java gives educators many
        degrees of freedom:<br>
        they can situate students in `jshell` or Notepad or a
        full-fledged IDE; they can<br>
        teach imperative, object-oriented, functional, or hybrid
        programming styles; and<br>
        they can easily find libraries to interact with external data
        and services.  <br>
        <br>
        No language is perfect, and one of the most common complaints
        about Java is that<br>
        it is "too verbose" or has "too much ceremony."  And
        unfortunately, Java imposes<br>
        its heaviest ceremony on those first learning the language, who
        need and<br>
        appreciate it the least.  The declaration of a class and the
        incantation of<br>
        `public static void main` is pure mystery to a beginning
        programmer.  While<br>
        these incantations have principled origins and serve a useful
        organizing purpose<br>
        in larger programs, they have the effect of placing obstacles in
        the path of<br>
        _becoming_ Java programmers. Educators constantly remind us of
        the litany of<br>
        complexity that students have to confront on Day 1 of class --
        when they really<br>
        just want to write their first program.  <br>
        <br>
        As an amusing demonstration of this, in her JavaOne keynote
        appearance in 2019,<br>
        [Aimee Lucido](<a class="moz-txt-link-freetext" href="https://www.youtube.com/watch?v=BkPPFiXUwYk">https://www.youtube.com/watch?v=BkPPFiXUwYk</a>)
        talked about when<br>
        she learned to program in Java, and how her teacher performed a
        rap song<br>
        to help students memorize `"public static void main"`.  Our hats
        are off to<br>
        creative educators everywhere for this kind of dedication, but
        teachers<br>
        shouldn't have to do this.<br>
        <br>
        Of course, advanced programmers complain about ceremony too.  We
        will never be<br>
        able to satisfy programmers' insatiable appetite for typing
        fewer keystrokes,<br>
        and we shouldn't try, because the goal of programming is to
        write programs that<br>
        are easy to read and are clearly correct, not programs that were
        easy to type.<br>
        But we can try to better align the ceremony commensurate with
        the value it<br>
        brings to a program -- and let simple programs be expressed more
        simply.  <br>
        <br>
        ## Concept overload<br>
        <br>
        The classic "Hello World" program looks like this in Java:<br>
        <br>
        ```<br>
        public class HelloWorld { <br>
            public static void main(String[] args) { <br>
                System.out.println("Hello World");<br>
            }<br>
        }<br>
        ```<br>
        <br>
        It may only be five lines, but those lines are packed with
        concepts that are<br>
        challenging to absorb without already having some programming
        experience and<br>
        familiarity with object orientation. Let's break down the
        concepts a student<br>
        confronts when writing their first Java program:<br>
        <br>
          - **public** (on the class).  The `public` accessibility level
        is relevant<br>
            only when there is going to be cross-package access; in a
        simple "Hello<br>
            World" program, there is only one class, which lives in the
        unnamed package.<br>
            They haven't even written a one-line program yet; the notion
        of access<br>
            control -- keeping parts of a program from accessing other
        parts of it -- is<br>
            still way in their future.<br>
        <br>
          - **class**.  Our student hasn't set out to write a _class_,
        or model a<br>
            complex system with objects; they want to write a
        _program_.  In Java, a<br>
            program is just a `main` method in some class, but at this
        point our student<br>
            still has no idea what a class is or why they want one.<br>
        <br>
          - **Methods**.  Methods are of course a key concept in Java,
        but the mechanics<br>
            of methods -- parameters, return types, and invocation --
        are still<br>
            unfamiliar, and the `main` method is invoked magically from
        the `java`<br>
            launcher rather than from explicit code.  <br>
        <br>
          - **public** (again).  Like the class, the `main` method has
        to be public, but<br>
            again this is only relevant when programs are large enough
        to require<br>
            packages to organize them.  <br>
        <br>
          - **static**.  The `main` method has to be static, and at this
        point, students<br>
            have no context for understanding what a static method is or
        why they want<br>
            one.  Worse, the early exposure to `static` methods will
        turn out to be a<br>
            bad habit that must be later unlearned.  Worse still, the
        fact that the<br>
            `main` method is `static` creates a seam between `main` and
        other methods;<br>
            either they must become `static` too, or the `main` method
        must trampoline<br>
            to some sort of "instance main" (more ceremony!)  And if we
        get this wrong,<br>
            we get the dreaded and mystifying `"cannot be referenced
        from a static<br>
            context"` error.<br>
        <br>
          - **main**.  The name `main` has special meaning in a Java
        program, indicating<br>
            the starting point of a program, but this specialness hides
        behind being an<br>
            ordinary method name.  This may contribute to the sense of
        "so many magic<br>
            incantations."<br>
        <br>
          - **String[]**.  The parameter to `main` is an array of
        strings, which are the<br>
            arguments that the `java` launcher collected from the
        command line.  But our<br>
            first program -- likely our first dozen -- will not use
        command-line<br>
            parameters. Requiring the `String[]` parameter is, at this
        point, a mistake<br>
            waiting to happen, and it will be a long time until this
        parameter makes<br>
            sense.  Worse, educators may be tempted to explain arrays at
        this point,<br>
            which further increases the time-to-first-program.<br>
        <br>
          - **System.out.println**.  If you look closely at this
        incantation, each<br>
            element in the chain is a different thing -- `System` is a
        class (what's a<br>
            class again?), `out` is a static field (what's a field?),
        and `println` is<br>
            an instance method.  The only part the student cares about
        right now is<br>
            `println`; the rest of it is an incantation that they do not
        yet understand<br>
            in order to get at the behavior they want.<br>
        <br>
        That's a lot to explain to a student on the first day of class. 
        There's a good<br>
        chance that by now, class is over and we haven't written any
        programs yet, or<br>
        the teacher has said "don't worry what this means, you'll
        understand it later"<br>
        six or eight times.  Not only is this a lot of _syntactic_
        things to absorb, but<br>
        each of those things appeals to a different concept (class,
        method, package,<br>
        return value, parameter, array, static, public, etc) that the
        student doesn't<br>
        have a framework for understanding yet.  Each of these will have
        an important<br>
        role to play in larger programs, but so far, they only
        contribute to "wow,<br>
        programming is complicated."  <br>
        <br>
        It won't be practical (or even desirable) to get _all_ of these
        concepts out of<br>
        the student's face on day 1, but we can do a lot -- and focus on
        the ones that<br>
        do the most to help beginners understand how programs are
        constructed.<br>
        <br>
        ## Goal: a smooth on-ramp<br>
        <br>
        As much as programmers like to rant about ceremony, the real
        goal here is not<br>
        mere ceremony reduction, but providing a graceful _on ramp_ to
        Java programming.<br>
        This on-ramp should be helpful to beginning programmers by
        requiring only those<br>
        concepts that a simple program needs.  <br>
        <br>
        Not only should an on-ramp have a gradual slope and offer enough
        acceleration<br>
        distance to get onto the highway at the right speed, but its
        direction must<br>
        align with that of the highway.  When a programmer is ready to
        learn about more<br>
        advanced concepts, they should not have to discard what they've
        already learned,<br>
        but instead easily see how the simple programs they've already
        written<br>
        generalize to more complicated ones, and both the syntatic and
        conceptual<br>
        transformation from "simple" to "full blown" program should be
        straightforward<br>
        and unintrusive.  It is a definite non-goal to create a
        "simplified dialect of<br>
        Java for students".<br>
        <br>
        We identify three simplifications that should aid both educators
        and students in<br>
        navigating the on-ramp to Java, as well as being generally
        useful to simple<br>
        programs beyond the classroom as well:<br>
        <br>
         - A more tolerant launch protocol<br>
         - Unnamed classes<br>
         - Predefined static imports for the most critical methods and
        fields<br>
        <br>
        ## A more tolerant launch protocol<br>
        <br>
        The Java Language Specification has relatively little to say
        about how Java<br>
        "programs" get launched, other than saying that there is some
        way to indicate<br>
        which class is the initial class of a program (JLS 12.1.1) and
        that a public<br>
        static method called `main` whose sole argument is of type
        `String[]` and whose<br>
        return is `void` constitutes the entry point of the indicated
        class.  <br>
        <br>
        We can eliminate much of the concept overload simply by relaxing
        the<br>
        interactions between a Java program and the `java` launcher:<br>
        <br>
         - Relax the requirement that the class, and `main` method, be
        public.  Public<br>
           accessibility is only relevant when access crosses packages;
        simple programs<br>
           live in the unnamed package, so cannot be accessed from any
        other package<br>
           anyway.  For a program whose main class is in the unnamed
        package, we can<br>
           drop the requirement that the class or its `main` method be
        public,<br>
           effectively treating the `java` launcher as if it too resided
        in the unnamed<br>
           package.<br>
        <br>
         - Make the "args" parameter to `main` optional, by allowing the
        `java` launcher to<br>
           first look for a main method with the traditional
        `main(String[])`<br>
           signature, and then (if not found) for a main method with no
        arguments.<br>
        <br>
         - Make the `static` modifier on `main` optional, by allowing
        the `java` launcher to<br>
           invoke an instance `main` method (of either signature) by
        instantiating an<br>
           instance using an accessible no-arg constructor and then
        invoking the `main`<br>
           method on it.<br>
        <br>
        This small set of changes to the launch protocol strikes out
        five of the bullet<br>
        points in the above list of concepts: public (twice), static,
        method parameters,<br>
        and `String[]`.  <br>
        <br>
        At this point, our Hello World program is now:<br>
        <br>
        ```<br>
        class HelloWorld { <br>
            void main() { <br>
                System.out.println("Hello World");<br>
            }<br>
        }<br>
        ```<br>
        <br>
        It's not any shorter by line count, but we've removed a lot of
        "horizontal<br>
        noise" along with a number of concepts.  Students and educators
        will appreciate<br>
        it, but advanced programmers are unlikely to be in any hurry to
        make these<br>
        implicit elements explicit either.  <br>
        <br>
        Additionally, the notion of an "instance main" has value well
        beyond the first<br>
        day.  Because excessive use of `static` is considered a code
        smell, many<br>
        educators encourage the pattern of "all the static `main` method
        does is<br>
        instantiate an instance and call an instance `main` method"
        anyway.  Formalizing<br>
        the "instance main" protocol reduces a layer of boilerplate in
        these cases, and<br>
        defers the point at which we have to explain what instance
        creation is -- and<br>
        what `static` is.  (Further, allowing the `main` method to be an
        instance method<br>
        means that it could be inherited from a superclass, which is
        useful for simple<br>
        frameworks such as test runners or service frameworks.)<br>
        <br>
        ## Unnamed classes<br>
        <br>
        In a simple program, the `class` declaration often doesn't help
        either, because<br>
        other classes (if there are any) are not going to reference it
        by name, and we<br>
        don't extend a superclass or implement any interfaces.  If we
        say an "unnamed<br>
        class" consists of member declarations without a class header,
        then our Hello<br>
        World program becomes:<br>
        <br>
        ```<br>
        void main() { <br>
            System.out.println("Hello World");<br>
        }<br>
        ```<br>
        <br>
        Such source files can still have fields, methods, and even
        nested classes, so<br>
        that as a program evolves from a few statements to needing some
        ancillary state<br>
        or helper methods, these can be factored out of the `main`
        method while still<br>
        not yet requiring a full class declaration:<br>
        <br>
        ```<br>
        String greeting() { return "Hello World"; }<br>
        <br>
        void main() {<br>
            System.out.println(greeting());<br>
        }<br>
        ```<br>
        <br>
        This is where treating `main` as an instance method really
        shines; the user has<br>
        just declared two methods, and they can freely call each other. 
        Students need<br>
        not confront the confusing distinction between instance and
        static methods yet;<br>
        indeed, if not forced to confront static members on day 1, it
        might be a while<br>
        before they do have to learn this distinction.  The fact that
        there is a<br>
        receiver lurking in the background will come in handy later, but
        right now is<br>
        not bothering anybody.<br>
        <br>
        [JEP 330](<a class="moz-txt-link-freetext" href="https://openjdk.org/jeps/330">https://openjdk.org/jeps/330</a>) allows single-file
        programs to be<br>
        launched directly without compilation; this streamlined launcher
        pairs well with<br>
        unnamed classes. <br>
        <br>
        ## Predefined static imports<br>
        <br>
        The most important classes, such as `String` and `Integer`, live
        in the<br>
        `java.lang` package, which is automatically on-demand imported
        into all<br>
        compilation units; this is why we do not have to `import
        java.lang.String` in<br>
        every class.  Static imports were not added until Java 5, but no
        corresponding<br>
        facility for automatic on-demand import of common behavior was
        added at that<br>
        time.  Most programs, however, will want to do console IO, and
        Java forces us to<br>
        do this in a roundabout way -- through the static `System.out`
        and `System.in`<br>
        fields.  Basic console input and output is a reasonable
        candidate for<br>
        auto-static import, as one or both are needed by most simple
        programs.  While<br>
        these are currently instance methods accessed through static
        fields, we can<br>
        easily create static methods for `println` and `readln` which
        are suitable for<br>
        static import, and automatically import them.  At which point
        our first program<br>
        is now down to:<br>
        <br>
        ```<br>
        void main() {<br>
            println("Hello World");<br>
        }<br>
        ```<br>
        <br>
        ## Putting this all together<br>
        <br>
        We've discussed several simplifications:<br>
        <br>
         - Update the launcher protocol to make public, static, and
        arguments optional<br>
           for main methods, and for main methods to be instance methods
        (when a<br>
           no-argument constructor is available); <br>
         - Make the class wrapper for "main classes" optional (unnamed
        classes);<br>
         - Automatically static import methods like `println`<br>
        <br>
        which together whittle our long list of day-1 concepts down
        considerably.  While<br>
        this is still not as minimal as the minimal Python or Ruby
        program -- statements<br>
        must still live in a method -- the goal here is not to win at
        "code golf".  The<br>
        goal is to ensure that concepts not needed by simple programs
        need not appear in<br>
        those programs, while at the same time not encouraging habits
        that have to be<br>
        unlearned as programs scale up. <br>
        <br>
        Each of these simplifications is individually small and
        unintrusive, and each is<br>
        independent of the others.  And each embodies a simple
        transformation that the<br>
        author can easily manually reverse when it makes sense to do so:
        elided<br>
        modifiers and `main` arguments can be added back, the class
        wrapper can be added<br>
        back when the affordances of classes are needed (supertypes,
        constructors), and<br>
        the full qualifier of static-import can be added back.  And
        these reversals are<br>
        independent of one another; they can done in any combination or
        any order.<br>
        <br>
        This seems to meet the requirements of our on-ramp; we've
        eliminated most of the<br>
        day-1 ceremony elements without introducing new concepts that
        need to be<br>
        unlearned. The remaining concepts -- a method is a container for
        statements, and<br>
        a program is a Java source file with a `main` method -- are
        easily understood in<br>
        relation to their fully specified counterparts.  <br>
        <br>
        ## Alternatives<br>
        <br>
        Obviously, we've lived with the status quo for 25+ years, so we
        could continue<br>
        to do so.  There were other alternatives explored as well;
        ultimately, each of<br>
        these fell afoul of one of our goals.<br>
        <br>
        ### Can't we go further?<br>
        <br>
        Fans of "code golf" -- of which there are many -- are surely
        right now trying to<br>
        figure out how to eliminate the last little bit, the `main`
        method, and allow<br>
        statements to exist at the top-level of a program.  We
        deliberately stopped<br>
        short of this because it offers little value beyond the first
        few minutes, and<br>
        even that small value quickly becomes something that needs to be
        unlearned.  <br>
        <br>
        The fundamental problem behind allowing such "loose" statements
        is that<br>
        variables can be declared inside both classes (fields) and
        methods (local<br>
        variables), and they share the same syntactic production but not
        the same<br>
        semantics.  So it is unclear (to both compilers and humans)
        whether a "loose"<br>
        variable would be a local or a field.  If we tried to adopt some
        sort of simple<br>
        heuristic to collapse this ambiguity (e.g., whether it precedes
        or follows the<br>
        first statement), that may satisfy the compiler, but now simple
        refactorings<br>
        might subtly change the meaning of the program, and we'd be
        replacing the<br>
        explicit syntactic overhead of `void main()` with an invisible
        "line" in the<br>
        program that subtly affects semantics, and a new subtle rule
        about the meaning<br>
        of variable declarations that applies only to unnamed classes. 
        This doesn't<br>
        help students, nor is this particularly helpful for all but the
        most trivial<br>
        programs.  It quickly becomes a crutch to be discarded and
        unlearned, which<br>
        falls afoul of our "on ramp" goals.  Of all the concepts on our
        list, "methods"<br>
        and "a program is specified by a main method" seem the ones that
        are most worth<br>
        asking students to learn early.<br>
        <br>
        ### Why not "just" use `jshell`?  <br>
        <br>
        While JShell is a great interactive tool, leaning too heavily on
        it as an onramp<br>
        would fall afoul of our goals.  A JShell session is not a
        program, but a<br>
        sequence of code snippets.  When we type declarations into
        `jshell`, they are<br>
        viewed as implicitly static members of some unspecified class,
        with<br>
        accessibility is ignored completely, and statements execute in a
        context where<br>
        all previous declarations are in scope.  This is convenient for
        experimentation<br>
        -- the primary goal of `jshell` -- but not such a great mental
        model for<br>
        learning to write Java programs.  Transforming a batch of
        working declarations<br>
        in `jshell` to a real Java program would not be sufficiently
        simple or<br>
        unintrusive, and would lead to a non-idiomatic style of code,
        because the<br>
        straightforward translation would have us redeclaring each
        method, class, and<br>
        variable declaration as `static`.  Further, this is probably not
        the direction<br>
        we want to go when we scale up from a handful of statements and
        declarations to<br>
        a simple class -- we probably want to start using classes as
        classes, not just<br>
        as containers for static members. JShell is a great tool for
        exploration and<br>
        debugging, and we expect many educators will continue to
        incorporate it into<br>
        their curriculum, but is not the on-ramp programming model we
        are looking for.  <br>
        <br>
        ### What about "always local"?<br>
        <br>
        One of the main tensions that `main` introduces is that most
        class members are<br>
        not `static`, but the `main` method is -- and that forces
        programmers to<br>
        confront the seam between static and non-static members.  JShell
        answers this<br>
        with "make everything static". <br>
        <br>
        Another approach would be to "make everything local" -- treat a
        simple program<br>
        as being the "unwrapped" body of an implicit main method.  We
        already allow<br>
        variables and classes to be declared local to a method.  We
        could add local<br>
        methods (a useful feature in its own right) and relax some of
        the asymmetries<br>
        around nesting (again, an attractive cleanup), and then treat a
        mix of<br>
        declarations and statements without a class wrapper as the body
        of an invisible<br>
        `main` method. This seems an attractive model as well -- at
        first.<br>
        <br>
        While the syntactic overhead of converting back to full-blown
        classes -- wrap<br>
        the whole thing in a `main` method and a `class` declaration --
        is far less<br>
        intrusive than the transformation inherent in `jshell`, this is
        still not an<br>
        ideal on-ramp.  Local variables interact with local classes (and
        methods, when<br>
        we have them) in a very different way than instance fields do
        with instance<br>
        methods and inner classes: their scopes are different (no
        forward references),<br>
        their initialization rules are different, and captured local
        variables must be<br>
        effectively final.  This is a subtly different programming model
        that would then<br>
        have to be unlearned when scaling up to full classes. Further,
        the result of<br>
        this wrapping -- where everything is local to the main method --
        is also not<br>
        "idiomatic Java".  So while local methods may be an attractive
        feature, they are<br>
        similarly not the on-ramp we are looking for.<br>
        <br>
        <br>
      </font></font>
  </body>
</html>