Cyclic Types

The lbuiltin type references the lval type and the lenv type. This means that they should be declared first in the source file.

But we want to make a lbuiltin field in our lval struct so we can create function values. So therefore our lbuiltin declaration must go before our lval declaration. This leads to what is called a cyclic type dependency, where two types depend on each other.

We’ve come across this problem before with functions which depend on each other. The solution was to create a forward declaration which declared a function but left the body of it empty.

In C we can do exactly the same with types. First we declare two struct types without a body. Secondly we typedef these to the names lval and lenv. Then we can define our lbuiltin function pointer type. And finally we can define the body of our lval struct. Now all our type issues are resolved and the compiler won’t complain any more.

  1. /* Forward Declarations */
  2. struct lval;
  3. struct lenv;
  4. typedef struct lval lval;
  5. typedef struct lenv lenv;
  6. /* Lisp Value */
  7. enum { LVAL_ERR, LVAL_NUM, LVAL_SYM,
  8. LVAL_FUN, LVAL_SEXPR, LVAL_QEXPR };
  9. typedef lval*(*lbuiltin)(lenv*, lval*);
  10. struct lval {
  11. int type;
  12. long num;
  13. char* err;
  14. char* sym;
  15. lbuiltin fun;
  16. int count;
  17. lval** cell;
  18. };