4 ms·
IIUC, for checked exceptions Java lacks parametric polymorphism (generics).
by dllthomas 2y ago
IIUC, for checked exceptions Java lacks parametric polymorphism (generics).
- kaba0 2y agoAh. But that’s also not true, you can do something like `throws T`.
- Yoric 2y agoI assume that the poster meant that Java could have had `Result<T, E>` return values like Rust if it had launched with parametric polymorphism, instead of having a layer of the type system dedicated to errors.
- kaba0 2y agoIt still can have it, see e.g. Vavr, or other functional libraries. Edit: Not sure why the downvote. This works in Java today with proper pattern matching (I left out the complete name from the permit clause, it won’t compile as is): sealed interface <T,E> Result permits Ok, Error { record Ok(T val) implements Result<T,E> {} record Error(E err) implements Result<T,E> {} }
- mrkeen 2y agoMan I hope Vavr survives. It is an oasis of rationality and I'm disheartened that https://docs.vavr.io/ https://docs.vavr.io/ appears to be down. Its Set implementation actually has union and intersection (!!!)
- Yoric 2y agoSure, and it's great that this has become possible (a while ago now). My remark was about Java ~1.0, as by now, the ship has long sailed and it's unlikely that many people will start adopting this style. (and no, I have no idea why you're being downvoted, please take my upvote)
- Nullabillity 2y agoIt works, until it doesn't. Exceptions are the one place in Java that supports union types, if you have code that can throw both Exception1 and Exception2 then Java can keep track of whether they are thrown separately: class Exception1 extends Exception {} class Exception2 extends Exception {} interface ThrowingFunction { void apply() throws Exception1, Exception2; } class Foo { public void doFoo(ThrowingFunction f) throws T { f.apply(); } public static void main() throws Exception1, Exception2 { new Foo().doFoo(() -> { if (false) { throw new Exception1(); } if (false) { throw new Exception2(); } }); } }} However, if you pass them through a generic then they will be flattened into the closest common ancestor: class Exception1 extends Exception {} class Exception2 extends Exception {} interface ThrowingFunction<T extends Throwable> { void apply() throws T; } class Foo { public <T extends Throwable> void doFoo(ThrowingFunction<T> f) throws T { f.apply(); } // Fails to compile, because Exception is still unhandled public static void main() throws Exception1, Exception2 { new Foo().doFoo(() -> { if (false) { throw new Exception1(); } if (false) { throw new Exception2(); } }); } }
- dllthomas 2y agoAh, neat! I think the last time I looked you couldn't, but it was ages ago; I'm not surprised to have misremembered and even less surprised if it's changed. Is it possible to provide a map method that re-throws whatever is thrown by its argument, without widening?