If I’m understanding this correctly, I think you can achieve what you want by manually using the mechanism by which closures are implemented under the hood, namely callable structs:
code
module A
struct F{T}
a::T
end
end
module B
import ..A: F
function (f::F)(x::Integer)
return x + f.a
end
end
module C
import ..A: F
function (f::F)(x::Float64)
return x * f.a
end
end
using .A: F
function g()
a = 5
return F(a)
end
EDIT: Better yet, use a regular two-argument function and wrap a closure around it at the return point. Requires less code and gives you proper closure semantics if a
is reassigned.
module A
function f end
end
module B
import ..A: f
f(x::Integer, a) = x + a
end
module C
import ..A: f
f(x::Float64, a) = x * a
end
using .A: f
function g()
a = 5
return x -> f(x, a)
end
In either case:
julia> include("code.jl")
g (generic function with 1 method)
julia> g()(3)
8
julia> g()(3.0)
15.0
I suppose this is rather obvious, so apologies if it’s not helpful, but it seems like the way to accomplish your “bring your own method” goal. The capturing of variables must happen in a scope where said variables are defined, but you can decentralize everything else about the implementation.