Live data from Hacker News

Rating 26 years of Java changes

neilmadden.blog

51–60 of 327 posts

Re: Rating 26 years of Java changes

#51
post #9

Earlier quoted context omitted.

I used to joke that the direction spring was heading was that you’d have an application be a boilerplate main method with a dozen lines of annotations. Then I actually encountered this in the wild: we had an app that sent updates from db2 to rabbitmq, and the application literally was just configuration via annotations and no actual Java code other than the usual spring main method.

this is exactly why spring succeeded. I need to run a scheduled job, @EnableScheduling then @Scheduled(cron = “xxxxxx”) - done. I need XYZ, @EnableXYZ the @XYZ… sh*t just works…

Yeah, it works until it isn't. And they good luck debugging it. I'd prefer simple obvious linear code calling some functions over this declarative magic any day.

    cronService.schedule("xxx", this::refresh);
This isn't any harder than annotation. But you can ctrl+click on schedule implementation and below easily. You can put breakpoint and whatnot.

Re: Rating 26 years of Java changes

#52
I’m sure there are better ways to do streams on the JVM, scala being a great example, but however imperfect the implementation is streams are such a net positive I can’t imagine the language without them. I pine for the streams API when I write go.

Re: Rating 26 years of Java changes

#53
post #5

Definitely underrates the impact of annotations. I'm personally not a fan of the way annotations are used to implicitly wire together applications, but I have to admit the impact. Maybe 5/10 is fair in light of the wide range of positive and extremely negative ways annotations can be used. So many of these features were adopted after they were proven in other languages. You would expect that since Java took such a sl…

which is kinda horrifying - it means the framework designers didn't find the language powerful enough to express app logic, and hotglued their own custom arbitrary behavior on top of it.

Clear language code should be endeavor to be readable/understandable when printed on a sheet of paper by anyone, acceptable code should be understandable by anyone who knows a bit about the technologies and has some IDE support.

Garbage code is what you have when the code in question is only understandable when you actually run it, as it uses arbitrary framework logic to wire things together based on metadata on the fly.

Re: Rating 26 years of Java changes

#54

Earlier quoted context omitted.

It's called type inference and it's the way things should be. You get the same types but you don't have to spell them out everywhere. Java doesn't even go all the way, check OCaml to see full program inference.

OCaml's type inference is truly amazing, makes it such a delight to write statically typed code - reading it on the other hand... But I think that's easily solved by adding type annotations for the return type of methods - annotating almost anything else is mostly just clutter imo.

Annotations would be a substitute for writing the return type. Extra code for a shortcut seems like the worst solution.

Re: Rating 26 years of Java changes

#56
post #5

Definitely underrates the impact of annotations. I'm personally not a fan of the way annotations are used to implicitly wire together applications, but I have to admit the impact. Maybe 5/10 is fair in light of the wide range of positive and extremely negative ways annotations can be used. So many of these features were adopted after they were proven in other languages. You would expect that since Java took such a sl…

That's not how the OpenJDK sees things. They tend to think that the features they deliver are at best mildly informed by other languages. Not out of some sense of hubris, but out of a sense of pragmatics: Simply copy and pasting features from other languages into java - that would produce a frankenstein.

For example, java is somewhat unique in having lambda syntax where the lambda *must* be compile-time interpretable as some sort of 'functional type' (a functional type being any interface that defines precisely 1 unimplemented method). The vast, vast majority of languages out there, including scala which runs on the JVM, instead create a type hierarchy that describe lambdas as functions, and may (in the case of scala for example) compile-time automatically 'box'/'cast' any expression of some functional type to a functional interface type that matches.

Java's approach is, in other words, unique (as far as I know).

There was an alternate proposal available at the time that would have done things more like other languages does them, completely worked out with proof of concept builds readily available (the 'BGGA proposal'). The JVM would autogenerate types such as `java.lang.function.Function2` (representing a function that takes 2 arguments, first of type A second of type B, and returns a value of type R), would then treat e.g. the expression:

`(String a, List b) -> 2.0;`

As a `Function2, Double>`, and would also 'auto-box' this if needed, e.g. if passing that as the sole argument to a function:

``` void foo(MyOperation o) {}

interface MyOperation { Double whatever(String arg1, List arg2); } ```

This proposal was seriously considered but rejected.

The core problem with your comment is this:

Define the terms "polished" and "elegant". It sounds so simple, but language features are trying to dance to quite a few extremely different tunes, and one person's 'elegance' is another person's 'frankensteinian monster'.

The same mostly goes for your terms "beauty" and "charm", but, if I may take a wild stab in the dark and assume that most folks have a very rough meeting of the minds as to whatever might be a "charming" language: I know of no mainstream long-term popular languages that qualify for those terms. And I think that's inherent. You can't be a mainstream language unless your language is extremely stable. When you're not just writing some cool new toy stuff in language X - you're writing production code that lots of euros and eyeballs are involved in, and there's real dependence on that software continuing to run, then you __must__ have stability or it becomes extremely pricey to actually maintain it.

With stability comes the handcuffs: You need to use the 'deprecation' hammer extremely sparingly, essentially never. And that has downstream effects: You can't really test new features either. So far I have not seen a language that truly flourishes on the crutches of some `from future import ...` system. That makes some sense: Either the entire ecosystem adopts the future feature and then breaking _that_ brings the same headaches, or folks don't use these features / only for toy stuff, and you don't get nearly the same amount of experience from its deployment.

Said differently: If java is a frankenstein, so is Javascript, C#, Python, Ruby, Scala, and so on. They have to be.

