Abstract syntax tree in C++: classes vs. structs

1.5k Views Asked by At

I need to represent a tree hierarchy (an AST to be precise) in my C++ program. Ok, I saw examples of such structures many times, but one thing stays unclear to me. Please, tell me why it is so common to use classes instead of structs for an AST in C++? For example, consider this code, that represents a node of an AST:

class Comparison {
public:
  Node* getLhs() const { return m_lhs; }
  Node* getRhs() const { return m_rhs; }

  //other stuff
private:
  ComparisonOperator m_op;
  Node* m_lhs;
  Node* m_rhs;
};

(it is inspired by https://github.com/clever-lang/clever/blob/master/core/ast.h#L150 but I have thrown away some unnecessary details) As you see here we have two getters which return pointers to private data members and those pointers even aren't const! As I heard that breaks encapsulation. So why not structs (in which all members are public by default) for AST nodes? How would you implement an AST in C++ (I mean dealing with accessibility issue)? I personally think that structs are suit well for such tasks.

I posted code from an arbitrary project, but you may see this practice (classes with encapsulation breaking methods for ASTs) is rather often.

3

There are 3 best solutions below

0
On

Well, consider this code:

class Parent {
public:
    int x;
    void test();

private:
    int y;
};

class Child : public Parent {
public:
    int z;
};

Now the same thing with the struct keyword:

struct Parent {
    int x;
    void test();

private:
    int y;
};

struct Child : Parent {
    int z;
};

Some prefer the class keyword to make clear that something is a class, and struct for some data only classes

4
On

Maybe something like the following would be an acceptable pattern?

class Comparison {
public:
  const Node* lhs() const { return m_lhs; }
  const Node* rhs() const { return m_rhs; }
  Node* mutable_lhs() const { return m_lhs; }
  Node* mutable_rhs() const { return m_rhs; }

  //other stuff
private:
  ComparisonOperator m_op;
  Node* m_lhs;
  Node* m_rhs;
};

If the programmer intends to get a node that is mutable, then at least he makes his intention clear?

BTW even with mutable_lhs() he only gets pointer to a mutable node, but he still doesn't get to change the pointer itself. He would lose that protection if using struct without explicit public/private specification.

0
On

Please, tell me why it is so common to use classes instead of structs for an AST in C++? [..] I personally think that structs are suit well for such tasks.

It doesn't matter; C++ doesn't have structs. When you write struct, you're creating a class.

Either write struct or write class. Then either write public or write private.

Some people choose class, because they think that classes defined using struct cannot contain private members, member functions and so on. They are wrong.

Some people choose class, because they just prefer to keep struct behind for "simple" types with no private members or member functions, purely for style reasons. That's subjective and entirely up to them. (I mostly do a similar thing myself.)

The standard does use the term "structs" and "a struct" in a very small handful of places, sometimes apparently as a shortcut for referring to POD classes, but other times in error (e.g. C++14 §C.1.2/3.3 "a struct is a class"). This has led some people to question the fact that C++ does not have structs (including suggesting that "structs" are a subset of classes, although this notion is not well-enough defined to be formally accepted). Regardless, the behaviour of the std::is_class trait makes things pretty clear.