In theory, I have a macro that allows me to interpret
@← a = f(b...)
as either
f!(a, b...)
or
a = f(b...)
depending on whether f!
is defined or not. My attempt at writing such a macro is
macro ←(input)
# expression needs to be of form `a = f(b...)`
a = input.args[1]
f = input.args[2].args[1]
f! = Symbol(f, "!")
b = input.args[2].args[2:end]
output = quote
if (@isdefined $f!) && isa($f!, Function)
return $f!($a, $(b...))
elseif (@isdefined $f) && isa($f, Function)
return $a = $f($(b...))
else
error("ERROR!")
end
end
esc(output)
end
However, it does not seem to work as it should whenever I’m using it in local scope (e.g. some kind of function, etc.). Any idea why?
I think, you probably meant to write return $f!($a, $(b...))
instead of return $f!($a, $b...)
. The latter interpolates Any[:(b...)]
as a literal into the function call and then that gets splatted at runtime into $f!
, so you are effectively calling f!(a, :(b...))
. If you add the parentheses, the array is actually splatted into the expression tree.
1 Like
BTW, do you know about BangBang.jl? It sounds like you are trying to achieve something very similar.
3 Likes
You are completely right. However, the problem persists.
I did not! Their macro @!
is indeed doing something very similar. I’ll check that, thanks.
2 Likes
Could you share a full example of how you are calling it? That usually makes it a lot easier to help you.
Is the problem that isdefined
doesn’t handle local scope? Essentials · The Julia Language
I think I’m doing something like
f(b) = [1, 1, 1]
function f!(a, b)
a[1] = 2
a[2] = 2
a[3] = 2
a
end
function g(v)
@← v[1] = f("!@£%")
v
end
v = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
g(v)
which, however, seems to work just fine.
In actual practice, when running the following snippet
using RungeKutta
u0 = [2.0; 3.0; -14.0]
tspan = (0.0, 1.0)
problem = Lorenz(u0, tspan)
solver = Euler(h = 1e-3)
solution = solve(problem, solver)
plot(solution)
which calls my package RungeKutta.jl, I’m having trouble when changing from
f!(k[i], v, t[n] + h * c[i])
to
@← k[i] = f(v, t[n] + h * c[i])
lines 19-20 in step.jl.
It could very well be! Any alternative to @isdefined
then?
EDIT: I’ve changed @isdefined
with a custom one from https://discourse.julialang.org/t/check-whether-a-variable-is-defined/1018/3?u=jlapeyre which should work in local scope too, but, once again, without success.
EDIT 2: It turns out that, in this case, Julia correctly uses Base.@isdefined
instead of Core.@isdefined
, which is able to deal with the current scope.
1 Like
Getting rid of the return
s solved the issue.
2 Likes