I'd love to see a language whose core design principles are 100% focussed on preventing specifically that. Some sort of extreme take on versioning of a language itself that we haven't seen before. I don't really know what it looks like, but I can't recall any language that put in the kind of effort I'd want to see here. This is just a tiny sliver of what it'd take:

* The language itself is versioned, and all previous versions continue to be part of the lang spec and continue to be maintained by future compilers. At least for a long time, if not forever.

* ALL sources files MUST start with an indication about which version of the language itself they use.

* The core libraries are also versioned, and separately. Newer versions are written against old language versions, or can be used by source on old language versions.

* The system's compilers and tools are fundamentally operating on a 'project' level granularity. You can't compile individual source files. Or if you can, it's because the spec explains how a temporary nameless project is implied by such an act.

* All versions ship with a migrator tool, which automatically 'updates' sources written for lang ver X to lang ver X+1, automatically applying anything that has a near-zero chance of causing issues, and guiding the programmer to explicitly fixing all deprecated usages of things where an automated update is not available.

* The language inherently supports 'facades'; a way for a library at version Y to expose the API it had at version X (X is older than Y), but using the data structures of Y, thus allowing interop between 2 codebases that both use this library, one at version X and one at version Y.

That language might manage the otherwise impossible job of being 'elegant', 'simple', 'mainstream', 'suitable for serious projects', and 'actually good'.

Re: Rating 26 years of Java changes

#57
post #29
post #5

Definitely underrates the impact of annotations. I'm personally not a fan of the way annotations are used to implicitly wire together applications, but I have to admit the impact. Maybe 5/10 is fair in light of the wide range of positive and extremely negative ways annotations can be used. So many of these features were adopted after they were proven in other languages. You would expect that since Java took such a sl…

It's seriously puzzling. I just don't get how it's possible to look at what so many others have done better, and somehow design something worse. For what reason? Consistency with the rest of the language, possibly? But is that really so important. Do they just not want to tackle certain parts of the compiler?

OpenJDK redesigns massive swaths of the compiler every other month.

The true explanation, at least the way OpenJDK says it, is that designing language features is more complex than a casual glancer can fathom, and there's 30 years of "Java is in the top 5 most used languages on the planet, probably #1 especially if focussing on stuff that was meant to be supported for a long time" to think about.

From personal experience, essentially every single last "Just do X to add (some lang feature) to java; languages A and B do it and it works great!" would have been bad for java. Usually because it would cause a 'cultural split' - where you can tell some highly used library in the ecosystem was clearly designed before the feature's introduction.

Even if you introduce a new feature in a way that doesn't break existing code, it's still going to cause maintainability headaches if you've cornered the pillars of the ecosystem into total rewrites if they want to remain up to date with the language. Because they will (or somebody will write an alternative that will) and you've _still_ 'python 2 v python 3'd the language and split the baby in the half.

For what its worth, I think the OpenJDK team doesn't take this seriously enough, and a number of recently introduced features have been deployed too hastily without thinking this through. For example, `LocalDate`, which has 'this should be a record' written all over it, is not a record. Or how the securitymanager is being ditched without replacements for what it is most commonly used for here in the 2020s. (To be clear: Ditching it is a good idea, but having no in-process replacement for "let me stop attempts to access files and shut down the JVM, not for security purposes but simply for 'plan B' style fallback purposes" - that's a bit regrettable).

I'm nitpicking on those points because on the whole OpenJDK is doing a far better job than most languages on trying to keep its ecosystem and sizable existing codebase on board _without_ resorting to the crutch of: "Well, users of this language, get to work refactoring everything or embrace obsoletion".

Re: Rating 26 years of Java changes

#58
post #50

I think the author is sleeping on Java assertions. I really like the feature, and it's really one of the features I feel Java got right. The syntax is very expressive, and they can easily be made to generate meaningful exceptions when they fail. It's also neat that it gives the language a canonical way of adding invariant checks that can be removed in production but run in tests or during testing or debugging (with -…

I'm quite surprised that he said asserts are not found in production code. Is that really so? I rarely write Java, but in C code we use asserts (in production code) all the time. It's not uncommon for functions to contain 2 or 3 asserts.

I very rarely see assertions in "real" Java code; I think the author is right - in fact the place I see them the most often is in unit tests where they've been used by mistake in place of an assertion library's methods!

I don't know why they're not more popular.

Re: Rating 26 years of Java changes

#59
post #50

I think the author is sleeping on Java assertions. I really like the feature, and it's really one of the features I feel Java got right. The syntax is very expressive, and they can easily be made to generate meaningful exceptions when they fail. It's also neat that it gives the language a canonical way of adding invariant checks that can be removed in production but run in tests or during testing or debugging (with -…

I'm quite surprised that he said asserts are not found in production code. Is that really so? I rarely write Java, but in C code we use asserts (in production code) all the time. It's not uncommon for functions to contain 2 or 3 asserts.

If you're only doing like CRUD endpoints, they may be less useful, but that's hardly the extent of Java production code. I certainly use asserts in production code quite a lot in Java, though the use biases toward more low level functions, rarely in high level application logic.

Re: Rating 26 years of Java changes

#60
post #9

Earlier quoted context omitted.

I used to joke that the direction spring was heading was that you’d have an application be a boilerplate main method with a dozen lines of annotations. Then I actually encountered this in the wild: we had an app that sent updates from db2 to rabbitmq, and the application literally was just configuration via annotations and no actual Java code other than the usual spring main method.

this is exactly why spring succeeded. I need to run a scheduled job, @EnableScheduling then @Scheduled(cron = “xxxxxx”) - done. I need XYZ, @EnableXYZ the @XYZ… sh*t just works…

Then you need to deploy it on multiple nodes and neex to make sure it only runs once for each run of the cron, etc.
Post reply on HN