Skip to main content

When to use code generation vs metaclasses

Ruby example of an ActiveRecord class
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:

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?

Comments

  1. Since the “meta” in metaprogramming implies writing code that writes code, all three forms of code generation can be considered metaprogramming..

    ReplyDelete

Post a Comment

Popular posts from this blog

Optimize Wordpress for tiny free tier VMs

In which I show how to optimize Wordpress on Apache to handle a reasonable continuous load on a tiny free tier virtual machines, with only standard Ubuntu packages. [6 minutes]

The keys to doing long-form Narrative Improv

Here are some key ingredients for full-length improvised plays known as Narrative Improv. Providing tips on story structure, normalcy, the protagonist, consequences and clarity. [4 minutes]

Declutter your home with the Outbox Method

Here are some easy ways to reduce the clutter at home by means of an "Outbox". It's a box for things that you think you might not need, that you then periodically empty. [4 minutes]