Live data from Hacker News

A categorized list of all Java and JVM features since JDK 8 to 16

advancedweb.hu

161–170 of 243 posts

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#162

Earlier quoted context omitted.

Say you have: public void doSomething(Optional foo) { ... } You want `foo` to be `Optional.empty()` or `Optional.of("some string")`. The way things currently work, `foo` could also be `null`.

Kotlin's approach of making null act kind of like Optional is pretty nice, but I wish there was a strict option for interacting with Java types -- by default, all Java-native types (type names ending with ! ) can be null and are not null checked at compile time.

In our code base we just throw a `?:` after any type that shows up as Type! and handle it immediately. If you actually expect a null value you can also use `?: null`

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#163

Earlier quoted context omitted.

It surprises me as well. And to belabor my own point some more: there's a reason the #1 question about Rust from newbies seems to be "Is there a language like Rust, but with a garbage collector?" - sometimes reworded as "Is there a way to turn off the borrow checker?" To be fair, I think that a decent amount is possible on JVM and CLR. Scala, for as much hate as it gets, has a much stronger type system than Kotlin/Ja…

Kotlin is the application language you're looking for (and Scala 3 to a lesser extent). Contrary to what you say it is the best language I've ever used for concurrency. It has it all, structured concurrency, cancelation, Flow, transparency (no await), etc. Regarding your second point the JVM is increasingly using the stack and with the soon complete generics you'll be able to avoid the boxed versions of the primitive…

> Contrary to what you say it is the best language I've ever used for concurrency. It has it all, structured concurrency, cancelation, Flow, transparency (no await), etc.

I disagree.

Have you ever tried to actually implement something non-trivial that takes advantage of structured concurrency with cancellation? It's pretty hard to do correctly. Can you really tell me off the top of your head what the difference is between `withContext(coroutineContext) {}` and `coroutineScope {}` from within a suspend function?

Coroutines use unchecked exceptions for control flow. Kotlin also uses unchecked exceptions for fatal and non-fatal error handling. Figuring out how all these things interplay when it comes to coroutines and suspend functions has some subtleties that, IMO, are very difficult to figure out from just documentation and blog posts.

Also, Kotlin's standard types are entirely unsafe to use concurrently. The fact that MutableList inherits from List means that a function that accepts a List parameter CANNOT assume that the list wont change while the function is executing. So if you write `if (list.isNotEmpty()) { doSomething(list.first()) }` - that's a race condition because the list can literally become empty between the if clause and the body.

"But, wait! You should have just been smart enough to make a copy of your List before sending it between threads/coroutines." Okay, great. Let's do full copies of potentially-large collections. Thank goodness Kotlin is so concurrency ready that the standard collection types are persistent .. colle..ctions... oh.

Kotlin's concurrency story is really not that awesome. Scala is better, but still not perfect. Clojure is better still. Rust is good. Elixir (or anything with some kind of actor framework, I guess) is good. Haskell is good.

But I agree, overall, that if I had to pick a best app language today, it's either Kotlin or Scala, or Swift if you're writing for Apple stuff. I'll admit that I have a glaring experience gap with .NET languages, so I can't honestly say anything about C# and F#.

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#164

Earlier quoted context omitted.

> No unsigned ints. I think that's a mixed blessing. I believe Java did this deliberately to avoid the trouble that C and C++ have with signed and unsigned integer types having to coexist. Personally I've never been inconvenienced by Java's lack of unsigned integer types, but I'm sure it can be annoying in some situations. I'm quite fond of Ada's approach to integer types, but I suspect I'm in a minority. > Silent in…

> I believe Java did this deliberately to avoid the trouble that C and C++ have with signed and unsigned integer types having to coexist. The problems really only come from mixing those types, and the simple solution is to disallow such mixing without explicit casts in cases where the result type is not wide enough to represent all possible values - this is exactly what C# does. I think Java designers just assumed th…

My opinion is that a high-level language like Java has no business making me guess how many bytes my numeric values will occupy. It's insane. Since when does Java give a crap about memory space? "Allocations are cheap!" they said. "Computers are fast!" they said about indirection costs. Then they stopped and asked me if I want my number to occupy 1, 2, 4 or 8 bytes? Are you kidding me?

Yes, you should have those types available so that your Java code can interact with a SQL database, or do some low-ish level network crap, or FFI with C or something. But the default should basically be a smart version of BigInteger that maybe the JVM and/or compiler could guesstimate the size of or optimize while running.

Thus, IMO, there should be a handful of numeric types that are strict in behavior and do not willy-nilly cast back and forth. Ideally you'd have Integer, UInteger, PositiveInteger, and a similar suite for Decimal types.

Schemes have done numbers correctly since basically forever.

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#165

