4 ms·
This article shows a lot of the silliness in both a) writing compilers in C++ and b) re-creating well-worn compilers tools like parsers from scratch. 1. Their
by wcrichton 10y ago
This article shows a lot of the silliness in both a) writing compilers in C++ and b) re-creating well-worn compilers tools like parsers from scratch.
1. Their definition of values in the language (unfortunately called "Variables") is a product (class) over all possible types:
class Variable {
...
double numValue;
string strValue;
vector<Variable> tuple;
string action;
string varname;
Constants::Type type;
};
This means each value at runtime has a large memory footprint, as each instance of a value contains slots for all possible types even though only one will ever be filled. Sum types solve this problem.
2. The author intermixes parsing and code generation. This makes it difficult to implement any kind of optimizations, even for an interpreter. For example, in order to do function inlining in the author's language, you would have to manually inline calls in every single part of the code generator instead of having IR transformations as separate modules (see: LLVM). It also tightly couples the two pieces of the compiler, making it difficult to change parsing strategies without rewriting the code generator for instance.
3. It took the author nearly 5000 lines of C++ to write an interpreter for a simple Javascript-like scripting language. Some of this is due to the verbosity of C++, and some is due to the needless effort of reimplementing parsing from scratch. I implemented a similar language in <1k lines of Rust [1], and I'm sure that others could do even better in Haskell or OCaml. On top of that, the author's claimed benefit of extensibility requires writing large amounts of boilerplate.
[1] https://github.com/willcrichton/lia https://github.com/willcrichton/lia
- pcunite 10y agoSome people make things while other discuss the theory. Each has their place. There would be nothing to improve if people don't try.
- chubot 10y agoAt the risk of stating the obvious -- in C and C++, unions solve that problem.
- catnaroek 10y agoYou still need to roll your own tagged unions by hand. Algebraic data types solve that problem.
- metaobject 10y agoBut can you have a union of string and numeric data? It's been awhile since I've used them, but how would that work?
- ruste 10y agoUnion of numeric and character pointer.
- wcrichton 10y agoThey solve the memory issue, although they are inconvenient to use vs. pattern matching and aren't type safe. Additionally, I've had no luck using classes (e.g. string) inside of unions because the compiler reasonably complains about initializers. I believe this is somewhat solved with boost::variant (and that's also getting put into C++17, iirc), but ideally it would be a part of the type system.
- wolfgke 10y agoReplace the type (e.g. std::string) by the pointer type (e.g. std::string*) in the union.
- flamedoge 10y agounion is a max-size-fits-all solution. a better solution is inheritance.
- clappski 10y agoWhich would introduce the overhead of a vtable, which would vary depending on how deep your inheritance goes. I haven't read the article, but I would maybe use an enum if this is just use to parse variable declarations.
- beached_whale 10y agoGenerally the vtable is not much slower. I believe around the cost of an extra pointer derefence vs the alternative of branching. Also the compiler can sometimes optimize the cost to be the same as a normal call(e.g. final)
- fsloth 10y agoThis is a toy example - one needs to have a lot of values for that whale of a Variable class to create a problem.