That's exactly the point of code generation - to fill out mundane code that can't be replaced (directly or nicely) by function calls and/or would be a hassle and error to go through and do manually.
An example of this is my profiling system, which preprocesses BlitzMax files and spits out a version that writes a performance profile to the disk when it ends. The code that it autogenerates is extremely simple - PushFunctionCall() and the start and PopFunctionCall() before each return - but it would be difficult to impossible to maintain this in a project and keep sane.
Another example is C++, which started out life as a preprocessor for C. Virtual methods can be replaced by a function call for sure, but it's not typesafe and looks quite ugly. That's what Frank's code is doing (but he might as well just use BlitzMax instead of messing around with code generators).
Code generation at runtime can also be very useful. You can write a function such as memoize in lisp that will automatically cache the result of a large calculation - basically, the equivilant blitz syntax would be (it can't work for a few reasons but it can in lisp):
Which would generate MyLoadImageFast as:
Which will take so many milliseconds on the first call at it loads the image from disk, but subsequent calls trying to load the same image will return the cached version. But the point of code generation is that you can just write the function to generate the cache enabled version of a function once, and from then on you just have to call memoize to automatically generate a cached version of any function, and it'll be bug free.
A good way to think this is to think about functions as a first class data type that you can pass around and manipulate just like integers, strings and objects. So a code generator is a function that operates on a function.
An example of this is my profiling system, which preprocesses BlitzMax files and spits out a version that writes a performance profile to the disk when it ends. The code that it autogenerates is extremely simple - PushFunctionCall() and the start and PopFunctionCall() before each return - but it would be difficult to impossible to maintain this in a project and keep sane.
Another example is C++, which started out life as a preprocessor for C. Virtual methods can be replaced by a function call for sure, but it's not typesafe and looks quite ugly. That's what Frank's code is doing (but he might as well just use BlitzMax instead of messing around with code generators).
Code generation at runtime can also be very useful. You can write a function such as memoize in lisp that will automatically cache the result of a large calculation - basically, the equivilant blitz syntax would be (it can't work for a few reasons but it can in lisp):
Function MyLoadImage:Timage( path$ ) return LoadImage( path ) End Function Functino MyLoadImageFast = Memoize( myLoadImage )
Which would generate MyLoadImageFast as:
Function MyLoadImageFast:TImage( path$ ) Global loadedImages:Tmap = new TMap if ( loadedImage.ValueForKey( path ) ) return TImage( loadedImage.ValueForKey( path ) ) Endif local im:Timage = loadimage( Path ) loadedImages.Insert( path, im ) Return im End Function
Which will take so many milliseconds on the first call at it loads the image from disk, but subsequent calls trying to load the same image will return the cached version. But the point of code generation is that you can just write the function to generate the cache enabled version of a function once, and from then on you just have to call memoize to automatically generate a cached version of any function, and it'll be bug free.
A good way to think this is to think about functions as a first class data type that you can pass around and manipulate just like integers, strings and objects. So a code generator is a function that operates on a function.