> From: "Brian Goetz" <[email protected]> > To: "amber-spec-experts" <[email protected]> > Sent: Wednesday, October 19, 2022 6:43:18 PM > Subject: Re: Paving the on-ramp
> Discussion here seems to have settled down. Here's what seem like the > possibly-open parts: > - Most of the concerns centered around the imports part, not the main part. We > should think some more about alternatives for Console IO other than > auto-importing a static println method; this might mean that their invocation > is something more verbose than just "println", but better than > "System.out.println", and possibly more discoverable. In the meantime, we'll > separate off the auto-import for STR as part of string templates to decouple > these trains. > - The notion of "unnamed class" seems to fill a hole alongside "unnamed > package" > and "unnamed module", but the analogy is imperfect, because these classes > _will_ have a name, just not one visible from _inside_ the class. The > alternative is to view these as _implicitly named_ classes, where they have a > name, just derived from the file system rather than the source code. The > distinction might influence whether such simplified class declarations can > have > constructors (if you can't name it, you can't name the constructor), whether > static methods or fields can be accessed from within the class, etc. (However, > these influences are weak; we could still reasonably choose to disallow > constructors and instance initializers even if the name is denotable.) > We could, of course, prevent class access from outside the class too, > effectively making such classes visible only to the launcher. But this would > come at no small cost to prevent such accesses, and for limited benefit. We can cheaply disallow access by - only allowing one compilation unit if there is an unnamed class. - mark the generated class as synthetic (see JVMS 4.7.8) so it does not work with separate compilation. > The status-quo proposal currently says: the name of the class is not visible > from within the class, you can't have constructors or instance initializers, > you get an implicit no-arg constructor like every other constructor-less > class. > If you want a more complex construction protocol, or supertypes, or class > declaration annotations, or to live in a package, declare a class. This still > seems pretty OK. I still think that allowing fields inside an unamed class is a mistake (if we can avoid to talk about null at the beginning, it's a win). Rémi https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-4.html#jvms-4.7.8 > On 10/12/2022 7:56 PM, Brian Goetz wrote: >> I've gotten some good feedback from this writeup, much of it illuminating how >> different people (myself included) make different assumptions about how >> certain >> things work / what things are for. >> #### Role of main >> A main() method can be viewed from two perspectives: it is an ordinary method >> with modifiers, parameters, etc, but it is also an externally significant >> _entry point_ into a program. (We've seen a similar double-duty with method >> parameters in the context of the underscore discussion: a method parameter is >> both a "local" that serves the implementation of the method, but its also >> part >> of the specification of the method (e.g., the name and type bleed into the >> Javadoc.)) >> Java made the choice in 1995 that an entry point is "just" a suitably named / >> structured / accessible method. This was somewhat "un-Java-ish", as >> identification of main-ness is a structural property, and Java (certainly >> back >> then) mostly avoided such structural techniques where it could. I think its >> fair to question whether this decision is still serving us (Stephen's >> proposal >> does exactly that), but I think this was a pragmatic choice and I'm inclined >> to >> continue to run with it, rather than look at it as something "to be fixed". >> So the proposal broadens the structure parameters around "what is a main", >> but >> ultimately leaves the "some methods are special" decision in place. (Aside: >> if >> we'd had annotations in Java 1.0, we might well have used an @EntryPoint >> capture the metadata of "this method is externally launchable", and let the >> launcher reflect over the methods of a class to find a suitable entry point. >> But we didn't, and trying to rewrite history in this way is likely a losing >> game.) >> #### Role of launcher >> This raises a secondary question about the role of the launcher. My mental >> model >> was one of "the launcher is just some out-of-sight code that invokes the main >> method." That `main` (currently) should be public plays into this, because if >> this out-of-sight code is going to call this method, surely accessibility >> will >> have a chance to say "can this code call this method". I was surprised, >> though, >> to find out that others have a different view of this. Kevin asked whether it >> was a "bug" in the model that, in order for the launcher to be able to call a >> `main` method, then so must other code. This is a form of coupling that I had >> assumed is pure good (because it means there's a unified model of >> invocation), >> but is reasonable to call it out as a coupling. >> In my view, treating the launcher as "just another caller" simplifies the >> story, >> because we don't have to have a separate story for invoking entry points. If >> we're doubling down on "main is just a method with some special metadata that >> says 'start here'", then doubling down on accessibility here as well makes >> sense to me also. Hence my suggestion to frame the launcher as "ordinary code >> in the unnamed package". But as natural as this seems to me, I recognize that >> this may seem weird to others. >> #### Role of unnamed packages >> Another place where there were differing viewpoints is on the role of unnamed >> packages. Some felt that using the unnamed package at all should be reserved >> for the most transient of "run it once and delete it" programs; others felt >> that it had a role beyond mere experiments. >> In part because of the difficulties described in the On Ramp document, Java >> has >> not found extensive use in scripts, but we are hoping that this will become >> more common over time. (The "Launch Single File Java Programs" JEP was a step >> towards being more script-friendly.) I would think that the unnamed package >> is >> the right place for scripts as well, since users will want to identify the >> program by its path in the file system, not by setting up a class path and >> referring to a relative position within that. >> Overall, I think the result of this project will be that *more* code lives in >> the unnamed package -- and that's OK, because people will write more simple, >> self-contained programs in Java, and the unnamed package is an OK place for >> these things to live. >> #### Instance main and interfaces >> Several folks have pointed out that perhaps an instance main should be >> specified >> by an interface (say, Program), and that unnamed classes implicitly implement >> Program. This has some attraction, since this is generally how we prevent >> names >> from being magic. >> There are some downsides, though. We already have two ways to spell "main"; >> we >> might want more in the future, and having to spell them all out in an >> interface >> (even with defaults) could impede evolution. More importantly, this is using >> a >> different mechanism that we use for the main we currently have, which means >> there are two different ways to identify the two kinds of main. This is >> starting to veer into the sort of "fix mistakes of the past" siren song which >> leaves you with two different ways of doing the same thing, which appears to >> new users as more complexity, not less. >> #### Moral hazards >> A significant proportion of the negative feedback to the proposal amounted to >> some sort of "moral hazard". The biggest component here was that shortening >> `System.out.println()` to `println()` would encourage people to use console >> IO >> more often, in places where it was not appropriate, or that it would be an >> impediment to testing. I didn't find this argument very compelling, though; I >> don't think the number of characters required to access console IO is the >> determining factor here in choosing an IO strategy (or even being aware that >> there is such a thing as an IO strategy.) >> #### Console IO >> There were a variety of opinions on the direction we should go with >> simplifying >> console IO. While nearly everyone agrees that `System.out.println` is a >> mouthful, there were a number of alternate approaches suggested, such as: >> - Expose new classes (e.g., SystemOut) with static methods >> (SystemOut.println) >> instead of new static methods; >> - Expose a new API for console IO, but don't auto-import anything; >> - Auto-import console IO methods only in unnamed classes; >> - others. >> #### Auto imports >> After some thought, I realize that the auto-import feature is trying to serve >> two separate goals, and maybe is getting distorted because of it. The String >> Templates JEP defines some canned processors (STR and FMT), which are >> effectively part of the language. At first blush (which is when people are >> often most vocal about peripheral features), people already don't like having >> to type STR-dot (sorry, not changing our mind about that), and having to >> import >> STR feels like adding insult to injury. STR is effectively part of the >> language, so we don't want to place hoops in the way of using it. But that >> is a >> slightly different use case than rescuing println, for which there are >> multiple >> possible paths. Maybe its best to separate these. >> The On Ramp document outlined some (admittedly fuzzy) goals which may be >> helpful >> for evaluating some of these thoughts. We are not trying to create a >> "beginner's dialect of Java", nor am I particularly interested in using this >> effort to turn back the clock and redesign features that some people wish had >> been designed otherwise. The goal here is, to the extent possible, to make >> elements of program declaration recede into the background until they are >> actually adding value. Access control, classes, statics, etc, should come >> into >> the picture when they are needed, and not before. I'm sure that there are >> other >> aspects of the language that people would like to have recede into the >> background too, and will attempt to attach to this project, but I'm >> interested >> in focusing primarily on those that are impediments to learning the language. >> If we do our job right, these will have benefits well beyond the first few >> days >> of using Java. >> My thoughts: >> - Java made the choice that "entry points" are specially structured methods, >> and >> can be called both programmatically and via the launcher. I see no reason to >> tinker with this concept, or to materially change how entry points are >> declared >> -- just to widen the range of `main` methods that are considered entry >> points. >> - While the JLS doesn't really say what the launcher is (just that there is >> something that launches programs), positioning the launcher as some code in >> the >> unnamed package seems helpful, because familiar concepts of access control >> apply both to programmatic and command line invocation. >> - While I get that some people find the unnamed package to be a "smell", I >> think >> it is actually fine for a range of programs, and I expect that range to >> broaden >> over time as people start using Java for scripts. >> - I am sympathetic to the argument that people don't want "println" and >> friends >> to effectively become global; this is separate from simplifying the locution. >> Where there may be an attractive middle ground is: >> - Take the new methods for console IO and put them somewhere in java.lang, >> say >> ConsoleIO; >> - Auto-import ConsoleIO only in unnamed classes. >> While this creates a new coupling, it may align well, in that the programs >> who >> most want access to console IO are those that are most likely to be able to >> be >> unnamed classes -- and the rest can import all the console IO with a single >> `import static ConsoleIO.*`. Refactoring to a named class would then involve >> adding both the class wrapper and this import. >> - I am open to other approaches for improving the console IO story. Maybe >> this >> is Console.println(), which avoids the need for auto-static-import at all at >> the cost of some more words (but at least doesn't require understanding >> static >> fields, and has the advantage that all the console stuff can be in one >> place), >> or maybe something else. (A big part of the problem with the status quo now >> is >> that not only is System.out.println undiscoverable, but having found that, >> you >> still have no idea where "readln" is.) >> - While I get why people are attracted to putting instance main in an >> interface, >> I don't think I'd like the result. As mentioned above, this implicitly places >> an impediment in future expansion of the launcher protocol, but more >> importantly, means we have two mechanisms for finding main -- an "old" and >> "new" one. I try hard to avoid creating this situation, because the benefit >> is >> rarely worth the increased cognitive load. >> On 9/28/2022 1:57 PM, Brian Goetz wrote: >>> 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. >>> Markdown source is below, HTML will appear soon at: >>> [ https://openjdk.org/projects/amber/design-notes/on-ramp | >>> https://openjdk.org/projects/amber/design-notes/on-ramp ] >>> # Paving the on-ramp >>> Java is one of the most widely taught programming languages in the world. >>> Tens >>> of thousands of educators find that the imperative core of the language >>> combined >>> with a straightforward standard library is a foundation that students can >>> comfortably learn on. Choosing Java gives educators many degrees of freedom: >>> they can situate students in `jshell` or Notepad or a full-fledged IDE; >>> they can >>> teach imperative, object-oriented, functional, or hybrid programming >>> styles; and >>> they can easily find libraries to interact with external data and services. >>> No language is perfect, and one of the most common complaints about Java is >>> that >>> it is "too verbose" or has "too much ceremony." And unfortunately, Java >>> imposes >>> its heaviest ceremony on those first learning the language, who need and >>> appreciate it the least. The declaration of a class and the incantation of >>> `public static void main` is pure mystery to a beginning programmer. While >>> these incantations have principled origins and serve a useful organizing >>> purpose >>> in larger programs, they have the effect of placing obstacles in the path of >>> _becoming_ Java programmers. Educators constantly remind us of the litany of >>> complexity that students have to confront on Day 1 of class -- when they >>> really >>> just want to write their first program. >>> As an amusing demonstration of this, in her JavaOne keynote appearance in >>> 2019, >>> [Aimee Lucido]( [ https://www.youtube.com/watch?v=BkPPFiXUwYk | >>> https://www.youtube.com/watch?v=BkPPFiXUwYk ] ) talked about when >>> she learned to program in Java, and how her teacher performed a rap song >>> to help students memorize `"public static void main"`. Our hats are off to >>> creative educators everywhere for this kind of dedication, but teachers >>> shouldn't have to do this. >>> Of course, advanced programmers complain about ceremony too. We will never >>> be >>> able to satisfy programmers' insatiable appetite for typing fewer >>> keystrokes, >>> and we shouldn't try, because the goal of programming is to write programs >>> that >>> are easy to read and are clearly correct, not programs that were easy to >>> type. >>> But we can try to better align the ceremony commensurate with the value it >>> brings to a program -- and let simple programs be expressed more simply. >>> ## Concept overload >>> The classic "Hello World" program looks like this in Java: >>> ``` >>> public class HelloWorld { >>> public static void main(String[] args) { >>> System.out.println("Hello World"); >>> } >>> } >>> ``` >>> It may only be five lines, but those lines are packed with concepts that are >>> challenging to absorb without already having some programming experience and >>> familiarity with object orientation. Let's break down the concepts a student >>> confronts when writing their first Java program: >>> - **public** (on the class). The `public` accessibility level is relevant >>> only when there is going to be cross-package access; in a simple "Hello >>> World" program, there is only one class, which lives in the unnamed package. >>> They haven't even written a one-line program yet; the notion of access >>> control -- keeping parts of a program from accessing other parts of it -- is >>> still way in their future. >>> - **class**. Our student hasn't set out to write a _class_, or model a >>> complex system with objects; they want to write a _program_. In Java, a >>> program is just a `main` method in some class, but at this point our student >>> still has no idea what a class is or why they want one. >>> - **Methods**. Methods are of course a key concept in Java, but the >>> mechanics >>> of methods -- parameters, return types, and invocation -- are still >>> unfamiliar, and the `main` method is invoked magically from the `java` >>> launcher rather than from explicit code. >>> - **public** (again). Like the class, the `main` method has to be public, >>> but >>> again this is only relevant when programs are large enough to require >>> packages to organize them. >>> - **static**. The `main` method has to be static, and at this point, >>> students >>> have no context for understanding what a static method is or why they want >>> one. Worse, the early exposure to `static` methods will turn out to be a >>> bad habit that must be later unlearned. Worse still, the fact that the >>> `main` method is `static` creates a seam between `main` and other methods; >>> either they must become `static` too, or the `main` method must trampoline >>> to some sort of "instance main" (more ceremony!) And if we get this wrong, >>> we get the dreaded and mystifying `"cannot be referenced from a static >>> context"` error. >>> - **main**. The name `main` has special meaning in a Java program, >>> indicating >>> the starting point of a program, but this specialness hides behind being an >>> ordinary method name. This may contribute to the sense of "so many magic >>> incantations." >>> - **String[]**. The parameter to `main` is an array of strings, which are >>> the >>> arguments that the `java` launcher collected from the command line. But our >>> first program -- likely our first dozen -- will not use command-line >>> parameters. Requiring the `String[]` parameter is, at this point, a mistake >>> waiting to happen, and it will be a long time until this parameter makes >>> sense. Worse, educators may be tempted to explain arrays at this point, >>> which further increases the time-to-first-program. >>> - **System.out.println**. If you look closely at this incantation, each >>> element in the chain is a different thing -- `System` is a class (what's a >>> class again?), `out` is a static field (what's a field?), and `println` is >>> an instance method. The only part the student cares about right now is >>> `println`; the rest of it is an incantation that they do not yet understand >>> in order to get at the behavior they want. >>> That's a lot to explain to a student on the first day of class. There's a >>> good >>> chance that by now, class is over and we haven't written any programs yet, >>> or >>> the teacher has said "don't worry what this means, you'll understand it >>> later" >>> six or eight times. Not only is this a lot of _syntactic_ things to absorb, >>> but >>> each of those things appeals to a different concept (class, method, package, >>> return value, parameter, array, static, public, etc) that the student >>> doesn't >>> have a framework for understanding yet. Each of these will have an important >>> role to play in larger programs, but so far, they only contribute to "wow, >>> programming is complicated." >>> It won't be practical (or even desirable) to get _all_ of these concepts >>> out of >>> the student's face on day 1, but we can do a lot -- and focus on the ones >>> that >>> do the most to help beginners understand how programs are constructed. >>> ## Goal: a smooth on-ramp >>> As much as programmers like to rant about ceremony, the real goal here is >>> not >>> mere ceremony reduction, but providing a graceful _on ramp_ to Java >>> programming. >>> This on-ramp should be helpful to beginning programmers by requiring only >>> those >>> concepts that a simple program needs. >>> Not only should an on-ramp have a gradual slope and offer enough >>> acceleration >>> distance to get onto the highway at the right speed, but its direction must >>> align with that of the highway. When a programmer is ready to learn about >>> more >>> advanced concepts, they should not have to discard what they've already >>> learned, >>> but instead easily see how the simple programs they've already written >>> generalize to more complicated ones, and both the syntatic and conceptual >>> transformation from "simple" to "full blown" program should be >>> straightforward >>> and unintrusive. It is a definite non-goal to create a "simplified dialect >>> of >>> Java for students". >>> We identify three simplifications that should aid both educators and >>> students in >>> navigating the on-ramp to Java, as well as being generally useful to simple >>> programs beyond the classroom as well: >>> - A more tolerant launch protocol >>> - Unnamed classes >>> - Predefined static imports for the most critical methods and fields >>> ## A more tolerant launch protocol >>> The Java Language Specification has relatively little to say about how Java >>> "programs" get launched, other than saying that there is some way to >>> indicate >>> which class is the initial class of a program (JLS 12.1.1) and that a public >>> static method called `main` whose sole argument is of type `String[]` and >>> whose >>> return is `void` constitutes the entry point of the indicated class. >>> We can eliminate much of the concept overload simply by relaxing the >>> interactions between a Java program and the `java` launcher: >>> - 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. >>> - 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. >>> - 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. >>> This small set of changes to the launch protocol strikes out five of the >>> bullet >>> points in the above list of concepts: public (twice), static, method >>> parameters, >>> and `String[]`. >>> At this point, our Hello World program is now: >>> ``` >>> class HelloWorld { >>> void main() { >>> System.out.println("Hello World"); >>> } >>> } >>> ``` >>> It's not any shorter by line count, but we've removed a lot of "horizontal >>> noise" along with a number of concepts. Students and educators will >>> appreciate >>> it, but advanced programmers are unlikely to be in any hurry to make these >>> implicit elements explicit either. >>> Additionally, the notion of an "instance main" has value well beyond the >>> first >>> day. 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. >>> Formalizing >>> the "instance main" protocol reduces a layer of boilerplate in these cases, >>> and >>> defers the point at which we have to explain what instance creation is -- >>> and >>> what `static` is. (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.) >>> ## Unnamed classes >>> In a simple program, the `class` declaration often doesn't help either, >>> because >>> other classes (if there are any) are not going to reference it by name, and >>> we >>> don't extend a superclass or implement any interfaces. If we say an "unnamed >>> class" consists of member declarations without a class header, then our >>> Hello >>> World program becomes: >>> ``` >>> void main() { >>> System.out.println("Hello World"); >>> } >>> ``` >>> Such source files can still have fields, methods, and even nested classes, >>> so >>> that as a program evolves from a few statements to needing some ancillary >>> state >>> or helper methods, these can be factored out of the `main` method while >>> still >>> not yet requiring a full class declaration: >>> ``` >>> String greeting() { return "Hello World"; } >>> void main() { >>> System.out.println(greeting()); >>> } >>> ``` >>> This is where treating `main` as an instance method really shines; the user >>> has >>> just declared two methods, and they can freely call each other. Students >>> need >>> not confront the confusing distinction between instance and static methods >>> yet; >>> indeed, if not forced to confront static members on day 1, it might be a >>> while >>> before they do have to learn this distinction. The fact that there is a >>> receiver lurking in the background will come in handy later, but right now >>> is >>> not bothering anybody. >>> [JEP 330]( [ https://openjdk.org/jeps/330 | https://openjdk.org/jeps/330 ] ) >>> allows single-file programs to be >>> launched directly without compilation; this streamlined launcher pairs well >>> with >>> unnamed classes. >>> ## Predefined static imports >>> The most important classes, such as `String` and `Integer`, live in the >>> `java.lang` package, which is automatically on-demand imported into all >>> compilation units; this is why we do not have to `import java.lang.String` >>> in >>> every class. Static imports were not added until Java 5, but no >>> corresponding >>> facility for automatic on-demand import of common behavior was added at that >>> time. Most programs, however, will want to do console IO, and Java forces >>> us to >>> do this in a roundabout way -- through the static `System.out` and >>> `System.in` >>> fields. Basic console input and output is a reasonable candidate for >>> auto-static import, as one or both are needed by most simple programs. While >>> these are currently instance methods accessed through static fields, we can >>> easily create static methods for `println` and `readln` which are suitable >>> for >>> static import, and automatically import them. At which point our first >>> program >>> is now down to: >>> ``` >>> void main() { >>> println("Hello World"); >>> } >>> ``` >>> ## Putting this all together >>> We've discussed several simplifications: >>> - Update the launcher protocol to make public, static, and arguments >>> optional >>> for main methods, and for main methods to be instance methods (when a >>> no-argument constructor is available); >>> - Make the class wrapper for "main classes" optional (unnamed classes); >>> - Automatically static import methods like `println` >>> which together whittle our long list of day-1 concepts down considerably. >>> While >>> this is still not as minimal as the minimal Python or Ruby program -- >>> statements >>> must still live in a method -- the goal here is not to win at "code golf". >>> The >>> goal is to ensure that concepts not needed by simple programs need not >>> appear in >>> those programs, while at the same time not encouraging habits that have to >>> be >>> unlearned as programs scale up. >>> Each of these simplifications is individually small and unintrusive, and >>> each is >>> independent of the others. And each embodies a simple transformation that >>> the >>> author can easily manually reverse when it makes sense to do so: elided >>> modifiers and `main` arguments can be added back, the class wrapper can be >>> added >>> back when the affordances of classes are needed (supertypes, constructors), >>> and >>> the full qualifier of static-import can be added back. And these reversals >>> are >>> independent of one another; they can done in any combination or any order. >>> This seems to meet the requirements of our on-ramp; we've eliminated most >>> of the >>> day-1 ceremony elements without introducing new concepts that need to be >>> unlearned. The remaining concepts -- a method is a container for >>> statements, and >>> a program is a Java source file with a `main` method -- are easily >>> understood in >>> relation to their fully specified counterparts. >>> ## Alternatives >>> Obviously, we've lived with the status quo for 25+ years, so we could >>> continue >>> to do so. There were other alternatives explored as well; ultimately, each >>> of >>> these fell afoul of one of our goals. >>> ### Can't we go further? >>> Fans of "code golf" -- of which there are many -- are surely right now >>> trying to >>> figure out how to eliminate the last little bit, the `main` method, and >>> allow >>> statements to exist at the top-level of a program. We deliberately stopped >>> short of this because it offers little value beyond the first few minutes, >>> and >>> even that small value quickly becomes something that needs to be unlearned. >>> The fundamental problem behind allowing such "loose" statements is that >>> variables can be declared inside both classes (fields) and methods (local >>> variables), and they share the same syntactic production but not the same >>> semantics. So it is unclear (to both compilers and humans) whether a "loose" >>> variable would be a local or a field. If we tried to adopt some sort of >>> simple >>> heuristic to collapse this ambiguity (e.g., whether it precedes or follows >>> the >>> first statement), that may satisfy the compiler, but now simple refactorings >>> might subtly change the meaning of the program, and we'd be replacing the >>> explicit syntactic overhead of `void main()` with an invisible "line" in the >>> program that subtly affects semantics, and a new subtle rule about the >>> meaning >>> of variable declarations that applies only to unnamed classes. This doesn't >>> help students, nor is this particularly helpful for all but the most trivial >>> programs. It quickly becomes a crutch to be discarded and unlearned, which >>> falls afoul of our "on ramp" goals. Of all the concepts on our list, >>> "methods" >>> and "a program is specified by a main method" seem the ones that are most >>> worth >>> asking students to learn early. >>> ### Why not "just" use `jshell`? >>> While JShell is a great interactive tool, leaning too heavily on it as an >>> onramp >>> would fall afoul of our goals. A JShell session is not a program, but a >>> sequence of code snippets. When we type declarations into `jshell`, they are >>> viewed as implicitly static members of some unspecified class, with >>> accessibility is ignored completely, and statements execute in a context >>> where >>> all previous declarations are in scope. This is convenient for >>> experimentation >>> -- the primary goal of `jshell` -- but not such a great mental model for >>> learning to write Java programs. Transforming a batch of working >>> declarations >>> in `jshell` to a real Java program would not be sufficiently simple or >>> unintrusive, and would lead to a non-idiomatic style of code, because the >>> straightforward translation would have us redeclaring each method, class, >>> and >>> variable declaration as `static`. Further, this is probably not the >>> direction >>> we want to go when we scale up from a handful of statements and >>> declarations to >>> a simple class -- we probably want to start using classes as classes, not >>> just >>> as containers for static members. JShell is a great tool for exploration and >>> debugging, and we expect many educators will continue to incorporate it into >>> their curriculum, but is not the on-ramp programming model we are looking >>> for. >>> ### What about "always local"? >>> One of the main tensions that `main` introduces is that most class members >>> are >>> not `static`, but the `main` method is -- and that forces programmers to >>> confront the seam between static and non-static members. JShell answers this >>> with "make everything static". >>> Another approach would be to "make everything local" -- treat a simple >>> program >>> as being the "unwrapped" body of an implicit main method. We already allow >>> variables and classes to be declared local to a method. We could add local >>> methods (a useful feature in its own right) and relax some of the >>> asymmetries >>> around nesting (again, an attractive cleanup), and then treat a mix of >>> declarations and statements without a class wrapper as the body of an >>> invisible >>> `main` method. This seems an attractive model as well -- at first. >>> While the syntactic overhead of converting back to full-blown classes -- >>> wrap >>> the whole thing in a `main` method and a `class` declaration -- is far less >>> intrusive than the transformation inherent in `jshell`, this is still not an >>> ideal on-ramp. Local variables interact with local classes (and methods, >>> when >>> we have them) in a very different way than instance fields do with instance >>> methods and inner classes: their scopes are different (no forward >>> references), >>> their initialization rules are different, and captured local variables must >>> be >>> effectively final. This is a subtly different programming model that would >>> then >>> have to be unlearned when scaling up to full classes. Further, the result of >>> this wrapping -- where everything is local to the main method -- is also not >>> "idiomatic Java". So while local methods may be an attractive feature, they >>> are >>> similarly not the on-ramp we are looking for.
