The timeline of its promotion from draft status along with several mentions of JDK 21 in the provided examples make it likely to ship with JDK 21 in September.
The section on how the main method will be resolved is a bit painful. I can’t see a way around it that doesn’t do nasty things for composability and/or backwards compatibility, but it does give me pause. Any situation where you have to ask “which main method in this class will be executed?” is quite bad.
Which is why, as part of designing this feature, we ran a corpus search to see what portion of classes with a main method have another main that would be a candidate entry point under this JEP. It was negligible. Additionally, we'll give a linter warning if there's more than one candidate.
As much as it's a crutch in programming language design to say "we don't have to worry too much about the lack of ergonomics in this case, it would be such bad code if this edge case gets run into in the first place," this seems like one of those situations.
Another point: IDEs will be able to tell you which main method will get chosen, which should eliminate at least some uncertainty.
I feel like this is introducing a change for the sake of change, solving a problem which does not exist. The price of this change is very real: adding complexity and bugs to all the tools, IDEs, code analyzers and the like.
There is negative net benefit to pretty much everyone involved, and for what?
That is literally what is addressed by the first section of the document. Both in "Summary" and in "Goals"
> Far from using a separate dialect of Java, students can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow.
I remember when I started with Java 20 years we had a special IDE (BlueJ maybe? DrJava?) that wrapped the main class so that <code>System.out.println("Hello world");</code> was a complete program.
So that is clearly
> Do not introduce a separate beginner's dialect of Java.
Perhaps this is in response to Python growing as an initial programming language (IMHO wrongly because types are fundamental to thinking about programming).
They also mention:
> Reduce the ceremony of writing simple programs such as scripts and command-line utilities.
You can question the merits or trade-offs, but it's very clearly spelled out.
> Reduce the ceremony of writing simple programs such as scripts and command-line utilities.
I think it is important to be able to determine the root cause of a problem first. Do students find difficult to write "public static void main(String[] args)" or do they find difficulty understanding the concepts of a public method, a static method, a void method? Perhaps then we should focus on teaching these concepts, which are essential to java, first, instead of undermining the core of the language and the platform.
Neither "goals" nor "summary" can explain away why this can solve the problem this JEP purports to solve.
> Perhaps then we should focus on teaching these concepts, which are essential to java, first.
As the JEP explains, this change does make the concepts of classes and access modifiers easier to teach by allowing the teacher to postpone their introduction to a point in time when they're actually useful and can be understood. Access control, static, and class declarations are only meaningful once you have other classes and/or objects interacting with your code. We don't want to force teachers to teach programming in the large early because many of them told us they don't do that anyway.
> instead of undermining the core of the language and the platform
The syntax and concepts of anonymous classes are unchanged. Providing an unnamed class, implicitly, when a class isn't needed is consistent with how we already provide an unnamed package and an unnamed module implicitly when they're not needed.
It sounds like you haven't taught or taken an intro to programming course using Java before.
In that situation, instructors might spend weeks trying to get their students to understand variables or control flow concepts. Visibility may be a core concern for you, as a (presumably) professional Java programmer, but it's not at all to programming novices.
This particular problem, in my opinion, has a much simpler solution: a special educational environment. A sort of mini-IDE where two things happen:
1. code written by a student gets inserted into a top-level class's main() method (has to be smart enough to deal with imports, inner classes etc.)
2. the top level class might declar certain utility functions such as print() instead of System.out.println(), and possibly others.
Bingo. No need to mess with something that works just fine for 99.99% of the professional users.
edit, in response to @crummy (as we reached the maximum depth it seems):
Some people commented that it might be beneficial to delay introduction of more complex concepts until the basic ones are digested. So hiding the class/main method would help with that (similar to jshell, I might add). And keep in mid this is an IDE and not java-lite.
> What I really dislike about this JEP is not only that it tries to solve the educational problem in a worst possible manner (my opinion), but it also risks creating a generation of students who don't really understand the fundamental concepts that allow us to write reliable code.
How would your special IDE/forked Java-lite prevent creating a generation of students who don't really understand the fundamental concepts that allow us to write reliable code?
Such an environment already exists, and the JEP rejects it as an option:
> Evolving a batch of working declarations in JShell into a real Java program leads to a non-idiomatic style of code because it declares each method, class, and variable as static... it is not the on-ramp programming model we are looking for.
The problem is when you sit down to teach the beginner, all the boilerplate clutter forces you to either A) teach them the magic incantation to be unquestionably written before they start writing any code, or B) you explain everything before getting into any real programming.
Both suck. In the first case, students are torn away from the mode of thinking that programming thrives in: that everything is made up of simple, understandable pieces, that can be built up into complex solutions. It ends up serving as a trap for the very kind of inquisitive student that is equipped to succeed in programming. In the second case, everyone's bored to tears, and you can be assured that your entire class will be hopelessly lost before they write their first line of code. It's a bad time all around.
Basically, programming wants to be built up with the following concepts, in order:
1. Algorithmic Thinking (solutions can be representing as a series of simple steps)
2. Structured Syntax (these steps can be represented as structured text)
3. Symbolic Reasoning (types, variables, arrays)
4. Control Flow (loops, conditionals)
5. Functions
6. Higher Structures (classes, objects, etc)
Python, IMO, is pretty good pedagogical tool in this regard
print("Hello World")
"We want our computer to display to us (or 'print' in software terms) the phrase 'Hello World'. Python provides us with a built-in way to do so: the "print" function. In the majority of programming languages, we express a call to a function as a command, followed by its inputs (or 'arguments') contained within parentheses. As our one and only argument, we provide what we want printed, in this case the text "Hello World". By wrapping this text in quotes, we can tell the language that we intend this text to be interpreted as a chunk of literal text, called a 'String' rather than as a variable or other symbol for the language."
In contrast, explaining everything going on in the equivalent Java
public class MyFirstClass {
public static void main(String[] args){
System.out.println("Hello World");
}
}
would take more text than I'm willing to hammer into a HN comment, but to be explained to a complete beginner would likely involve skipping, but promising to explain later: classes, functions, "public", "static", "void", command line arguments, and the uniquely weird "System.out", followed by a similar explanation to the Python example, with the added "we end each step with a semicolon".
Please see my response to @pgwhalen. In short, the problem has, I think, a much simpler solution.
What I really dislike about this JEP is not only that it tries to solve the educational problem in a worst possible manner (my opinion), but it also risks creating a generation of students who don't really understand the fundamental concepts that allow us to write reliable code.
Perhaps we need to start teaching basic programming with BASIC instead, and graduate to a more complicated platform once the basic concepts have been understood.
My personal opinion on it is that Java's simply a bad first language, and over-taught in schools. It has a lot of language-specific baggage that it thrusts upon you immediately on first use. My preferred first (university-level) language is Racket, because it's got incredibly simple syntax as a LISP, it's radically batteries-included giving a good sandbox to play in, and segues into CS-theory type stuff pretty damn well. It also has the added bonus of minimizing the impact on the subset of the class with non-trivial programming experience, who otherwise can easily get bored hearing stuff they know already, stop paying attention because they assume they know everything already, and then wash out when the real CS-heavy stuff hits.
But a lot of "universities" treat their "CS" programs as glorified trade schools, and want to focus exclusively on industry-applicable languages, and land on Java because Oracle had a great outreach program. Like it or not, many students will be starting their programming journey in Java, and not fucking it up is probably a good idea.
My approach would have been pretty similar to their listed alternative under "Interpret code units as static members", but that probably comes down to differences over the importance of Object-Oriented principals in beginner programming pedagogy.
Barring that, this proposal really isn't bad. It doesn't break existing code, it does its job well enough. I would have liked there to be support for inline subclasses that can be called from within the same anonymous class environment, but I can see how that would create ambiguity with existing code.
> I would have liked there to be support for inline subclasses that can be called from within the same anonymous class environment, but I can see how that would create ambiguity with existing code.
Not sure what you mean by "inline subclasses", but an anonymous main class can contain class declarations -- just as classes, named or anonymous can today. This file would be a complete legal program:
record Foo(int x, int y) {}
class Bar { static void print(Foo f) { System.out.println(f); } }
void main() {
Bar.print(makeFoo());
}
Foo makeFoo() { return new Foo(3, 4); }
Ah, in that case I take that back. I definitely thought you needed to be able to reference the parent class in order to call (classes defined within other classes, can't remember the nomenclature).
There's no need to do that from within the class. It all works just as it would in an anonymous class today. This code, that employs an anonymous class, is valid Java today (you can paste it into jshell):
new Object() {
record Foo(int x, int y) {}
class Bar { static void print(Foo f) { System.out.println(f); } }
void main() {
Bar.print(makeFoo());
}
Foo makeFoo() { return new Foo(3, 4); }
}.main();
This JEP merely brings together two existing ideas in Java:
1. Anonymous classes
2. Unnamed instances of programming-in-the-large concepts are implicitly provided for you (today this is the case only for packages and modules).
There are no new changes or restrictions to Java syntax in the body of the anonymous class.
I think Java is a fine first language - it has a strongly typed, static runtime with good cross platform support, and stellar backwards compatibility (meaning that you can use decade old code samples as well).
The often touted alternative starting language is C and python, and I believe Java is better than both — C’s mentioned advantage is “learning low level details”, but I don’t see it as necessary, plus C can fail at runtime (or worse, at *some runtime on someone else’s machine) in completely cryptic ways, you may not even realize your program is incorrect until you submit an assignment. I have seen even very smart students be puzzled by it. Also, pointers can be learned afterwards easily, I don’t see it problematic at all.
Python’s problem comes mostly from its dynamically typed nature, it is very hard for new programmers to reason about the runtime state of programs, and why might have it failed on the nth cycle of this loop.
Java is a great in-between. It is not perfect (for example arrays having special syntax is not ideal), but not bad and it being an industry language is just a plus.
Why would it create a generation of students who don’t understand the fundamentals? You will have to use all the language features for anything more complex, it is only for the earlier lessons.
In my experience teaching introductory programming with Java, the problem is very real. For beginning programmers, making sense of the first Java program(s) results too often in misunderstanding of all sorts of concepts.
Of course, you can tell students to ignore most of the code until later in the course when they'll learn all about it, but that doesn't work. They'll make sense of the code within their limited understanding of programming and frames of reference. They'll build local theories of how and why these programming elements, like "static", "class", "main", "String[]" etc. fit together, how they relate to error messages they get when their programs don't compile or don't work.
Then, when they do reach the place in the course when they're to learn all about these concepts, they have to reconcile their own local theories with the material at hand to create a more thorough and evolved understanding of the concept. That's often not an easy process. In many introductory programming courses, there's not much time for reflection. As a result, their evolving understanding is likely closer to their initial understanding instead of the ones we aim at as teachers.
What's not helping here is that as experienced programmers who have developed a deep understanding of these concepts to understand novice's point-of-view and their struggles with the material.
Yes! The easier it is to get started with a language, the easier it is to learn and teach. Rather than focusing on (fighting) tools, you can focus on developing understanding of the core concepts of (Java) programming with a suitable learning trajectory. That's huge. And a boon to keep a language and community relevant. Once schools and teachers move on to other languages for teaching, you have to fight to win programmers over to use your language.
As for the added complexity to the compile or run-time system, that seems mostly an issue for language implementers, not users. It certainly won't be an issue for beginning programmers, so for them and their teachers, there's no tradeoff to pay for.
Thanks for raising this issue. What you describe as "local theories" (I'd say "mental model" but I think we're talking about the same thing) is quite important. We expect beginners to come up with erroneous models as they're exposed to stuff; revising and even discarding such models is intrinsic to learning. One of the benefits of this JEP is to minimize the opportunities for beginners to create erroneous mental models.
I agree. And having to re-evaluate and improve your own mental models or local theories is part of learning anyway. That's not going away with these changes. But I think with these changes, the mental models will be easier to understand for teachers and closer to the model we aim for as teachers. As a result, it should be easier to nudge students into reforming their understanding towards the models we aim for. In particular, we can make easier programming examples because we can strip simple programs of a lot of more advanced boilerplate and syntax.
I've written a ton of Java and I'd find this handy for datetime stuff. Even though I don't use it for my work anymore, I still pull out Java when I need to answer questions like what day is 90 days from now because java.time.* is very well designed. Instead of just using the shell, this makes things a little nicer with less ceremony if I want to do these date calculations in a local file.
I do wonder how much benefit will be gained from this. Is the main method really causing beginners that many problems?
I'd say beginners are much more likely to trip over other problems with the language like using == with String instances, the differences between primitives and objects (e.g. copy-by-value vs copy-by-reference, no methods on a primitive, etc.), or the unending problems with null.
Of course, those may never be resolved, and so we'll have to change something that doesn't really matter instead.
Not sure if you're being sarcastic but the solution to some of those things is on the horizon (e.g. null awareness). Seems like a lot of work is necessary to get there though.
Why would this cause extreme problems for Java where it didn’t for C# doing the same thing a few years ago? I’m honestly asking not having done Java in a few years, as I remember they both had this “you gotta put all the code in classes” problem.
This still seems pretty useless, It'd be nice if java could allow for static interface methods.
interface Program {
static void main(String...args);
}
And then I digressed - heavily.
There have been several times when I've wanted static methods that apply to the specific class - although many of the situations could be shoehorned into a constructor, it's not the best.
You'd also want something like a 'This' meta-class keyword.
interface Foo extends Comparable<This> {
static This(A argA, B argB);
static This difference(This v0, This v1);
static int compare(This v0, This v1);
default int compareTo(This other){
return compare(v0, v1);
}
}
/*
I want to return an instance of my class' own type (defined in a subclass an so unknown),
so I pass every implementation itself as its own generic parameter.
*/
interface Why<W extends Why<W>> implements Comparable<W>{
W someManipulation();
}
class Foo implements Why<Foo> {
@Override
Foo someManipulation(){
....
}
}
To be honest, I think I reacted to how robust this does not feel.
It also blurs the line between static and instance syntax/functionality in a way that does not seem useful - and given that this is intended to reduce barriers to entry, is quite probably harmfully confusing.
I'd love to see them follow with full-blown package-level methods and fields at some point (as alluded to in the alternatives) but this seems like a great minimal change to address a real pain point with learning to code in Java.
Pretty nice! Makes me wonder why they didn't take the final step and say that anything not inside `void main()` gets bundled up into an implicit function run first.
> Eliminating the main method altogether may seem like the natural next step, but it would work against the goal of gracefully evolving a first Java program to a larger one and would impose some non-obvious restrictions (see below):
The "see below" boils down to there being a number of differences between how class-level and method-level code units (fields vs. variables) work, and blurring the line there isn't worth the minor additional effort of writing a main() method.
Question that just now occurs to me: what if you have the follow class and invoke it? (typing without an IDE, forgive any compilation errors). I can imagine answers, but I’m not sure if the JEP explains which one will happen (genuinely unsure, I could’ve easily missed it).
public class Foo {
int x;
public Foo(int x) {
this.x = x;
}
void main() {
System.out.println(x);
}
}
> If a launched class has no static main method but has a non-private zero-parameter constructor ... and a non-private instance main method, then construct an instance of the class... [and] invoke the instance main method
Your class doesn't have a zero-parameter constructor nor a suitable static main, so launching it as a program will fail (as it would today).
When I write the Getting Started for my (FOSS) library, I'll definitely make a JBang variant. (Gitpod and SDKMAN also look interesting.)
The use of Groovy's @Grab et al is also interesting. I'm eager to see how the dependency, imports, modules, local repo cache story, etc story plays out.
Even after all this time, the Java stack still hasn't found its sweet spot. Though I confess I don't know what that'd look like.
My 2¢ is that this will probably do more to confuse than to enlighten students.
Getting your "first" program off the ground quickly is good, but only if it doesn't cripple your understanding of what's going on for months later.
For me the main thing that confuses the crap out of students is how people who introduce java tend to take "shortcuts" and bundle all functionality under the sun into a single class, which then also has a main method at the end. Presumably this is done so that everything is a single file, or can fit in a single presentation slide. But then suddenly your main looks like it's calling its container class to make objects of "itself" that contain new "mains", at which point your student has lost the plot completely.
The simplest thing to keep things clean and self explanatory is to separate everything that isn't "main-related" into its own class (preferably another file if public), and then keep a nice clean public class called "Main" which contains 'only' the main method. Then you get to explain nicely how public classes have their own files, and if you attempt to run this class from the terminal, java will look for the 'main' function, and how this therefore needs to be public, static because you're running it straight from the class, void because you don't depend on it returning a value (which also makes for a nice intermission on how c returns status as an int, but java has a special mechanism instead).
I do agree with the end of the JEP though; if you want to teach simple snippets like System.out.println, jshell is a nice way to do this, if you want to delay talking about classes and their methods.
> But then suddenly your main looks like it's calling its container class to make objects of "itself" that contain new "mains", at which point your student has lost the plot completely.
Exactly. This is one of the problems this JEP attempts to solve.
> separate everything that isn't "main-related" into its own class ... and then keep a nice clean public class called "Main" which contains 'only' the main method. Then you get to explain nicely how public classes have their own files, and if you attempt to run this class from the terminal, java will look for the 'main' function, and how this therefore needs to be public, static because you're running it straight from the class, void because you don't depend on it returning a value
Only then you've taught a number of programming-in-the-large concepts as well as a bunch of Java technicalities -- all designed for the purpose of building large programs in a team -- before teaching what a computer program is.
However, if you use this feature to teach your students and encounter a problem, we would be interested to hear your experience on the amber-dev mailing list.
Java has had a nice focus on "decluttering" improvements lately; I think it's a nice focus to have (if done carefully), as 'verbosity' has always been one of the supposed pain points of java. I would welcome this JEP in this light.
I see this as great for developers already familiar with the language in making code more streamlined. But it's along a similar vein to, say, "anonymous classes can be expressed as lambdas which can in turn be expressed as method references". Or, say, the 'var' keyword as a way to automatically infer the variable type and how memory will be allocated for it, on the basis of the applied constructor. In both cases, the last step may be a nice, simple-looking expression, but it hides a lot of underlying complexity and context, which you need to understand properly to use it effectively.
So the part I 'object' to in the wording of the JEP is the educational intent/strategy implied in the summary. For me there is a big difference between something like "introduce complex idea A at a higher level because simpler idea B depends on it", vs "obfuscate the true nature of A to pretend B can be understood in isolation, and deal with the resulting confusion later". Learning works by creating basic blocks of understanding, consolidating them, and then using them to build more complex blocks later on. Relying on a faulty foundation, hoping to come back and re-build it later on is generally not the best educational strategy (in my humble view).
So from an educational point of view, for me this does not make my job simpler. If I wanted my students to build a solid foundation of understanding, I would have to first explain what classes are, what static methods are, how methods can NOT in fact live outside a class in java, and only THEN explain that "to make things less verbose, in this VERY specific case, java allows you some syntactic-sugar to hide some of that complexity under a simpler-looking syntax, that would otherwise look weird in standard java".
But yes, having said all that, this seems like a nice proposal for the language more generally, that could lead to further similar improvements down the line, and I would be in favour of it! Great work!
> obfuscate the true nature of A to pretend B can be understood in isolation, and deal with the resulting confusion later
What confusion? All the code in the body of an anonymous class is perfectly valid Java code that you can put in the body of an anonymous class today. There is no new magic here.
> I would have to first explain what classes are, what static methods are, how methods can NOT in fact live outside a class in java, and only THEN explain that "to make things less verbose, in this VERY specific case, java allows you some syntactic-sugar to hide some of that complexity under a simpler-looking syntax, that would otherwise look weird in standard java".
I don't think you would.
There is no syntactic sugar here that Java doesn't already do. The body of an anonymous main class is valid as the body of an anonymous class today -- there is no special magic or any kind of special interpretation of code here -- and the notion of "implicitly supply an unnamed instance of a programming-in-the-large concept" is something Java already does today for packages and modules.
Every method lives in a class, every class lives in a package, every package lives in a module. And yet, we don't require you to explicitly declare a package or a module. The current way we treat class declarations is the inconsistent one: it requires a class declaration even when it's not useful.
Classes are no more fundamental to how Java "really" works under the covers than modules and class loaders. And yet, Java doesn't force you to learn these concepts before learning what a variable is or what a loop is. There is simply no way to know how Java really works without understanding modules. Modules are what gives actual meaning to access modifiers. Do you teach modules before loops today?
Classes (and so static) and access modifiers really are completely meaningless before you have more than one class or more than one object, just as modules are meaningless until you have several of them. We are making Java more consistent in not an explicit invocation of a concept that is only meaningful once you add more context to it.
> Every method lives in a class, every class lives in a package, every package lives in a module. And yet, we don't require you to explicitly declare a package or a module. The current way we treat class declarations is the inconsistent one: it requires a class declaration even when it's not useful.
I hadn't thought it like that. Sure, that makes sense from that angle.
That's basically C# top-level programs[0]. IMHO, In C# these are a mixed bag, because once a project becomes more complex a file without a class looks out of place, so it's a feature for beginners/very simple programs. It was controversial enough that VS eventually included an option to create projects without using this...
From the questioning around "needs to import basic utility classes", I'm guessing the feature following this would be something like C# implicit usings?
Working with both stacks, I really hope Java doesn't start going through the C# trends of fighting Python and JS on lines of code to produce an "Hello World" application.
Next step, language changes for Jakarta EE/Spring/Quarkus/Helidon minimal APIs.
Well, ASP.NET (Core) was startup was not exactly intuitive. How many people could type it up without a template? Routing was also way more complex than necessary...
If you have an anonymous class, it can’t be referenced from elsewhere (it has no defined class name) so it is strictly only for small projects, which is imo the correct choice.
But it is easy to “name” it when the program have to grow.
Now students will need to learn the pain of versioning on their first day of class.
Bob: I get this weird error when I run this example from class.
Sally: Works for me! Hey can you try running this?
Bob: oh that works, lots of extra stuff in it. I guess I have to copy all of these things along for an app to work anywhere.
Sally: I guess so - it's weird the simple example works on my laptop and not yours.
Bob: must be a compiler bug, I hear about those alot in the compsci lab.
Personally I think that the compiler should generate a synthetic main entry point when it encounters code that matches the new "launch protocol". It provides a degree of portability and repeatability over relying on the runtime to select the entry point. There are probably downsides here too.
Approximately none. Which is why I would be fine with javac generating a synthetic public static void main(string[] args) that forwards to it when the pattern is encountered.
In this setup the generated classes/jars work fine without extra flags to java and even work on older jvm installations if you pass the right flags to javac at build time. I really struggle to come up with a reason to implement this as a change to java vm over just javac.
I really like this feature as they managed to cut down on verbosity with only a tiny amount of change to the language, the bigger part is done by simply changing the default classloader (it accepting not only public static void main(String… args))
C is already much better, but we still have some boilerplate. Currently this is the bare minimum:
#include <stdio.h>
int main() {
printf("Hello world\n");
return 0;
}
But I wish we could get rid of that "boilerplate" #include. I think compilers could add it by themselves when needed (many already suggest it to you if you forget it, so they do know when it's the case).
On the other hand I wouldn't get rid of the explicit return from main(), as it has an important pedagogical function.
I disagree, #include <stdio.h> implies a system which has a stdout or stdin.
That is not necessarily a case for embedded systems, where maybe at most you can blink an LED as a form of user output.
I don't disagree, but the compiler could insert it automatically when you need it. In those rare cases where e.g. you want to use a function called printf() that's not the standard printf(), you explicitly opt out of the default via a compiler argument, a #pragma, etc.
This is easily 20 years overdue. It was obviously a major problem in the 2000s. It's not even about pedagogy -- the lack of ceremony for simple calculations is one of the reasons I reach for Python or even Typescript before Java to do one-off experiments, programming puzzles, or anything else.
66 comments
[ 3.6 ms ] story [ 136 ms ] threadAnother point: IDEs will be able to tell you which main method will get chosen, which should eliminate at least some uncertainty.
Glad to see them evolving faster as a result
There is negative net benefit to pretty much everyone involved, and for what?
> Far from using a separate dialect of Java, students can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow.
I remember when I started with Java 20 years we had a special IDE (BlueJ maybe? DrJava?) that wrapped the main class so that <code>System.out.println("Hello world");</code> was a complete program.
So that is clearly
> Do not introduce a separate beginner's dialect of Java.
Perhaps this is in response to Python growing as an initial programming language (IMHO wrongly because types are fundamental to thinking about programming).
They also mention:
> Reduce the ceremony of writing simple programs such as scripts and command-line utilities.
You can question the merits or trade-offs, but it's very clearly spelled out.
> Reduce the ceremony of writing simple programs such as scripts and command-line utilities.
I think it is important to be able to determine the root cause of a problem first. Do students find difficult to write "public static void main(String[] args)" or do they find difficulty understanding the concepts of a public method, a static method, a void method? Perhaps then we should focus on teaching these concepts, which are essential to java, first, instead of undermining the core of the language and the platform.
Neither "goals" nor "summary" can explain away why this can solve the problem this JEP purports to solve.
This is my opinion, of course.
As the JEP explains, this change does make the concepts of classes and access modifiers easier to teach by allowing the teacher to postpone their introduction to a point in time when they're actually useful and can be understood. Access control, static, and class declarations are only meaningful once you have other classes and/or objects interacting with your code. We don't want to force teachers to teach programming in the large early because many of them told us they don't do that anyway.
> instead of undermining the core of the language and the platform
The syntax and concepts of anonymous classes are unchanged. Providing an unnamed class, implicitly, when a class isn't needed is consistent with how we already provide an unnamed package and an unnamed module implicitly when they're not needed.
In that situation, instructors might spend weeks trying to get their students to understand variables or control flow concepts. Visibility may be a core concern for you, as a (presumably) professional Java programmer, but it's not at all to programming novices.
1. code written by a student gets inserted into a top-level class's main() method (has to be smart enough to deal with imports, inner classes etc.)
2. the top level class might declar certain utility functions such as print() instead of System.out.println(), and possibly others.
Bingo. No need to mess with something that works just fine for 99.99% of the professional users.
edit, in response to @crummy (as we reached the maximum depth it seems):
Some people commented that it might be beneficial to delay introduction of more complex concepts until the basic ones are digested. So hiding the class/main method would help with that (similar to jshell, I might add). And keep in mid this is an IDE and not java-lite.
> What I really dislike about this JEP is not only that it tries to solve the educational problem in a worst possible manner (my opinion), but it also risks creating a generation of students who don't really understand the fundamental concepts that allow us to write reliable code.
How would your special IDE/forked Java-lite prevent creating a generation of students who don't really understand the fundamental concepts that allow us to write reliable code?
> Evolving a batch of working declarations in JShell into a real Java program leads to a non-idiomatic style of code because it declares each method, class, and variable as static... it is not the on-ramp programming model we are looking for.
As Brian Goetz would say, this is a classic “why not just” take.
Both suck. In the first case, students are torn away from the mode of thinking that programming thrives in: that everything is made up of simple, understandable pieces, that can be built up into complex solutions. It ends up serving as a trap for the very kind of inquisitive student that is equipped to succeed in programming. In the second case, everyone's bored to tears, and you can be assured that your entire class will be hopelessly lost before they write their first line of code. It's a bad time all around.
Basically, programming wants to be built up with the following concepts, in order:
1. Algorithmic Thinking (solutions can be representing as a series of simple steps)
2. Structured Syntax (these steps can be represented as structured text)
3. Symbolic Reasoning (types, variables, arrays)
4. Control Flow (loops, conditionals)
5. Functions
6. Higher Structures (classes, objects, etc)
Python, IMO, is pretty good pedagogical tool in this regard
"We want our computer to display to us (or 'print' in software terms) the phrase 'Hello World'. Python provides us with a built-in way to do so: the "print" function. In the majority of programming languages, we express a call to a function as a command, followed by its inputs (or 'arguments') contained within parentheses. As our one and only argument, we provide what we want printed, in this case the text "Hello World". By wrapping this text in quotes, we can tell the language that we intend this text to be interpreted as a chunk of literal text, called a 'String' rather than as a variable or other symbol for the language."In contrast, explaining everything going on in the equivalent Java
would take more text than I'm willing to hammer into a HN comment, but to be explained to a complete beginner would likely involve skipping, but promising to explain later: classes, functions, "public", "static", "void", command line arguments, and the uniquely weird "System.out", followed by a similar explanation to the Python example, with the added "we end each step with a semicolon".Please see my response to @pgwhalen. In short, the problem has, I think, a much simpler solution.
What I really dislike about this JEP is not only that it tries to solve the educational problem in a worst possible manner (my opinion), but it also risks creating a generation of students who don't really understand the fundamental concepts that allow us to write reliable code.
Perhaps we need to start teaching basic programming with BASIC instead, and graduate to a more complicated platform once the basic concepts have been understood.
But a lot of "universities" treat their "CS" programs as glorified trade schools, and want to focus exclusively on industry-applicable languages, and land on Java because Oracle had a great outreach program. Like it or not, many students will be starting their programming journey in Java, and not fucking it up is probably a good idea.
My approach would have been pretty similar to their listed alternative under "Interpret code units as static members", but that probably comes down to differences over the importance of Object-Oriented principals in beginner programming pedagogy.
Barring that, this proposal really isn't bad. It doesn't break existing code, it does its job well enough. I would have liked there to be support for inline subclasses that can be called from within the same anonymous class environment, but I can see how that would create ambiguity with existing code.
Not sure what you mean by "inline subclasses", but an anonymous main class can contain class declarations -- just as classes, named or anonymous can today. This file would be a complete legal program:
1. Anonymous classes
2. Unnamed instances of programming-in-the-large concepts are implicitly provided for you (today this is the case only for packages and modules).
There are no new changes or restrictions to Java syntax in the body of the anonymous class.
The often touted alternative starting language is C and python, and I believe Java is better than both — C’s mentioned advantage is “learning low level details”, but I don’t see it as necessary, plus C can fail at runtime (or worse, at *some runtime on someone else’s machine) in completely cryptic ways, you may not even realize your program is incorrect until you submit an assignment. I have seen even very smart students be puzzled by it. Also, pointers can be learned afterwards easily, I don’t see it problematic at all.
Python’s problem comes mostly from its dynamically typed nature, it is very hard for new programmers to reason about the runtime state of programs, and why might have it failed on the nth cycle of this loop.
Java is a great in-between. It is not perfect (for example arrays having special syntax is not ideal), but not bad and it being an industry language is just a plus.
Of course, you can tell students to ignore most of the code until later in the course when they'll learn all about it, but that doesn't work. They'll make sense of the code within their limited understanding of programming and frames of reference. They'll build local theories of how and why these programming elements, like "static", "class", "main", "String[]" etc. fit together, how they relate to error messages they get when their programs don't compile or don't work.
Then, when they do reach the place in the course when they're to learn all about these concepts, they have to reconcile their own local theories with the material at hand to create a more thorough and evolved understanding of the concept. That's often not an easy process. In many introductory programming courses, there's not much time for reflection. As a result, their evolving understanding is likely closer to their initial understanding instead of the ones we aim at as teachers.
What's not helping here is that as experienced programmers who have developed a deep understanding of these concepts to understand novice's point-of-view and their struggles with the material.
Learning and teaching is hard!
As for the added complexity to the compile or run-time system, that seems mostly an issue for language implementers, not users. It certainly won't be an issue for beginning programmers, so for them and their teachers, there's no tradeoff to pay for.
I'd say beginners are much more likely to trip over other problems with the language like using == with String instances, the differences between primitives and objects (e.g. copy-by-value vs copy-by-reference, no methods on a primitive, etc.), or the unending problems with null.
Of course, those may never be resolved, and so we'll have to change something that doesn't really matter instead.
This still seems pretty useless, It'd be nice if java could allow for static interface methods.
And then I digressed - heavily.There have been several times when I've wanted static methods that apply to the specific class - although many of the situations could be shoehorned into a constructor, it's not the best.
You'd also want something like a 'This' meta-class keyword.
To be honest, I think I reacted to how robust this does not feel.It also blurs the line between static and instance syntax/functionality in a way that does not seem useful - and given that this is intended to reduce barriers to entry, is quite probably harmfully confusing.
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tu...
https://learn.microsoft.com/en-us/dotnet/api/system.numerics...
> Eliminating the main method altogether may seem like the natural next step, but it would work against the goal of gracefully evolving a first Java program to a larger one and would impose some non-obvious restrictions (see below):
The "see below" boils down to there being a number of differences between how class-level and method-level code units (fields vs. variables) work, and blurring the line there isn't worth the minor additional effort of writing a main() method.
public class Foo {
> If a launched class has no static main method but has a non-private zero-parameter constructor ... and a non-private instance main method, then construct an instance of the class... [and] invoke the instance main method
Your class doesn't have a zero-parameter constructor nor a suitable static main, so launching it as a program will fail (as it would today).
Don't forget to support shebang. So we can finally use Java as a system scripting language.
Maybe something like:
And maybe also allow specifying the runtime version:When I write the Getting Started for my (FOSS) library, I'll definitely make a JBang variant. (Gitpod and SDKMAN also look interesting.)
The use of Groovy's @Grab et al is also interesting. I'm eager to see how the dependency, imports, modules, local repo cache story, etc story plays out.
Even after all this time, the Java stack still hasn't found its sweet spot. Though I confess I don't know what that'd look like.
Getting your "first" program off the ground quickly is good, but only if it doesn't cripple your understanding of what's going on for months later.
For me the main thing that confuses the crap out of students is how people who introduce java tend to take "shortcuts" and bundle all functionality under the sun into a single class, which then also has a main method at the end. Presumably this is done so that everything is a single file, or can fit in a single presentation slide. But then suddenly your main looks like it's calling its container class to make objects of "itself" that contain new "mains", at which point your student has lost the plot completely.
The simplest thing to keep things clean and self explanatory is to separate everything that isn't "main-related" into its own class (preferably another file if public), and then keep a nice clean public class called "Main" which contains 'only' the main method. Then you get to explain nicely how public classes have their own files, and if you attempt to run this class from the terminal, java will look for the 'main' function, and how this therefore needs to be public, static because you're running it straight from the class, void because you don't depend on it returning a value (which also makes for a nice intermission on how c returns status as an int, but java has a special mechanism instead).
I do agree with the end of the JEP though; if you want to teach simple snippets like System.out.println, jshell is a nice way to do this, if you want to delay talking about classes and their methods.
Exactly. This is one of the problems this JEP attempts to solve.
> separate everything that isn't "main-related" into its own class ... and then keep a nice clean public class called "Main" which contains 'only' the main method. Then you get to explain nicely how public classes have their own files, and if you attempt to run this class from the terminal, java will look for the 'main' function, and how this therefore needs to be public, static because you're running it straight from the class, void because you don't depend on it returning a value
Only then you've taught a number of programming-in-the-large concepts as well as a bunch of Java technicalities -- all designed for the purpose of building large programs in a team -- before teaching what a computer program is.
However, if you use this feature to teach your students and encounter a problem, we would be interested to hear your experience on the amber-dev mailing list.
I see this as great for developers already familiar with the language in making code more streamlined. But it's along a similar vein to, say, "anonymous classes can be expressed as lambdas which can in turn be expressed as method references". Or, say, the 'var' keyword as a way to automatically infer the variable type and how memory will be allocated for it, on the basis of the applied constructor. In both cases, the last step may be a nice, simple-looking expression, but it hides a lot of underlying complexity and context, which you need to understand properly to use it effectively.
So the part I 'object' to in the wording of the JEP is the educational intent/strategy implied in the summary. For me there is a big difference between something like "introduce complex idea A at a higher level because simpler idea B depends on it", vs "obfuscate the true nature of A to pretend B can be understood in isolation, and deal with the resulting confusion later". Learning works by creating basic blocks of understanding, consolidating them, and then using them to build more complex blocks later on. Relying on a faulty foundation, hoping to come back and re-build it later on is generally not the best educational strategy (in my humble view).
So from an educational point of view, for me this does not make my job simpler. If I wanted my students to build a solid foundation of understanding, I would have to first explain what classes are, what static methods are, how methods can NOT in fact live outside a class in java, and only THEN explain that "to make things less verbose, in this VERY specific case, java allows you some syntactic-sugar to hide some of that complexity under a simpler-looking syntax, that would otherwise look weird in standard java".
But yes, having said all that, this seems like a nice proposal for the language more generally, that could lead to further similar improvements down the line, and I would be in favour of it! Great work!
What confusion? All the code in the body of an anonymous class is perfectly valid Java code that you can put in the body of an anonymous class today. There is no new magic here.
> I would have to first explain what classes are, what static methods are, how methods can NOT in fact live outside a class in java, and only THEN explain that "to make things less verbose, in this VERY specific case, java allows you some syntactic-sugar to hide some of that complexity under a simpler-looking syntax, that would otherwise look weird in standard java".
I don't think you would.
There is no syntactic sugar here that Java doesn't already do. The body of an anonymous main class is valid as the body of an anonymous class today -- there is no special magic or any kind of special interpretation of code here -- and the notion of "implicitly supply an unnamed instance of a programming-in-the-large concept" is something Java already does today for packages and modules.
Every method lives in a class, every class lives in a package, every package lives in a module. And yet, we don't require you to explicitly declare a package or a module. The current way we treat class declarations is the inconsistent one: it requires a class declaration even when it's not useful.
Classes are no more fundamental to how Java "really" works under the covers than modules and class loaders. And yet, Java doesn't force you to learn these concepts before learning what a variable is or what a loop is. There is simply no way to know how Java really works without understanding modules. Modules are what gives actual meaning to access modifiers. Do you teach modules before loops today?
Classes (and so static) and access modifiers really are completely meaningless before you have more than one class or more than one object, just as modules are meaningless until you have several of them. We are making Java more consistent in not an explicit invocation of a concept that is only meaningful once you add more context to it.
I hadn't thought it like that. Sure, that makes sense from that angle.
Putting code in a single file is definitely an asset for instruction, whether Java, C, Python, JavaScript, etc.
That said, a Java file can have multiple classes (though just one public class).
https://dev.java/learn/single-file-program/
From the questioning around "needs to import basic utility classes", I'm guessing the feature following this would be something like C# implicit usings?
[0] https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/#t...
IIRC C# doesn't have the complex main selection as in here because it relies on csproj files.
Next step, language changes for Jakarta EE/Spring/Quarkus/Helidon minimal APIs.
But it is easy to “name” it when the program have to grow.
Bob: I get this weird error when I run this example from class.
Sally: Works for me! Hey can you try running this?
Bob: oh that works, lots of extra stuff in it. I guess I have to copy all of these things along for an app to work anywhere.
Sally: I guess so - it's weird the simple example works on my laptop and not yours.
Bob: must be a compiler bug, I hear about those alot in the compsci lab.
Personally I think that the compiler should generate a synthetic main entry point when it encounters code that matches the new "launch protocol". It provides a degree of portability and repeatability over relying on the runtime to select the entry point. There are probably downsides here too.
In this setup the generated classes/jars work fine without extra flags to java and even work on older jvm installations if you pass the right flags to javac at build time. I really struggle to come up with a reason to implement this as a change to java vm over just javac.
On the other hand I wouldn't get rid of the explicit return from main(), as it has an important pedagogical function.
Will allows for easy experimentation. Once you need to use methods, put it into a static method and a class.