Java gets a bad rap from people that used it late 90's through early 2000's and got burned out by XML and design pattern heavy frameworks but its a lovely language that with a little discipline can be used to create very lean looking code. Go is one of the HN darling languages and I work in Go everyday for work (and generally like it), but I really wish I could reach for Java most days.

“Java is a big DSL to transform XML into stacktraces” — so was the joke at the time when domain-specific languages were the hype. This, and the FizzBuzz, Enterprise Edition: https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris... More seriously, what are you missing in Go that is well-done in Java? I assume verbosity of the code is still the defining characteristic of Java?

I at the same time laughed and got nauseated just by looking at that FizzBuzzEnterprise code LOL. I'm a minimalistic programmer myself, so the thing I hate the most in coding is over engineered code. Yes , it's a joke, but a joke based on real life haha.

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#166
post #86

Earlier quoted context omitted.

I disagree that it's a lovely language. I think, as developers, we very quickly develop Stockholm syndrome. Once you "learn" a language, it's really easy to churn out code and apply idioms without even realizing that you're constantly writing workarounds and kludges for your language's deficiencies. As a polyglot dev, the following are my gripes with Java: * null - we all know, so I'm not going to bother expanding ex…

> No unsigned ints. I think that's a mixed blessing. I believe Java did this deliberately to avoid the trouble that C and C++ have with signed and unsigned integer types having to coexist. Personally I've never been inconvenienced by Java's lack of unsigned integer types, but I'm sure it can be annoying in some situations. I'm quite fond of Ada's approach to integer types, but I suspect I'm in a minority. > Silent in…

I don't know about Ada, but I enjoy Rust's strictness when it comes to numeric types.

> Java-style wrapping integers should never be the default, this is arguably even worse than C and C++’s UB-on-overflow which at least permits an implementation to trap.

EXACTLY. It's f-ing stupid. C's excuse was compilers doing magic on UB or whatever. Java has no such excuse. They just wanted it to behave the same as C/C++ to attract C++ devs.

> At least Java has the defence that they didn't know how it would pan out. C# has no such excuse in copying Java.

My understanding was that they DID know it was wrong and chose to do it anyway because it was more convenient and ergonomic to allow it that way. I guess they realized that was a terrible idea, because the generic collection interfaces do it correctly.

I don't see how const and immutability align with Java's original philosophy of being object-oriented, which is all about opaque objects that control internal mutable state. The very fact that it's taken until now to have records is proof-positive that "everything is an object" was taken pretty literally for most of its life. Immutable data doesn't really jive with that.

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#167
I was programming in Java before generics came out. While generics were a very big upgrade, it was such a disastrous mistake to go for type erasure, because Java has a bifurcated type system. As we all well know, you can't be generic over a primitive type, for exactly this reason. I knew then and have minefield-of-rakes stumbled my way through every single consequence of that decision and still think it was wrong. That decision was made, approximately, because it was a.) too hard to retrofit the existing libraries without erasure and wildcards, and b.) the VM developers staunchly resisted extending class files.

I've been away from Java for 7-8 years, and returning to use lambdas now. At first it feels like a pleasant experience, and it was a neat trick to allow single-method interfaces to basically denote function types. But that early mistake of not allowing generics over primitives hits back again...LongFunction, IntFunction, oi vey. Not adding a syntax for function types, but relying on single-method interfaces seems like a simple, clever hack. But I think it will turn out to be one of those broken-generics class mistakes.

