In real world applications, some functions are quite complex and so may have many parameters.At application level, this is currently well supported through a set of options that may be passed though the command line. Such an an example might be:
gcc -s -O2 -mregparm=3 myapp.c
The most common way of using meta programming is to write functions that will scan the arguments provided, check their type and write the proper set of simple instructions that do the complex function.Such a function will look very similar to the main function of any application, with a loop that scans arguments one after the other.
Another example is the 'expression' function in expression2.pli. The 'expression' function is used to build an object of type Expression though calling a single function and providing many arguments to it that will specify all the content of the new expression.
a size := 12
a 'size :=' 12
The C++ template notion is an attempt to improve the C preprocessor macros notion.
Much more is achieved by Pliant meta programming mechanism.Such an example can be found in array.pli
Now if you like the C++ template notion, go on, write a pliant 'template' function that does the same. No problem, with Pliant we don't have to extend the language in order to add these kind of features: they are all applications of the Pliant meta-programming feature.
In any language, there are some features that cannot be implemented as functions because the arguments must not be computed sequentially before calling the function itself. Some languages provide lazy computation which helps with this kind of functions, but there is a cost on every function call because the mechanism appends everywhere, not only when usefull. Pliant meta programming allow to change the way arguments are computed whenever, and only, when required.
Such an example is shunt.pliRoughly speaking we can say that shunt c1 v1 c2 v2 ... vn is the same as the C expression c1 ? v1 : c2 ? v2 : ... vn.
Another much more complicated and powerfull example is the Pliant 'thread' function.Pliant 'thread' function is much more powerfull than the one found in classical languages because it will check what local variables of the calling function are also used in the thread, create a structure that can store the set of values and write the program that makes the copies before creating the new thread. An example
The example is the '%' function in intn.pli
When dealing with big integers, an expression such as a^b%c must be computed through calling a 'power_modulus' function that will perform the modulus at every stage of the a^b computation, because if not, the intermediate number a^b might be so big that it overflows the computer memory, not talking about speed issue.
So, in the example, the '%' function checks if the last instruction that computed it's first argument is a call to the '^' function. If yes, then it changes the call to the '^' function by a call to the 'power_modulus' function.
This example is very interesting because it proves that with Pliant, you can build powerfull libraries. By powerfull i mean libraries with a small set of intelligent functions that will rewrite the code on the fly in order to build an optimized program rather that a large set of functions that relies completely on the user to select the right one.
The '%' sample could have been expressed as an optimizing function that scans the instruction set at code generation time, and rewrites it when it finds a sequence '^' followed by '%', but it would have been a bit more complicated.
Todo: an example that removes x+0 or 0+x sequences.