Comment

Comment by loup-vaillant

> It has the best performance and the highest level abstractions in one package.

The highest level abstractions, are you kidding me?

I am currently writing a little interpreter in C++. I would have used Ocaml, but the rest of the project is in C++. Well, just try to write an abstract syntax tree in C++. In languages such as ML and Haskell, this is easy:

  type expression = Litteral    of value
                  | Symbol      of string
                  | Funcall     of expression * expression
                  | Conditional of expression * expression * expression
                  | While_loop  of expression * expression
                  | Sequence    of expression list
And I'm pretty much done. Now in C++:

  --------------------------------------------------------------------------------
  #ifndef __Expression_h__
  #define __Expression_h__
  
  #include <cstdint>
  #include <string>
  #include "Value.h"
  
  
  namespace Script {
  
  class Expression;
  
  class Expression {
  public:
      enum Tag {
          litteral,
          symbol,
          funcall,
          conditional,
          while_loop,
          sequence
      };
  
      union Val {
          Value                   *litteral;
          std::string             *symbol; // or a true symbol?
          std::vector<Expression> *composite;
      };
  
      Expression(const Value&);
      Expression(const std::string&);
      Expression(Tag, std::vector<Expression>*); // takes ownership
      ~Expression();
  
  private:
      Tag _tag;
      Val _val;
  };
  
  } // namespace Script
  
  #endif // __Expression_h__
  --------------------------------------------------------------------------------
Don't forget the cpp file either:

  --------------------------------------------------------------------------------
  #include "Expression.h"
  #include <cstdio>

  using namespace Script;
  
  Expression::Expression(const Value& val)
      : _tag(litteral)
  {
      _val.litteral = new Value(val);
  }
  
  Expression::Expression(const std::string& sym)
      : _tag(symbol)
  {
      _val.symbol = new std::string(sym);
  }
  
  Expression::Expression(Tag tag, std::vector<Expression>* exprs)
  {
      if ((tag == funcall     && exprs->size() == 2) ||
          (tag == conditional && exprs->size() == 3) ||
          (tag == while_loop  && exprs->size() == 2) ||
          tag == sequence) {
          _tag = tag;
          _val.composite = exprs;
      } else {
          std::fprintf(stderr, "Expression constructor: Invalid Expression\n");
          exit(1);
      }
  }
  
  Expression::~Expression()
  {
      switch (_tag) {
      case litteral   :
          delete _val.litteral;
          break;
      case symbol     :
          delete _val.symbol;
          break;
      case funcall    :
      case conditional:
      case while_loop :
      case sequence  :
          delete _val.composite;
          break;
      default:
          std::fprintf(stderr, "Expression destructor: broken class invariant\n");
          exit(1);
      }
  }
  --------------------------------------------------------------------------------
I may use smart pointers instead of doing my own RAII by hand, but that's still a hassle. Some may point out that my ugly unsafe union type is not the way to to this, I should use a class hierarchy and polymorphism. But just imagine the sheer amount of code I'd have to write.

C++ is a low level language. It's high level pretense is nothing but a thin veneer that cracks under the slightest scratch. Or, someone show me how to implement an abstract syntax tree in less than 20 lines of code. I'm lenient: Haskell and ML only need 6.

(Yes, I'm using Sum types, a feature that's pretty much unique to ML languages. But no, that's not cheating: providing enumeration and unions but somehow failing to combine them into sum types is a serious oversight.)

parent loup-vaillant 10 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton