In the last post, I was evaluating various solutions for generating the Julia-OpenCV bindings I dream of.
I am currently studying how the libcxxwrap library works, in order to check if it fits my requirements. I quickly noticed that it misses the capability of generating function with keywords (see the Github issue). This feature would be really interesting for the binding since OpenCV uses a lot of default and keyword arguments, both of which are nicely supported in python.
But no worries, Julia is a Lisp (or, at least, looks very much like it for many reasons). It should be easy to manipulate function code in order to add defaults, keyword, etc…
Let’s find out how.
Basics
The fundamentals of Julia metaprogramming are explained in the official documentation. You should read that before going further. However, we will start with the easy stuff.
First, let’s write a macro that creates a function.
1 2 3 4 5 6 7 8 9 10 11 |
|
What happens when macro make_fn1 is called? We first take value of the macro argument name and convert it into a string, which will be used later for printing. Then, we return an expression that defines a function. The name of the function comes from the same macro argument. When the macro is called, the returned expression is evaluated and thus the function ‘world’ is defined.
We can inspect the expression returned by make_fn1 by using the @macroexpand macro:
1 2 3 4 5 6 |
|
Note how in the function declaration we used $(esc(name))
instead of just using $(name)
. Otherwise, Julia hygiene rules will cause the function to have a random name:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Adding arguments
Ok, we can now generate function with arbitrary names, but we still miss arguments. A possible solution for this was discussed in this discourse thread.
This is the proposed solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
A more complex example
ok, how to add default arguments now?
I have tried to extend the previous solution and failed. I thought it was possible to use this substitution syntax again but I still didn’t figure out how the parser works with the macro output.
However, there is a better way to do this: We can easily manipulate
the AST programmatically,
by composing list of keywords and arguments. Even better, Julia allows you to
inspect the AST via the @dump
macro:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
This is pretty handy: you can write an example of the expression you would like to build, inspect its AST and use it as a reference.
Note how the function arguments are just a list of Symbol
s and Expr
essions.
Finally, here an example of a macro that defines a function with default and keyword arguments:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
Check out the function generated by the macro:
1 2 3 |
|
Conclusions
I think the AST manipulation offers what I need for extending libcxxwrap. Probably it will also be useful during the actual binding generation, allowing to automatically write Julia code that better integrates with the OpenCV interface.