In which I compare the advantages of two kinds metaprogramming: with metaclasses at runtime, versus templated code generation prior to compilation. [2 minutes]
In the Active Record pattern a class wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. Writing in Java and C# one often does metaprogramming in the form of templates to generate code for each table: you would see a template and multiple generated class files for each table. In more-dynamic interpreted languages like Python and Ruby languages, one typically instantiates a specialised class for each table at runtime based off of a metaclass, so in the source code you only see the metaclass and possibly instantiations.
Let's look at the relative advantages:
P.S. I also have some views on how to write bad code in Python.
What are your views on (runtime) metaprogramming versus code generation?
In the Active Record pattern a class wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. Writing in Java and C# one often does metaprogramming in the form of templates to generate code for each table: you would see a template and multiple generated class files for each table. In more-dynamic interpreted languages like Python and Ruby languages, one typically instantiates a specialised class for each table at runtime based off of a metaclass, so in the source code you only see the metaclass and possibly instantiations.
Let's look at the relative advantages:
Advantages of metaclasses
- Size: metaclasses yield a smaller source control tree. With generated classes, one might find most of the codebase consists of generated files.
- Locality: metaclass changes affect only small sections of code, while code generation can change thousands of files for a small change to the template or database schema.
- Edit speed: the edit-run cycle is quicker than a generate-compile-run cycle, a typical interpreted language advantage.
Advantages of code generation
- Execution speed: code generation has no runtime overhead, compared to the generalized metaclass logic.
- Type checking: compilers can statically check the method calls and types against generated code on disk, but not against classes that only appear at runtime.
- Editor assistance: similarly IDEs can provide completions and contextual help for generated code, not normally for classes that appear at runtime.
- Debugging: is more straightforward in generated code than in metaclass methods.
- Generality: templated code generation seems to generalise more easily than metaclasses (not limited to classes), so sometimes you have to do it anyway.
Code generators all the way down
Code generation can be seen as using a higher level language to output code in a lower level one. In that sense, compilers are code generators of assembly and machine language, interpreters are code generators of bytecode, and what we usually call "code generators" are template languages that generate high-level language code. So everyone is using code generation, but should one be generating code for the language that one is also coding in right now?P.S. I also have some views on how to write bad code in Python.
What are your views on (runtime) metaprogramming versus code generation?
Since the “meta” in metaprogramming implies writing code that writes code, all three forms of code generation can be considered metaprogramming..
ReplyDelete