Julia macro that generates accessors - macros

I need a macro that generates accessor functions in the Julia programming language. With a struct like this:
struct Account
account_number::String
balance::Float64
end
I want it to generate this code:
account_number(acc::Account) = acc.account_number
balance(acc::Account) = acc.balance
And I want to use it like so:
#generate_accessors Account
I have searched the internet and found the Accessors.jl package, but it does not seem to be related to my issue. There is quite a Julia community so I hope a macro like this exists somewhere. Unfortunately I do not have enough Julia experience to implement such a macro myself, I don't even know if such a macro can be made at all. Thanks for any help of pushes in the right direction.

I do not know of a library that has such a macro but creating a basic one is not too difficult:
# accessor(:foo, FooBar) -> quote foo(x::FooBar) = x.foo end
accessor(field, type) = :($(esc(field))(x::$type) = x.$field)
macro generate_accessors(type)
definitions = (accessor(s, type) for s in fieldnames(eval(type)))
Expr(:block, definitions...)
end
julia> struct FooBar
foo
bar
end
julia> #generate_accessors FooBar
bar (generic function with 1 method)
julia> foo(FooBar(1,2))
1
julia> bar(FooBar(1,2))
2

Related

Try-Catch Macro in Julia

I have the following functions.
foo(x) = x + 1
bar(x) = x * 2
I use them in a wrapper function (not sure whether this is even important).
function baz(x)
d = Dict{Symbol,Any}()
d[:foo] = foo(x)
d[:bar] = bar(x)
return d
end
The problem is that foo() and bar() can fail, and I want the code to continue running in this case. Introducing try catch statements would make the code very messy, however. So, is there maybe one of the following two solutions out there, that could make this easier?
Dream Solution
A macro that I could just write in front of d[:foo] = foo(x) and which in case of failure would write a default value do d[:foo].
Also-a Solution
A macro that would just continue if the code fails.
So, I managed to do the following. However, I have no clue if this is in any way good style.
macro tc(ex)
quote
try
$(esc(ex))
catch
missing
end
end
end
#tc foo(1)
1
#tc foo("a")
missing
Note the $(esc(ex)). This is important. If the expression is not escaped, the macro will work as expected in the global scope but not inside a function (as in the question). If anyone can provide a crisp explanation of why this is the case, please add a comment.

Using struct from a module inside another module in Julia

I have found similar questions on SO but none of them seem to give an answer that works for my case.
I have a few modules, in one of them I create a mutable struct which I want to be able to use in the others. All files are at the same level:
file_module_A.jl
file_module_B.jl
file_module_C.jl
In file_module_A.jl:
module A
mutable struct MyType
variable
end
end
In file_module_B.jl:
module B
# I need to import MyType here
end
In file_module_C.jl:
module C
# I need to import MyType here
end
I have tried the followings without success:
Using directly: using .A doesn't work
I can't use: include("./file_module_A.jl") in both B and C because when they interact between each other I get the error can't convert from Main.B.A to Main.C.A since include includes a copy of the whole code
Any ideas? Thanks in advance!
You need to use using ..A. using .A means to look for A in the current module (B in the example below), and you need an extra . to step up one module level, to Main if you run the example in the REPL:
module A
mutable struct MyType
variable
end
end
module B
using ..A: MyType
end

Using LuaJ with Scala

I am attempting to use LuaJ with Scala. Most things work (actually all things work if you do them correctly!) but the simple task of setting object values has become incredibly complicated thanks to Scala's setter implementation.
Scala:
class TestObject {
var x: Int = 0
}
Lua:
function myTestFunction(testObject)
testObject.x = 3
end
If I execute the script or line containing this Lua function and pass a coerced instance of TestObject to myTestFunction this causes an error in LuaJ. LuaJ is trying to direct-write the value, and Scala requires you to go through the implicitly-defined setter (with the horrible name x_=, which is not valid Lua so even attempting to call that as a function makes your Lua not parse).
As I said, there are workarounds for this, such as defining your own setter or using the #BeanProperty markup. They just make code that should be easy to write much more complicated:
Lua:
function myTestFunction(testObject)
testObject.setX(testObject, 3)
end
Does anybody know of a way to get luaj to implicitly call the setter for such assignments? Or where I might look in the luaj source code to perhaps implement such a thing?
Thanks!
I must admit that I'm not too familiar with LuaJ, but the first thing that comes to my mind regarding your issue is to wrap the objects within proxy tables to ease interaction with the API. Depending upon what sort of needs you have, this solution may or may not be the best, but it could be a good temporary fix.
local mt = {}
function mt:__index(k)
return self.o[k] -- Define how your getters work here.
end
function mt:__newindex(k, v)
return self.o[k .. '_='](v) -- "object.k_=(v)"
end
local function proxy(o)
return setmetatable({o = o}, mt)
end
-- ...
function myTestFunction(testObject)
testObject = proxy(testObject)
testObject.x = 3
end
I believe this may be the least invasive way to solve your problem. As for modifying LuaJ's source code to better suit your needs, I had a quick look through the documentation and source code and found this, this, and this. My best guess says that line 71 of JavaInstance.java is where you'll find what you need to change, if Scala requires a different way of setting values.
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
Perhaps you should use the method syntax:
testObject:setX(3)
Note the colon ':' instead of the dot '.' which can be hard to distinguish in some editors.
This has the same effect as the function call:
testObject.setX(testObject, 3)
but is more readable.
It can also be used to call static methods on classes:
luajava.bindClass("java.net.InetAddress"):getLocalHost():getHostName()
The part to the left of the ':' is evaluated once, so a statement such as
x = abc[d+e+f]:foo()
will be evaluated as if it were
local tmp = abc[d+e+f]
x = tmp.foo(tmp)

