Hacker News new | ask | show | jobs
by cesarb 682 days ago
> Java has the first part down, for the class of checked exceptions: a function that doesn't throw can't call functions that do (except in try/catch blocks, but that's largely irrelevant).

That's not actually true, it's possible to do "sneaky throws" (https://www.baeldung.com/java-sneaky-throws) of a checked exception from a method which isn't declared to throw that checked exception. The classic example is Class.newInstance(), which propagates any exception from the called constructor. Other ways are calling code from JVM languages other than Java, which do not have the same "checked exception" concept (like Kotlin: see https://kotlinlang.org/docs/exceptions.html and https://kotlinlang.org/docs/java-to-kotlin-interop.html#chec...), generics trickery to confuse the compiler, and manually creating JVM bytecode.

1 comments

Sure, but that's essentially the same as using explicit jumps through raw assembly instructions to go around C++'s destructor guarantees. That is, when your Java process runs non-Java code, of course this can defeat certain Java guarantees. No programming language can make promises for semantics of external code like this.
That's still the case in pure Java code. The "Class.newInstance()" method is a public method on the core Java API, calling "MyClass.class.newInstance()" is mostly equivalent to "new MyClass()". And the generics trick in the "sneaky throws" article I linked is also pure Java code, without any calls to "sun.misc.Unsafe".
Class.newInstance() is a known unsafe method and has been deprecated for quite some time now (since Java 9). It's similar to Haskell's unsafePerformIO from this point of view.

The generics hole is indeed interesting, but it's ultimately a known limitation of how generics were implemented in Java, the presence of type inference, and the design of the exception hierarchy, than an intentional feature. When inferring the type of T to apply in that example, there is no good unique solution: inferring T = Throwable would have been safer, but it makes many simple cases behave unexpectedly, especially with lambdas. Inferring T = RuntimeException is unexpected and unsafe, but in practice it makes many common cases be way more usable, so a call was made to do it, despite the hole.

C++'s templates wouldn't have a similar problem, as they actually instantiate the definition at compile time and can re-check it. Also, there is no equivalent issue to the ambiguous inference, because C++ doesn't do type inference of this kind at all, and anyway there is no problem of the exception hierarchy. Even if there were, C++ could also take the opposite choice than Java, and explicitly infer the safer option when both `noexcept` and `potentially-throws` were possible.

And of course Lombok is a tool for modifying the compilation of Java, so writing Lombok code is not exactly writing pure Java.