why precompile is needed in codegen

Feb 25, 2014 at 10:30 AM
Edited Mar 3, 2014 at 12:06 PM
the codegen project contains a set of c++ / cs logic to generate vb.net source code with repeated logic, while there is also a small program called precompile.exe to support a very simple syntax to generate source code by replacing some keywords to others, or include another source file. this program is heavily used in the formation project.
the reason i need this is mainly for the performance.
to explain the impact of performance, two facts need to be clarified first.
  1. generics and type erasure
    your template / generic methods / classes are not generic during runtime in .net, instead they regression to the very basic types as the constraints in the class definition. i.e.
    void SomeFunction<T : IDisposible>(T input) equals to
    void SomeFunction(IDisposiable input>
    which is similar when it's a class instead of a function.
    to make it simpler, you cannot use any functions other than the constraints provided.
  2. interface is slow, much slower than a static function / not inherited function
    calling a function of an interface needs to go through the virtual function table, since the caller has no idea which type has been sent in, and where is the function entry of the type.
let's go back to the formation project, there are three binary search tree implementations, an ordinary binary search tree <obst>, an splay binary search tree <sbst>, a balanced binary search tree <bbst>. and all of these implementations have enough functionality to be wrapped as a map. then i will have three implementations of map, ordinary map <omap>, splay map <smap>, balanced map <bmap>. whether we need three implementations of map or not is not what we are discussing here. but then we need to write three classes omap, smap, bmap. to avoid to write the logic for three times -- not only write them three times, but also need to update for three times if we need to update the logic later, we can use interface, obst / sbst / bbst are all implementing an interface ibst. but according to the fact 2 above, the performance will be significant impacted if we call interface functions in the map. i.e.
class map<T : ibst<pair<XT, YT>, XT, TY>
private readonly T t;

void insert(XT x, YT y)
t.insert(make_pair(x, y));
since the t.insert here is a virtual function.
and according to the fact 1, we cannot write the code as what we can do in c++.

in this case, generating the source code from a template looks like a good way. the generator needs to be able to input several parameters to decide the types for output and internal types to use, and a template file which is written in some pseudo code with the output and internal types to be marked specifically, and be able to be replaced during generation stage.
to make the generator common, i.e. i do not want to write one generator for one scenario, it's waste, define and include functions are required. say,

class ##OUTPUT_TYPE##<KT, VT>
private readonly ##INTERNAL_TYPE##<pair<KT, VT>> t;
public void insert(KT key, VT value)
t.insert(make_pair(key, value));
generating script
##INCLUDE template
this sample is just part of the bmap.vbp and map.vbp, in c# syntax instead of vb.net syntax. vbp is short for visual basic precompiled
if i need to update the map logic, i only need to update map.vbp, and run the generator again to get the new source code. both performance and maintainability are all satisfied.