Hacker News new | ask | show | jobs
by tlhand 689 days ago
std::variant is not a true algebraic data type, since the individual element constructors do not construct the variant type automatically. Compare to OCaml, written in a verbose and unidiomatic way that is similar to C++:

  # type foo = Int of { n : int } | Float of { f : float };;
  type foo = Int of { n : int; } | Float of { f : float; }
  # Int { n = 10 };;
  - : foo = Int {n = 10}
  # let r = ref (Int { n = 10 });;
  val r : foo ref = {contents = Int {n = 10}}
Notice that the constructor Int { n = 10 } automatically produces a foo type and assigning to a mutable ref works.

The same in C++, using assignment to a pointer to avoid the lvalue ref error that is irrelevant to this discussion:

  #include <variant>
  
  struct myint {
    int n;
    myint(int n) : n(n) {}
  };

  struct myfloat {
    float f;
    myfloat(float f) : f(f) {}
  };

  using foo = std::variant<myint, myfloat>;

  int
  main()  
  {
    const foo& x = myint{10}; // works
    foo *z = new myint{10}; // error: cannot convert ‘myint*’ to ‘foo*
  }

As stated above, this obviously cannot work since C++ has no way of specifying a myint constructor that -- like in OCaml -- automatically produces the variant type foo.

C++ would need true algebraic data types with compiler support (that would hopefully be as fast as switch statements). To be useful, they would need a nice syntax and not some hypothetical abomination like:

  using foo = std::variant<myint, myfloat> where
  struct myint of foo { ... };