Automatic programming: write code that writes code
programmers.stackexchange.com
programmers.stackexchange.com
For instance, I have nine libraries which do the same things for different file formats. Ideally I'd like the main API for each library to be as similar as possible. So the files which implement the API are generated by a Perl template script. Each library implements a couple of core functions; then the code generated from the template calls those functions in various ways. So I implement LowLevelStepImport; the automatically generated code uses that to implement ArrayStepImport, ClassStepImport, CCallableStepImport, etc. Then I implement LowLevelJTImport, and it implements ArrayJtImport, ClassJTImport, CCallableStepImport, etc.
There are lots of advantages to this. It means I don't have to write a bunch of boring code which is essentially the same. It makes it very easy to keep the APIs consistent across all the libraries. If I need to change part of the API, I just change the template and all the libraries update automatically. And if I add a new library, it is trivial to get it added to the collection.
Its objective says, "Teach students the virtues of metadata. More specifically, they learn how to formally represent the requirements of a Web service and then build a computer program to generate the computer programs that implement that service."
This is one of the problem sets potential ArsDigita (http://en.wikipedia.org/wiki/ArsDigita) recruits were required to solve during the first bubble.
UPDATE: Philip explains automatic code generation here (http://philip.greenspun.com/seia/metadata), and the "SQL for Web Nerds" book he references in the pset has been moved to (http://philip.greenspun.com/sql/).
One use that is highly relevant to many shops is creating client tools for their APIs. That is, creating libraries in common/target client languages for higher order abstractions of some of the granular/repetitive stuff and/or some of the mechanical access actions.
Keeping this sort of stuff straight by hand as an API evolves is tedious and error prone. Creating the infrastructure to generate these sorts of libraries is a largish cost up front but pays off hugely downstream.
We are still working (very early stage) on our tools, but our tools code generator(s) works/will work off of the same infrastructure that generates our API model metadata (https://sigkat.com/services/api/model)
abc
def
Other handy formatting:
italics are done by placing * around the text
indented text by putting two space characters before each line.
Useful for code snippets and other preformatted text
Or very long lines of text like this this this this this this this this this this this this this this thishttps://github.com/libguestfs/libguestfs/tree/e275786cb2bce7...
$ ./generator/generator
generated 300518 lines of codeAssuming you want to break a number of seconds contained in variable secnum into hours, minutes, and seconds, you would write something like this:
val secnum: Int = Console.readInt
val (hours, minutes, seconds) = choose((h: Int, m: Int, s: Int) => (
h * 3600 + m * 60 + s == secnum
&& 0 <= m
&& m < 60
&& 0 <= s
&& s < 60
) )
Code that computes the hours, minutes, and seconds will be generated at compile time (it's not interpreted). val (hours, minutes, seconds) = {
val loc1 = secnum div 3600
val num2 = secnum + ((−3600) ∗ loc1)
val loc2 = min(num2 div 60, 59)
val loc3 = secnum + ((−3600) ∗ loc1) + (−60 ∗ loc2)
(loc1, loc2, loc3)
}
Note that it works for constraints expressed in (parameterized) linear arithmetic and with operations on sets (like taking cardinality, union, intersection...).and paper: http://nautilus.cs.miyazaki-u.ac.jp/~skata/skatayama_pricai2...
attr_accessor :age
a bit of nifty metaprogramming kicks in and generates the following getter/setter methods in your class def age= value
@age = value
end
def age
@age
endand yes, pretty much all code we write is mandatory syntactical verbiage
Actually, it's runtime-during-parsing magic, IIRC.
I think a better example of metaprogramming might be the usage of method_missing in Ruby, or, say, __call and __callStatic in PHP, which all allow one to do interesting things with non-existent method invocations.
What about ActiveRecord (Rails' default ORM)? That makes great use of code-writing-code to generate a ton of methods on your class all based on db fields.
The primary concern of a problem should always be possible to solve without metaprogramming.
Metaprogramming is one of those things which sounds good but rapidly increases complexity beyond what is humanly manageable (even if you do it right i.e. LISP macros etc).
Building successive abstractions is the right way of doing things. I think even SICP tries to nail that into people's heads
Macros are the least desirable "quality" of various LISPs if you ask me.
A suitable abstraction can always be built cleanly and efficiently without relying on the macro system.
All you're talking about is taking your abstraction and calling it a "tool".
A basic abstraction remains untouched in the underlying implementation. It's just a call away.
There are semantic and technical differences between abstraction and meta-programming.
We are so very far away from understanding the best approaches for writing software that solves problems.
To add some context, I'm in the "interpreters all the way down" camp. On other words, it seems to me that hardware vs software is an arbitrary distinction. After all, someone had to decide how the hardware would respond to code, in other words, someone had to physically program the hardware to behave a certain way. In that sense, isn't the code we write (in lisp, C, C++, etc...) just a way to meta-program the hardware?
I'm not sure if that was very clear... Another way of saying it is that simply declaring "software should never modify software" or "software should never be treated as data" is an arbitrary and almost meaningless declaration.
> Building successive abstractions is the right way of doing things.
You seem to think that "code that writes code" only addresses problems that are solvable by building successive abstractions.
Most "code that writes code" that I've seen had nothing to do with implementing abstractions. Most were implementing code based on data, database-driven-code generation if you will.
oid "1.3.6.1.4.1.12345"
group "1"
message "MyNotification"
field string message_body
and it would generate a Java class called MyNotification which contained about 100 lines of code to handle sending and receiving of these notification messages, plus the MIB equivalent so that network management tools can understand the message.Once the messages were defined, they rarely changed since customers would have to change their network management tool configuration, so it was mainly only used to add new notification types once the original set stabilized, but it saved a ton of time over having to hand craft each message type.
I think MDSD is very undeservedly underrated in the web world.
I was ecstatic that I could write a large chunk of my code automatically. What I eventually realized was that I had missed abstractions that would have allowed me to achieve the same ends with generics and dynamic programming. Also a change of language (C++ at the time) would have drastically changed my perspective.
YMMV.
I wrote Python scripts which spat out the method calls with the appropriate arguments.
Yes, I could probably have written an abstraction to create the data set in Java, but it worked out faster to write it in Python, and one doesn't get marks for generating test data.
I am guessing code that writes code is an attempt to further decouple a process from the code providing the support for that process (data driven programming is another example but is often very domain specific).
It seems that full decoupling of a processes behavior from the code supporting that process would be the end goal. I don't think this is something that meta-programming fully solves.
E.g. http://sourceforge.net/projects/malclassifier.adobe/files/Ad...
I daydream of a programming language to which I can fuzzily explain my needs and it automagically solves problem. Natural language processing might be hard to debug as part of a programming language though.
On one occasion, this worked out better than expected, when I realized I could convert my compiler to an interpreter and get a really flexible program configurable at runtime.
That's the core of our startup :) We're building robots who can build games. You just give us basic simple instructions like "this type of gameplay, with these features and these characters" that can be described in 5 lines of code. And we build a whole game with it. To the user, it looks automagic. But inside, it's just a compiler that converts one data format into another.
> Natural language processing might be hard to debug as part of a programming language though.
You don't really need to go there. Just limit your input to what your compiler knows. Instead of trying to guess intent from ambiguous input, you just give them options instead. If you really want the user to have the freedom to type their ideas out, then use auto-complete and/or code suggestions. That "feels" like natural typing, but dodges the problem with NLP that is trying to guess what ambiguous input means.
The worst codebase I ever worked on was some C++ generated using a scripting language. It made awkward and unweildy looking C++ code that leaked smart pointers everywhere and barely worked. But man, the authors that wrote it thought they were so clever.
Apple's Objective-C to MSVC C++ clang compiler is a close second. I'm not sure if it ever made it out into the wild or if it was just an Apple internal thing, but there's nothing like debugging a 3000 character post-preprocessor C++ expansion of several nested obc_msgsend calls.
It's rough when you long for the C preprocessor. At least the CPP limitations prevent people from stretching themselves too far into meta territory. It's almost kind of elegant in its badness, now that I've seen what people can do to imperative/OO languages when more capable macro processors are involved.
Protocol Buffers and Thrift seem to be good examples of code generation.
Another case that illustrates this point: Suppose you are defining a wire protocol between two communicating processes. The tool you want is a language in which the protocol is defined, from which sender and receiver code can be generated. A flexible tool would be able to generate sender and receiver in different languages, or, in fact, in multiple languages. It would be able to generate language-independent documentation of the protocol in multiple formats. It's not easy to see how macros embedded in a single programming language could produce these results.