C Preprocessor, Macro "Overloading"

I'm trying to do some kind of Macro "Overloading", so that MACRO(something), gets expanded differently than MACRO(something, else).
Using a snippet I got from here (I'm not sure if it's 100% portable) and some functions from the Boost PP Library, I was able to make it work :D
//THESE TWO COUNT THE NUMBER OF ARGUMENTS
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)
//THIS ONE RETURNS THE PARAMETER AT POSITION _i FROM A LIST OF __VA_ARGS__
#define VA_ARG(_i, ...) BOOST_PP_ARRAY_ELEM(_i, (VA_NARGS(__VA_ARGS__), (__VA_ARGS__)))
//AND THIS ONE IS THE 'OVERLOADED' MACRO ;)
#define TEST(...) BOOST_PP_IF(BOOST_PP_EQUAL(1, VA_NARGS(__VA_ARGS__)), function_A(VA_ARG(0, __VA_ARGS__)), \ //1 parameter
BOOST_PP_IF(BOOST_PP_EQUAL(2, VA_NARGS(__VA_ARGS__)), function_B(VA_ARG(0, __VA_ARGS__) + VA_ARG(1, __VA_ARGS__)), \ //2 parameters
BOOST_PP_IF(BOOST_PP_EQUAL(3, VA_NARGS(__VA_ARGS__)), function_C(VA_ARG(1, __VA_ARGS__) + VA_ARG(2, __VA_ARGS__)), BOOST_PP_EMPTY())) // 3 parameters and so on ...
So TEST(a) = function_A(a)
TEST(a, b) = function_B(a + b)
TEST(a, b, c) = function_C(b + c)
Now I'm still missing two other things that I want to do:
(This one I don't really care if I never solve it) I believe that a MACRO can be written that when taking up the number of 'variants' and its correspondent 'output' generates a code similar like the one above. Something like TEMPLATE(3, function_A(...), function_B(...), function_C(...)) to generate the example above.
What happens when TEST() is called without arguments? Well, VA_NARGS expands to 1. But the first argument is ""(nothing). I'm trying to find a way to either detect 'zero' arguments in __VA_ARGS__ or to differentiate between a 'null' argument and a real one, in order to extend the 'overloading' function to react to this situation. Any ideas?
To answer your question 2 first. Yes, with variadic macros it is also possible to detect an empty argument list. The explanation is a bit lengthy, I have written it up here. It should be relatively easy to combine this approach with the boost macros that you are using.
For your question 1, yes this is also possible. Boost has some iterator macros that come close to this, I think, but they look a bit scary to use. If I understand correctly you have to use something like nested lists (a, (b, (c,d))), not too convenient.
(I wrote a set of macros that can achieve this more directly,
but unfortunately the package is not yet ready for release. Contact me in private if you are really interested in it.)
Edit: The P99 package is published in the mean time and contains a lot of stuff over macro "overloading" and type generic macros.

Defining operators in Boo

I'm looking to move some of my lighter weight metaprogramming from Nemerle to Boo and I'm trying to figure out how to define custom operators. For example, I can do the following in Nemerle:
macro #<-(func, v) {
<[ $func($v) ]>
}
Then these two are equivalent:
foo <- 5;
foo(5);
I can't find a way of doing this in Boo -- any ideas?
While Boo supports operator overloading by defining the appropriate static operator function (op_addition), and also supports syntactic macros, it does not support creating custom operators at this time.
I'm not sure if this is exactly what you need but you can create syntactic macros in Boo. There's some information on the CodeHaus site, http://boo.codehaus.org/Syntactic+Macros, but the syntax has changed in one of the recent releases. I don't know of any tutorials on the new syntax but the source release for Boo 0.8.2 has some examples (some of the language structures are implemented as macros). If you don't want to download the full source a view of the SVN repository is available, https://svn.codehaus.org/boo/boo/trunk/src/Boo.Lang.Extensions/Macros/. The assert macro would be a good place to start.
HTH
Stoo