3 ms·
That is a very nice summary! Some of these tensions seem unresolvable though. At some level if I want to toss a Map around everywhere and be able to transparen
by zmmmmm 8y ago
That is a very nice summary!
Some of these tensions seem unresolvable though. At some level if I want to toss a Map around everywhere and be able to transparently back it with a database, I'm going to have to accept that operations might fail. I can't have it both ways. In the end, the abstraction is "leaky". I don't really see how Rust or anything else can make that go away.
I feel like the closest I can get to have my cake and eat it too is by having the compiler transparently infer all the exceptions / errors that can be thrown by the calls I am making (like type inference for variables), but leave them out of the type signatures. Then I can opt in to enforcing the checking of them when I want to, so something like
check {
doSomething()
}
catch(...) { // every error now has to be handled
....
}
I guess this is something like what Rust is achieving through the ? operator.
- steveklabnik 8y agoIn rust, what you can do is define an error type as an enum, which holds the various kind of inner errors. Then you’re just a From implementation (which is very simple and macros exist to generate it) away from ? working on any of them, and it composes them together.
- int_19h 8y agoIn the case of Map, since some maps fail and others don't, and those that fail can fail with different errors, it would be reasonable to express in in the type itself - i.e. instead of Map<T>, you have Map<T, E> (and then you also need union types to properly express E being a list of exceptions, and a unit type to express an empty list). Then any code that handles generic maps can also be generic wrt E, propagating whatever is thrown, and possibly adding its own errors, or catching some specific ones. And, conversely, you could only accept Map<T, Unit> for code that expects non-throwing maps, and then you don't need to catch or propagate anything in that code. Add defaulted generic parameters for convenience - e.g. Map<T, E=Unit> - and now API clients don't have to care about E if they don't want to, and are happy with things as they are. Alternatively, you can just say that map is something that never throws, by definition. But, of course, that reduces the utility of the interface, by making it less generic than it could be. In some cases - especially with HOFs - the reduction in utility can be so substantial that it negates any gains from code reuse.