Subject: Re: [boost] Ternary logic programming (was: Re: [variant] Maintainer)
From: Lee Clagett (forum_at_[hidden])
Date: 2015-07-01 21:35:24


On Wed, Jul 1, 2015 at 8:49 PM, Niall Douglas <s_sourceforge_at_[hidden]>
wrote:

> On 1 Jul 2015 at 15:53, charleyb123 . wrote:
>
> > Under an alternative model, the common construct would be something like:
> >
> > void foo(...) {
> > return switch_(...) {
> > ...
> > }
> > }
> >
> > ... and you manage your true/false/unknown cases explicitly. Works great
> > for asynchronous and distributed, and for interfacing-with-hardware.
>
> That's exactly what Rust does. In fact, you'll find yourself either
> writing match x { patterns ... } or using monadic programming. A lot,
> because there is little other choice.
>
> Out of interest, what do you think of my free function ternary logic
> programming:
>
> tribool t;
> if(true_(t)) { /* true */ }
> else if(false_(t)) { /* false */ }
> else if(unknown(t)) { /* other state */ }
>
> Nobody here seemed to like it. I am looking for something the average
> programmer will notice immediately and not accidentally assume it's
> boolen logic going on here.
>

What if you combined a c++11 enum class with an implicit conversion
operator? The implicit conversion can take place in a switch statement, but
not if() or int() expressions since the enum class is not implicitly
convertible to those types.

enum class status { complete, error, waiting };

class niall_monad {
public:
  constexpr niall_monad(const niall_monad&) = default;
  constexpr niall_monad(status result) : result_(result) {}

  constexpr operator status() const {
    return result_;
  }
private:
  status result_;
};

constexpr bool is_complete(const niall_monad value) {
  switch(value) {
  case status::complete:
    return true;

  default:
  case status::error:
  case status::waiting:
    return false;
  }
}

int main() {
  static_assert(!is_complete(niall_monad(status::waiting)), "");
  static_assert(!is_complete(niall_monad(status::error)), "");
  static_assert(is_complete(niall_monad(status::complete)), "");

  if (niall_monad(status::complete)) { // fails
    return 1;
  }

  int foo = niall_monad(status::complete); // fails

  return 0;
}

With errors:

niall.cpp:33:7: error: no viable conversion from 'niall_monad' to 'bool'
  if (niall_monad(status::complete)) {
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
niall.cpp:9:13: note: candidate function
  constexpr operator status() const {
            ^
niall.cpp:37:7: error: no viable conversion from 'niall_monad' to 'int'
  int foo = niall_monad(status::complete);
      ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
niall.cpp:9:13: note: candidate function
  constexpr operator status() const {
            ^
2 errors generated.

Remove the bad conversions, and you've got a compiled program. Are there
other situations that an enum class can implicit convert to something else?
A static case will force things obviously. I'd have to read the specs to
know.

Lee