> Worse, the early exposure to static methods will turn out to be a bad habit that must be later unlearned.
I have been using Java since 1.0 and it is my default language. I am writing Java code today.
I write functions using ‘static’ all the time. I prefer that a function be static. It shows that it does not depend on state of the enclosing object. Using ‘static’ on methods is not a bad habit. Having static fields and state is to be avoided.
By far one of the most common errors I see as a CS instructor is aggressive over-reliance on global state. Not global methods, but state. However, usually what causes the student to reach for global state is the fact that it can be accessed from a static method like main; In lieu of figuring out how to structure a class, they reach for the easier "just make the variable static" approach. Allowing the initialization sequence to call main on an instance via the class's zero-arg constructor seems like it would address the point.
Recently I tried another take on the same idea: using default methods in Interfaces. It has nice properties, as it enables ~mixins in a way not dissimilar to what Scala provides, and enables overriding (e.g. for tests). Give it a try, it's ... refreshing :)
Fine, but that's not relevant to the subject of this document, the "first program", as it would make all fields static, too, and so methods would still be dependent on state. It will just make moving to the next step harder; as the article says: 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.
A good clean programming have it is to wrap all of your stream()/lambdas chains in a static method that describes what they do. This make sure they don’t have access to the local scope and can mutate data.
I'm not really sure what they're on about.
This is totally false. It will always depend on the use case.
The change I would most like to see in a new Java syntax would be to make final and immutable the default. Force the programmer to make clear where state lives.
I especially like the language team’s very conservative attitude, valuing backwards compatibility greatly. Here, they again solve most of the problem by simply changing the “program launcher” code, without any modifications/special casing done on the language level. For the rest, we will see. I think foregoing public requirements is a no-brainer, the rest may need a bit further thought based on further comments, here is the mailing list: https://mail.openjdk.org/pipermail/amber-spec-observers/2022...
As a (mostly) python and C++ programmer, Java feels like someone is afraid they’re speaking to an imbecile, so they constantly repeat themselves and over-explain every point.
Jvm developers also take backwards compatibility seriously which is a concern for companies that will be around for more than a year or two.
While I reach for Python for one-off and random small stuff, the lack of types, it’s lack of performance, and the significant spacing make it challenging to share code and maintain.
Java certainly has its place and the changes in this article certainly expand its footprint.
C++ devs seem to live in a bubble of self admiration, spending hours over engineering under-performing applications they never profile - after all, profiling is like debugging: it's for people who cant code :p
Another example: the lack of literals for collections in Java. Imagine this:
Map x = {"a": "A", "b": "B"}; // not Java
vs: Map x = new java.util.HashMap();
x.put("a", "A");
x.put("b", "B");
The first case is more declarative, and thus easier to grasp.
In the second case you have to read, parse and "execute" line by line in your head... (Does ordering matter? Does line 3 depend on line 2?, etc).When things like these compound, you end up with code-bases many times bigger and harder to grasp than in other languages.
Granted: you can write shitty code in any language, nothing will save you from that... But I think Java makes it harder to write simple and concise code, even to experienced coders.
Then there's also the "cultural" thing many already mentioned ("enterprise Java")... which is very real, but no JEP/JSR will fix that ;-).
Brian shows brilliance, even at "trivial" issues. I trust his judgement :-).
var ages = Map.of("sarah",19, "dan",35); //valid javaStressing the point: this welcomed improvement on the API is a lot more than "saving keystrokes".
I find that I use structures like that primarily when interfacing with other loosely-typed languages, like Javascript, which do encourage you to create structures on the fly like that. Impedance mismatch is always a pain, no matter where it occurs.
That's not to say Java doesn't want you to use Maps. They do -- but only when the content is dynamic. They don't want to add literals for it because that's the opposite of their goal.
There are days when you want it anyway, and then you grumble that the language has forced you to do something ugly. But every language is a set of tradeoffs where some things are ugly, other things are pretty, and the language spec doesn't require a shelf of its own.
A cleaner/simpler alternative was Kobalt, but it’s now abandoned. A simple, official build tool would make the ecosystem easier to learn.
They’ve had great tools along these lines in the Clojure world where the repl/shell has been around longer (deps.edn+repl and boot).
The biggest issue for teaching Java is IMHO not really the syntax of hello world - as Brian says, teachers can handwave this by saying they'll explain it later. It's worth improving mostly because it helps regular programmers who want to use Java in a scripting-like way. The more fundamental difficulty that newbies have is showing other people what they've done.
In the old JRE days it was easy - just send them a fat JAR that opens up a window with Swing and does some cool stuff. Your friends/parents/teachers/etc would probably have a JRE installed already and it'd all just work. In recent years they've abandoned the idea of a JRE and JARs as an app format. You can still open up a window with Swing or JavaFX and get scribbling, but now to show anyone what you did they want you to bundle the JVM and make a more 'native' style app with it. There's a lot to recommend that approach overall, but it's unquestionably harder for learners.
Last year I was discussing this problem with Dmitry Jemerov (product manager for IntelliJ). He sees this issue directly - learners download IntelliJ, get some cool pixels on screen with Swing or JavaFX and then hit a brick wall when they want to send their program to other people. They ask around and it becomes "oh why aren't you learning web dev?" and then they balk when they realize that involves learning 3 new languages and maybe server sysadmin stuff. App stores don't help here because Apple/MS don't like their nice discovery system being gunked up with "my first code" stuff. Even if they stick with Java and try to learn jpackage they quickly realize they need Windows, and a Mac, and maybe Linux just to make packages that their friends can run at all, and then having done all that there's no way to push updates!
We were discussing this problem in the context of maybe doing integrating IntelliJ together with Conveyor [1], a tool my company has been writing that makes desktop app distribution drastically simpler. Actually if you are OK with self-signing it's no harder than compiling Markdown to HTML is, the workflow is very similar. Even if you want to sign it's still very easy; the hardest part is just the general bureaucracy involved with buying the certs. It works for any kind of app including Electron or native apps, but of course with a JVM app you don't have to cross-build anything and Java GUI toolkits are a bit easier to learn than web dev.
There's more work to do here, for instance drawing icons is tedious and when learning a distraction, so we've got a feature in development that draws icons for you. And whilst you can upload the resulting package repository to GitHub Releases, that's not automated and it could be.
I think we're pretty close now to basically abolishing this on-ramp/off-cliff, at least if your users are willing to copy/paste commands to the terminal (due to the self-signing; if you supply real code signing certs the UX is obviously much nicer). Getting rid of the code signing requirements means sandboxing but that's a bigger lift.
BTW - Conveyor is actually implemented as a parallel incremental task-caching build system, internally. We've generalized it and are currently experimenting with that for some of our own build needs. We're some way from being able to replace Maven/Gradle but totally agree that usability of existing build tools is very poor. Usability is in fact the primary ground on which this experimental build system differentiates.
And when they test it on Windows they'll realize that the launcher that jpackage creates does something weird on startup (possibly involving relaunching itself? [1]) that makes Windows display a busy cursor for a while after the program has launched, so they'll have to forget about jpackage and redo it all with something like Packr [2] and Wix# [3]...
[1] https://github.com/openjdk/jdk/blob/fe45835f7cebfccd4544ae19...
Do serious people actually complain about this often? I think it's more of a drive-by comment from people who don't like Java for whatever other reasons.
It does however have some stuff that's plain dumb (can't have functions outside classes, public static void main(String[]), ...) some of it isn't even fixable (default visibility should be private, final should be like const in C++, or even better like const in D).
This is a change that takes very little effort and doesn't impact professional development in the slightest.
Maybe Java has changed in the last 5 years, but idiomatic Go has much, much, much less boilerplate than the idiomatic Java I used to know.
E.g. Foo.java
println("foo")
Becomes: class Foo implements Runnable {
void run() {
System.out.println("foo");
}
}
Then running java Foo.java instead just stubs a main() that looks like: class Main {
void main() {
new Foo().run();
}
}Instead of stubbornly implementing Runnable from those flat files, mix in the well-established concept of single-function-interfaces (Runnable is just one of many) and introduce a top-level "extends" that makes the file body an SFI implementation:
extends java.lang.Runnable;
java.lang.System.out.println("Hello world");
(and it only gets better if you also add the rule "in absence of any imports statements, an implicit import java.lang.*; is added)BTW, I think the pedantic view on this based on the (mailing list discussion) is that it becomes java.lang.StaticImports.println("Hello"), which calls System.out.println.
1. Single file single function imperative
2. Single file multi-function imperative (introduce multiple functions)
3. OO (introduce classes etc)
My understanding is that the ceremony and redundancy is deliberate. You type the same meaning multiple times so the compiler can detect inconsistencies and tell you about them. I.e. it's a feature, not a bug. Slightly analogous to type annotations or unit tests, one wants to write the redundant information in exchange for compiler diagnostics.
Syntactic sugar to make the language less annoying to work in is opposed to that goal, hard to guess if that's better for the target market.
I don't think you need to understand every single character of your very first program right from the beginning. A few of the concepts can be hand waved away to be explained in a later chapter without impeding the overall understanding of programs once you left the sub-twenty-lines beginner programs.
And one could argue that quickly writing up some program happens often regardless of skillset (I do make at least two psvm Main classes per month), so the code reduction there is also a welcome change.
For me it seems like a reaction to JavaScripts and Pythons of this world, optimizing for Hello World just to win over them on those 30 seconds.
They are going to rewrite their applications anyway, when performance comes knocking on the door.
Read the article, the "static trap" is a real thing for new students (on top of all other ceremony). To solve the issue of main being non-static some students will start to put static everywhere as a 'fix' to their initial issue, a day or two later they'll be asking why every student gets the same name (because they have one static variable to keep the student or name objects).
The verbosity of Java also introduces another more serious problem for learning, not only do the students have problems compiling, they also start putting their mind on focusing on syntax instead of logic once they're past the first few problems. The issue of de-programming students from this affliction is waaay too common to be ignored.
Java needs staunchly maintain its static type nature rather than move towards a ‘everything is a string/array whatever’. The concept of types are not only powerful, performant, but they are way to grasp conceptually because the Java semantics and compile time checking.
I do wish CDI (or SpringFramewotk) was brought into CS and similar degrees. Dependency Injection brings a large number of good habits to developers, but it is a concept that is hard to teach as an employer. In our onboarding program, we have to teach people about the CDI container (a program ruining your program) managing all of your state for you (to great benefit and speed of development). During this time, we’re not getting much value out of the developer, and the teacher is also away from their normal duties as well. :/
This article misses the point, however. The problem is not writing your first hello world. The ceremony is not so much in the language itself but in the infrastructure. The verbosity of the language is just the tip of the iceberg.
I think Java back in the 90's started out actually quite decently, although from the get-go it had the verbosity. But at least it didn't have everything else yet that you're expected to know for any non-trivial program.
The first time the word "enterprise" appeared together with Java was the moment it went all downhill.
https://www.boston.com/culture/lifestyle/2011/07/19/literall...
My concept is much more powerful by having a new kind of class declaration alongside 'record' and 'enum' - 'entrypoint'.
main() { println("Hello World"); }
I know that this notation is traditionally reserved for constructors but I'm not 100% sure why we cannot differentiate between methods and constructors just by looking at class name?
The proposed changes don’t have these negatives, while still provide benefits.
And i do not buy your argument that it will break the grammar, the parser of javac consider constructors as methods.
Well no, because that on-ramps you to Groovy, not Java.
At a more intermediate level Effective Java 3rd edition is a must read.
Did Java's papa get jealous?
But I don't think you're entirely wrong to suggest that competition had something to do with this. Python is one of Java's main competitors, and when it comes to teaching a first language it is the main competitor. Both students and teachers who prefer Python as a first language mentioned this "on-ramp" problem as one of the reasons. There are others, and they will be addressed by other enhancements.
[1]: Java's "charter" calls for it being a last mover, adopting features after they've been successfully used elsewhere
[2]: Although there is one I hope it would one day -- nullability types.
On the JVM: I'd say yes.
Scala, Groovy, Jython, JRuby, and what not came and went.
I'd say Clojure is the third, and it take a nice place in the design space.
But Kotlin to me is so close to Java that it is basically Java 2.0: the Java that Java cannot be due to intended organizational slowness.
> Python is one of Java's main competitors, and when it comes to teaching a first language it is the main competitor.
Yes it probably is. The changes outlines in the article are not going to help here I'm afraid.
But I'm weird. I'd say the best lang without static typing for noobs is a LISP (so that every student is likely equally confused). When learning a language with types go for Rust or Idris. All not exactly competitors of Java :)