Discontiguous Lexical Scope for Multiply Dispatched Functions

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.

5 Likes