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 function signature is frustrating. This is why everyone says they're "incompatible" with Java's closure APIs.
No unsigned ints.
No concept of `const` or immutability.
Kotlin allow to specify either variance or contravariance so I guess it fixe this point too?
* The fact that arrays got type variance wrong*
* interfaces are extremely lacking compared to type classes and lead to verbose and cumbersome patterns such as "Adapter".*
Interesting, can you link to an example?
Kotlin has first class support for delegation as an alternative.
* Type-erased generics. Why shouldn't I be able to implement a generic interface for multiple types? E.g., class MyNumber implements Comparable<Integer>, Comparable<Short>, Comparable<Long> {}*
Kotlin has support for reified generics to some extent.
The JVM is currently getting state of the art support for it too and for specialization.
* Dates and timezones are still insane, even in Java 8+.*
I always hear that Java has got the best Time library, what is the complaint about?
* JDBC sucks. JPA also kind of sucks.*
Do yourself a favor and use the JDBI or so many other sexy alternatives.
Of all your points the only unaddressed are:
* interfaces are extremely lacking compared to type classes and lead to verbose and cumbersome patterns such as "Adapter".
And
Silent integer overflow/wrap-around*
Strong agree about stockolmization and cargo cultism of language constructs.
Most programming languages are pretty awful Correct, hence why Kotlin stands out.
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<out T>(val value: Collection<T>): 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 <T> foo(clazz: Class<T>)`. 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:
But, I was complaining about the 8+ DateTime API. Now, granted, it's WAY, WAY, better than the old API. And it's much better than what's available in at least several other languages (cough JavaScript with no time zones at all).
It still depends on a global, mutable, time zone variable. It uses it in several places where it's kind of hard to get it to just use a given time zone.
The API is also just really hard to discover and use correctly. Look at what classes implement TemporalAccessor. It's not easy at all to guess which methods will throw an exception for a given implementer. Further, what if your function is just given a TemporalAccessor? I have NO IDEA what I'm actually able to call on the object without it exploding.
Calendar is awkward and hard to use.
Switching around between TimeZone, ZoneOffset, and ZoneID is pretty cumbersome. Some stuff takes Strings, some take ZoneID, etc. Some things that seem to take ZoneID don't seem to be able to take a custom TimeZone (not that I think I ever really needed that- I was trying to do something hacky IIRC).
A lot of methods take Long, which you have to just read the docs to know if that's seconds or milliseconds.
It's just kind of a bleh API.
Then you mix in the fact that JDBC is forced to use the old Date classes and that messes everything up because of timezone crap.
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 function signature is frustrating. This is why everyone says they're "incompatible" with Java's closure APIs.
No unsigned ints.
No concept of `const` or immutability.
Kotlin allow to specify either variance or contravariance so I guess it fixe this point too? * The fact that arrays got type variance wrong*
* interfaces are extremely lacking compared to type classes and lead to verbose and cumbersome patterns such as "Adapter".* Interesting, can you link to an example? Kotlin has first class support for delegation as an alternative.
* Type-erased generics. Why shouldn't I be able to implement a generic interface for multiple types? E.g., class MyNumber implements Comparable<Integer>, Comparable<Short>, Comparable<Long> {}* Kotlin has support for reified generics to some extent. The JVM is currently getting state of the art support for it too and for specialization.
* Dates and timezones are still insane, even in Java 8+.* I always hear that Java has got the best Time library, what is the complaint about?
* JDBC sucks. JPA also kind of sucks.* Do yourself a favor and use the JDBI or so many other sexy alternatives.
Of all your points the only unaddressed are: * interfaces are extremely lacking compared to type classes and lead to verbose and cumbersome patterns such as "Adapter".
And Silent integer overflow/wrap-around*
Strong agree about stockolmization and cargo cultism of language constructs.
Most programming languages are pretty awful Correct, hence why Kotlin stands out.