Boost logo

Boost :

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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk