if library maintainers take time/effort to enforce API correctness at compile time, it makes users’ lives much easier
I’m not super familiar with C++, but I suspect that the checks you are trying to do might make sense in C++, but not make sense in JVM languages. You mention library maintainers, so I suspect one of your concerns is making sure that, as the library evolves, the API is backwards compatible so that code which uses an older version of your library can continue to function unchanged with new versions of your library.
My understanding is that in the C++, you can control the layout of objects in memory, which can allow you to for example cast pointers to have something like a void*
type, and then as long as you know the layout of the object in memories, you could always cast to a custom struct or union type and recover the data out of the original fields. In that sense, you can do something like duck typing, and as a library maintainer this gives you some flexibility in the way you can evolve your data structures while maintaining the same API.
This concept does not exist on the JVM. JVM languages have no say in the layout of objects in memory, and so duck typing is not really possible at the bytecode level. Instead, the JVM leans much more towards nominal typing, where two types are only considered equal if they have the same name. There is still flexibility on JVM languages in evolving the data structures while maintaining backwards compatibility, because we can upgrade the JAR file that contains the definition of the named type (to, for example, suddenly have new fields on the type), and as long as all the relevant APIs still refer to the same name for the type they’re using, everything just works.
As such, it doesn’t make sense in JVM languages to make assertions on the structures of types (i.e. asserting that a given type has a given field) the way it might in C++, because “same structure” is not the mechanism through which types are considered equal and/or interoperable in JVM languages; only “same name”.
And then it doesn’t make much sense to write checks that APIs are using the same name of types from one version of an API to another, because accidentally changing the name of the type referenced in an API is simply not a mistake maintainers make in practice (i.e. maintainer’s don’t, in practice, accidentally change a function from taking an Foo
to taking a Bar
).
it might be that over time more people will be interested in enforcing correctness at compile time
Yes, the people designing languages for JVM tend to prefer static checks over dynamic checks. But I think you might need to tweak your idea of what is “correctness” actually means on the JVM (e.g. nominal vs duck typing).
As an analogy, a person might say that they have some C++ tooling to ensure that there are no circular #include
s and they’re looking for something similar in Kotlin, because they care about correctness, circular #include
s are clearly incorrect, and they think Kotlin folks should care about correctness too.
The response isn’t that “Kotlin doesn’t care about correctness”, but rather that it doesn’t have a concept of #include
, and thus there is no motivation to write any such tooling.