I want to allow a user of my module to generate some types and functions via a macro which are then supported by generated functions.
For reasons, I am able to deduce constant scalar numbers from type information for a pair of types. Could be multiple scalars for a pair. I’d like to exploit this with generated functions to compute this total scalar at compilation time.
Two reasons for wanting this.
a) performance guarantees ( nothing is faster than if it is guaranteed to be constant scalar vs maybe jit figures out it’s a scalar )
b) simpler implementation. if I need to chain a bunch of these as Expr(:call)
s vs reducing into a scalar the implementation becomes much simpler.
Simplified MWE
julia> module Foo
macro gen(x)
name = Symbol("foo"*string(x))
typ = :(struct $name end)
fun = :(foo(f::$name) = $x*$x)
Expr(:escape, Expr(:block, typ, fun))
end
struct foo0 end
foo(x::foo0) = 0
@gen(2)
@generated function bar(a,b)
v = foo(a())*foo(b())
v
end
struct foo1 end
foo(x::foo1) = 1
@gen(3)
end
julia> Foo.bar(Foo.foo0(),Foo.foo1())
ERROR: MethodError: no method matching Main.Foo.foo1()
The applicable method may be too new: running in world age 25591, while current world is 25595.
Closest candidates are:
Main.Foo.foo1() at REPL[5]:19 (method too new to be called from this world context.)
...
julia> Foo.bar(Foo.foo0(),Foo.foo0())
0
julia> Foo.bar(Foo.foo0(),Foo.foo2())
0
julia> Foo.bar(Foo.foo0(),Foo.foo3())
ERROR: ...world age
julia> Foo.@gen(4); Foo.bar(Foo.foo4(),Foo.foo4()); # ultimate goal
I’ve seen a number of threads related to world age “work arounds” which I can’t quite get my head around. There are some packages out there as well ( GG.jl, FunctionWrappers ), not really sure how/if I can apply those to help.
Anyone have a recommendation/code example? I suspect my reason ‘a’ is not doable, but reason ‘b’ would still be nice to have a solution for.
Edit: specify that scalars are constant
Edit 2: I’ve got a working solution now.