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

How to extend the life of your clothes

Here are some tips on preserving your clothes! Ways to make the wash easier on the clothes, and increase the number of wears one can get between washes. [3 minutes]

How to spring-clean your blog

Here are ways I found to clean up a Blogger blog. I've found and fixed many things with content, images, navigation, theme, descriptions, and analytics. [4 minutes]

How to grow a large crystal of copper (II) sulphate in 5 days

Presenting a faster way to grow large copper sulphate crystals! The pictured 4cm crystal took me 5 days by cooling, instead of the 3-6 weeks it would take by evaporation. [4 minute read]