
The Art of Metaprogramming (2005) - pcr910303
https://www.ibm.com/developerworks/library/l-metaprog1/index.html
======
rwmj
I'm involved in a couple of projects which do a lot of metaprogramming to
generate boilerplate. The generated code is usually C. For the generator I
wouldn't recommend using CPP or M4, use a real programming language instead.
I'm using OCaml since ML discriminated unions are a good fit for generating
code, but other languages would work too. It's a fantastic technique which
greatly reduces bugs, speeds development and eases maintenance.

Here are links to the generators for those projects:

[https://github.com/libguestfs/libnbd/blob/master/generator/g...](https://github.com/libguestfs/libnbd/blob/master/generator/generator)

\- This is a small C library. It uses a small-ish generator to generate a
state machine, Python bindings, OCaml bindings and (patch coming soon) Rust
bindings.

[https://github.com/libguestfs/libguestfs/tree/master/generat...](https://github.com/libguestfs/libguestfs/tree/master/generator)

\- This is a very large project mostly written in C, using a generator to
generate bindings in multiple programming languages, also RPC boilerplate,
structures, configuration code and much more. This generator is very large
having evolved with the project over 10+ years.

 _Edit:_ Some rules for effectively generating code:

(1) The generated code must look as far as is reasonable like it was hand
written. This is because you'll be debugging it. We also use #line directives
where possible.

(2) chmod -r the generated files so they cannot be edited by accident. Also
add a comment at the top pointing to the generator so that developers who have
no idea how it works can immediately find the right place.

(3) We add the generated files to the tarball (to allow end users to build
without needing OCaml) but keep them out of git (to avoid duplication in
commits).

(4) Maximum generation! If some piece of information is written twice, it
should probably be written once (in the generator) and the output should go to
those two places. Similarly we only have one generator in the project so no
one needs to read the Makefiles to find out how a file is generated.

------
quazar
In today's C++ you can precompute data structures at compile time with
constexpr.

Also slightly off-topic, but in SQL you can insert many tuples in one
statement like this

    
    
      insert into people (name) values ('Tony'), ('Bob'), ('Mary');

~~~
emmelaich
Nice. Works in sqlite3 - but it doesn’t like the parens around the tablename.

    
    
      $ cat multiple-insert.sql
      create table users (first, last);
      insert into users values ('fred','bloggs'), ('mary', ‘contrary');
      select * from users;
      $ sqlite3 < multiple-insert.sql
      fred|bloggs
      mary|contrary

------
sriram_iyengar
For me in 2006, when i moved from Java to Ruby, the videos by Dave Thomas
(pragprog) changed the dimension of thinking at code level - I did do java
reflection, but the whole method_missing to object specific methods etc.,
explained in a neat fashion by Dave Thomas were amazing !

~~~
kristianp
These ones?

[https://pragprog.com/screencast/v-dtrubyom/the-ruby-
object-m...](https://pragprog.com/screencast/v-dtrubyom/the-ruby-object-model-
and-metaprogramming)

Sample: [https://youtu.be/io34q2G4eOU](https://youtu.be/io34q2G4eOU)

------
jng
Art. SQL embedded in C using gotos. I don't want to meet whoever juxtaposed
those two.

~~~
gmfawcett
I can't be certain that they were the first, but Oracle's Pro*C/C++ tooling
does the same thing as the example in this article, and with virtually the
same syntax.

[https://docs.oracle.com/cd/E11882_01/appdev.112/e10825/toc.h...](https://docs.oracle.com/cd/E11882_01/appdev.112/e10825/toc.htm)

I've worked on a legacy app written with these tools. It's not the most awful
thing I've ever had to use. But there's a lot of magic in those macros, and
you have to code carefully to avoid introducing action-at-a-distance bugs,
esp. w.r.t. error handling.

~~~
tannhaeuser
It's called Embedded SQL, and is part of an ISO standard [1]. At one point an
embedded version of Informix translated ESQL/C to ISAM calls, without any SQL
parsing and query compilation at runtime. Though I don't know what this has to
do with metaprogramming as we know it today.

[1]:
[https://en.m.wikipedia.org/wiki/Embedded_SQL](https://en.m.wikipedia.org/wiki/Embedded_SQL)

~~~
gmfawcett
I had no idea that it was standardized. Thanks for sharing this!

------
why_only_15
The first reason (performance) given does not feel very compelling.
Metaprogramming is generally complicated, and performance is less important in
most cases than it once was, so making that tradeoff doesn't make as much
sense now as it might have when such systems were popular, or even in 2005.

~~~
amboo7
Metaprogramming is about making design more formal. A "constant fraction" of
anything written by hand should be automated, ideally. Metaprogramming is not
complicated, it is an essential skill, design may be complicated.

------
timClicks
Are there any tools (which are not part of the language itself) that can work
with IDEs? Using custom pre-build steps feels like something that's very hard
for tooling to introspect.

~~~
jchw
Editor integrations that aren’t aware of build systems are a huge issue.
Without awareness into the build system, its basically all just guesswork.

For languages like Go and Rust, this is partly solved by putting tooling into
the language and standardizing the build system. But even for languages that
have build systems, there’s reasons to use other build systems.

As far as I know, very few build systems used in the open world have readily
available integration with tooling. However, I think this is temporary. As an
example, Bazel and Go should play well together in the near future:

[https://github.com/bazelbuild/rules_go/issues/512](https://github.com/bazelbuild/rules_go/issues/512)

Hopefully, other languages will make mechanisms for code intelligence to
integrate with build systems. This is especially important if you want a good
developer experience across multiple programming languages.

Perhaps the more scalable (in terms of supporting many languages x many build
tools) alternative would actually be an inverse relation, a future language
server architecture where the build tool orchestrates the language servers.
Who knows.

------
zmix
Hmm...where is Part 2 of the series?