I spent 15 years working on Virgil [http://github.com/titzer/virgil]. Having tuples and real generics is really important to allow a language to be fully combinatorially complete. I wrote a paper about it. Nobody read it. Ah well. Dang it.

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#168

Earlier quoted context omitted.

“Java is a big DSL to transform XML into stacktraces” — so was the joke at the time when domain-specific languages were the hype. This, and the FizzBuzz, Enterprise Edition: https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris... More seriously, what are you missing in Go that is well-done in Java? I assume verbosity of the code is still the defining characteristic of Java?

Now we've got Spring, which in my, admittedly limited, experience does a great job of transforming what could have been compile-time errors into run-time errors.

Spring is a flow of control obfuscation framework.

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#169
post #86

Earlier quoted context omitted.

I disagree that it's a lovely language. I think, as developers, we very quickly develop Stockholm syndrome. Once you "learn" a language, it's really easy to churn out code and apply idioms without even realizing that you're constantly writing workarounds and kludges for your language's deficiencies. As a polyglot dev, the following are my gripes with Java: * null - we all know, so I'm not going to bother expanding ex…

Your analysis is interesting and far from exhaustive, It would be nice to have a collaborative feature matrix for languages, on github. Kotlin solve the following points: null - we all know, so I'm not going to bother expanding except to say that @NotNull is NOT a solution and it doesn't guarantee shit. I don't hate checked exceptions as a concept, but the fact that you can't be "generic" over the exceptions in a fun…

Kotlin does indeed (mostly) fix null.

Kotlin does not fix the issues with checked exceptions. It gives up and gives us nothing for error handling. So, for all the beauty and magic of a strong static type system, I have absolutely no idea if `fun foo(i: Int): Int` is just going to crash my program when I give it -1.

"Do you have a fatal error? Throw an exception."

"Do you have a non-fatal error that's totally expected as part of your API? Throw an exception."

"Do you want to cancel a coroutine? Throw an exception."

"Do you want to define a class and validate the parameters you pass to the constructor? Screw the type system! Write an init {} that throws an exception!"

Kotlin also doesn't really "fix" Java's lack of unsigned ints. The implementation that Kotlin provides is really poor. That's partly because of Java's lack of unsigned ints, so it's not entirely their fault, but it's a really bad API and going between signed and unsigned ints is very bug-prone. They also don't work with serialization libraries because they're implemented as inline classes, which don't work with serialization libraries.

Kotlin doesn't have the issue with array variance because it doesn't really have arrays like Java has. So that's good.

With respect to interfaces vs. type classes. The issue is this: let's say you're writing an API and you decide that you want to define an interface. Let's define it as `interface MaybeEmpty { fun isEmpty(): Boolean }`. So in your API, you might have some function like `fun foo(maybeEmpty: MaybeEmpty) { /* do something with maybeEmpty.isEmpty() */ }`

See where this is going? You realize: "Hey! I want to implement `MaybeEmpty` for a bunch of types to use in my function."

How do you implement `MaybeEmpty` for `String`? What about `Collection`? You can't. What you have to do in Java+Kotlin is define at least two new classes: `class MaybeEmptyStringAdapter(val value: String): MaybeEmpty { override fun isEmpty() = value.isEmpty() }` and `class MaybeEmptyCollectionAdapter(val value: Collection): MaybeEmpty { override fun isEmpty() = value.isEmpty() }`.

Then when you actually want to use a String or a Collection in your fancy code, you have to write:

val s: String = getSomeString()

foo(MaybeEmptyStringAdapter(s))

With type classes, which exist in Scala, Rust, Swift, and Haskell, you can extend types with interfaces AFTER their definition. So I could implement MaybeEmpty right on String itself and then just pass the String value right into my function. No extra classes, no extra wrapping, no performance overhead.

Kotlin has extension functions, which are a neutered version of type classes.

Kotlin does not support reified generics in classes. They can only be used in inline functions because it gets transpiled into the equivalent of `fun foo(clazz: Class)`. The JVM is not going to get reified generics any time soon. It's been in the works for years and years and will probably break things.

Java's dates and times depend on a global, mutable, timezone setting. The datetime classes use it pervasively. Dealing with Calendar is awkward as heck. The whole TemporalAccessor interface is madness- you never have any idea what method is going to throw an exception for a given implementer. JDBC's dates and times are utterly broken because they use the old Java Date class and it will never change.

JDBI relies on JDBC, so I'm not convinced it actually fixes the problems other than having a nicer API. I stand partly corrected: "By default, SQL null mapped to a primitive type will adopt the Java default value. This may be disabled by configuring jdbi.getConfig(ColumnMappers.class).setCoalesceNullPrimitivesToDefaults(false)." So at least it's only wrong by default...

So, it seems to me that Kotlin actually addresses only two things on my list of complaints: null and array type variance.

EDIT: I accidentally forgot about immutability. Kotlin doesn't have that either. `val` doesn't mean "immutable", it means "not reassignable". I can 100% mutate the ever living crap out of:

class Foo( val inner: MutableList )

val foo = Foo(mutableListOf(1))

foo.inner.add(2)

Look at all those vals! Not a "var" in sight!

Re: A categorized list of all Java and JVM features since JDK 8 to 16

#170
post #94

Is it in the realm of possibilities that Java will someday have runtime generics support (instead of type erasure)? It's the most frustrating aspect of the language because you can't use basic Java features like method overloading with them. Also, I don't understand how people use the `Optional `..? Is there a way to use method overloading with it? `ErasedType` could be _anything_ at runtime, doesn't sound fun. Besid…

When exactly would you benefit from overloading based on a generic type? How come it is never brought up with Haskell for example, or the other majority of languages that employ type erasure?

You might want to have something like `String concatenate(List strings)` and `List concatenate(List> lists)`.

Java won't let you do this because types are erased at compile time, and Java doesn't know exactly what function it's going to call until run time (in order to allow dynamically loading classes). Haskell does allow something similar to this kind of overloading, because Haskell determines what function is going to be called at compile time, before type erasure happens.

Post reply on HN