Suggestion unwrap_safe for Result<T, !>, or `impl From<Result<T, !>> for T`

They would indeed become an obsolete pattern, but keeping the options open can still be useful: in the same vein that () does not make any zero-sized struct useless (even if we ignored new-type usage for traits) since they can convey richer information.

Take, for instance, the return type of ::std::iter::Iterator::next(), and let's call it IteratorState<Item>:

  • Currently, IteratorState<Item> is Option<Item>:

    type IteratorState<Item> = enum Option<Item>
    {
      Some(Item),
      None,
    }
    
  • with generators, it could be seen as ::std::ops::GeneratorState<Iterator::Item, ()>,

    i.e.,

    type IteratorState<Item> = enum GeneratorState<Item, ()>
    {
      Yielded(Item),
      Complete(()),
    }
    

    And although the one-type-fits-them-all is elegant logical-patterns-wise, that Complete(()) does not look nice (although quite better than the initial None!). With an (isomorphic) custom type, we could improve it:

  • enum IteratorState<T>
    {
      Yielded(T),
      Exhausted,
    }
    use self::IteratorState::*;
    impl<T> IteratorState<T> {
      fn some(self) -> Option<T> { match self {
        Yielded(value) => Some(value),
        Exhausted      => None,
      }}
    }
    

I thus think that custom never types may very well exist, either in the form

struct Never /* = */ (!);

or in the empty enum form. Hence the need for such a trait.

As an aside, I find custom inhabited types useful for "type-level enums", since it prevents using them as values.

Those are useful for truly immutable settings that can then lead to constant propagation and dead code removal:

trait Bool { const TRUTH: bool; fn is_true () -> bool { Self::TRUTH } }
  enum True  {} impl Bool for True  { const TRUTH: bool = true ; }
  enum False {} impl Bool for False { const TRUTH: bool = false; }

/// they can be "converted back to (zero-sized) values" with `PhantomData`
use ::std::marker::PhantomData;

struct Config<Verbose : Bool> {
  // ...
  _phantom: PhantomData<Verbose>,
}

impl<Verbose : Bool> Config<Verbose> {
  fn run (
    // ...
  )
  {
    if Verbose::is_true() { /* be verbose */ }
    // do some stuff
    if Verbose::is_true() { /* be verbose */ }
    // do more stuff
    if Verbose::is_true() { /* be verbose */ }
  }
}
3 Likes