That's fine if you're using it via the Reader interface, but if you're working with StringReader directly it's a pain in the butt to deal with the non-existent exceptions. It sounds like never-patterns would help with that.
Thanks.
Uninhabited types are useful for expressing units.
I'm writing an app that makes heavy use of a Haskell library[1] that implements currency units and exchange rates using uninhabited types (type-level strings).
So, one dollar will have the type `Amount "USD"`, whereas one Euro will have the type `Amount "EUR"` (both will have a value of `1`).
An exchange rate from Euros to dollars will have the type `ExchangeRate "EUR" "USD"` (the first type parameter being 'source' and the second 'destination'), and its value will be `1.14` (the current exchange rate from EUR to USD).
A function for converting an amount in one currency into another currency unit will take two arguments: `Amount src` and `ExchangeRate src dst` and return an `Amount dst`.
Also, in general, it can be useful to:
1. Remove an argument from a function
2. Create an uninhabited type that, at the type level, represents the values of this argument
3. Tag the function's return type with this uninhabited "phantom" type
because now you no longer have to remember from which argument some return value was calculated/derived: it's right there in the value's type.
[1] https://www.stackage.org/haddock/lts-12.6/safe-money-0.6/Mon...
Uninhabitable types allow the implementer to tell the compiler "I cannot provide an error here", giving the compiler more information to work with when optimizing. For example, the compiler now knowing that the function call cannot return an error may make it so that the function does only return the string after optimization, and the compiler can also drop the error checking code in the caller because it's unreachable.
[0]: http://fog.io/
Removing checks for "cannot possibly happen" cases isn't usually worth the tiny time savings.
I don't know about C++, but it may be doing something different from Rust here. In Rust, the ! type (which I pronounce "Never"), isn't just a case of "I, the programmer, don't think any value will exist here"; the compiler forces you to prove (just like every other type is a proof) that a value can't exist. The Never type can't be instantiated (it has no constructor), and functions that "return" Never must prove that they, er, never return; imagine a function whose body is just `loop {}` (or the stdlib function process::exit, which cannot return by dint of killing the callstack when the process dies).
Of course it failed, and it was a royal pain to get to the bits that failed because they were embedded in concrete that was probably holding the building up.
You build for robustness because you might be wrong, the new guy might not understand, or a silicon isotope might decay at just the wrong time and flip a bit. Circuits are analog. They just pretend very very hard to be binary. Weird shit can happen that shouldn’t be possible.
On the other hand, the use of an uninhabited type means that the programmer has to prove to the compiler that the type is uninhabited, in the same way that declaring a function as returning a String requires the programmer to prove that the function actually does return a String. If we have a function that returns a String, the compiler does not generate any code to handle the case where that function returns an integer instead; that just doesn't make sense, we've used the type system to prove that can't happen. Likewise, it wouldn't make any sense for the compiler to generate code to handle the case where a function returning an uninhabited type returns anything at all.
If anything, you probably want something more like Erlang's supervision hierarchy where pattern-match failures (due to a cosmic ray, or anything else) kill the actor-process that was running, and then the actor's parent reinstanciates it and it tries again. Then you just need to draw fine-grained failure boundaries (i.e. what things end up in new actor-processes) to ensure that crashing out a process doesn't waste too much work unnecessarily.
Or the Mars-rover "six CPUs on separate NUMA nodes are each running a copy of the program, and quorum-consensus on the result of each function-call" strategy, but that's a bit expensive.
noreturn mainloop(State* s)
{
for(; s->valid ;s->itick++) do_step(s);
die(70,"invalid internal state");
}By choosing an unhabited return type, you can express that the stream never stops producing values by itself.
However when returning ! the compiler can optimize the entire error handling away.
I think what they're asking is "if you're returning a Result<String, Err>" but you're making the Err an unhinabitated type (so can't ever have an error) why not just return a String in the first place?
See these: https://internals.rust-lang.org/t/recent-change-to-make-exha... https://github.com/rust-lang-nursery/nomicon/issues/29 https://github.com/briansmith/ring/issues/416
> if you have to define an error type for some computation, but this particular computation can never fail, you might use an uninhabited type.
I don't see the reason behind returning a Result<String, Err> if there is no error to return. Why not just return a String?