Overriding methods with closures?

Hi,

Is it possible to override a method with a closure?

function add(x, y) x + y end
function test()
    add(y) = add(1, y)
    add(2)
end
test()

ERROR: MethodError: no method matching (::var"#add#4")(::Int64, ::Int64)

The same thing happens if I define add as function add(y) add(1, y) end, and it doesn’t seem to help if I declare global add as the first line of test. Is this possible, or do I just need to use different names?

Thanks in advance!

Hi and welcome!

The definition of add as a local name shadows all outer definitions.
To access any global identifier within a scope where that name is already taken, you can prepend them with the module name.
In your case, assuming you work in module Main:

function add(x, y) x + y end
function test()
    add(y) = Main.add(1, y)
    add(2)
end
test()
2 Likes

Thanks!

That makes sense. In this instance it would be nice if local identifiers could overload ones from outer scopes, but I imagine that the trade-offs around default cases for scopes are fairly tricky.

This implies that there’s still no overloading happening?

That is, if I wish to use the outer add in test() the only options are either add(x, y) = Main.add(x, y) or Main.add(3, 4)? There’s no automatic way of having the inner add include all the overloads of the outer one?

(There’s no problem with this, I can just rename things or use Main. Just wanting to make sure I understand)

Thanks!

Right, there’s no overloading.

The problem here is that local add and Main.add are two different identifiers. So, the local add cannot possibly add overloaded behavior to Main.add within local context.
The local add, however, can be overloaded:

function add(x, y) x + y end
function test()
    add(x, y) = Main.add(x, y)
    add(y) = add(1, y)
    add(y::Nothing) = 1
    return add(2), add(nothing)
end
test() # returns (3, 1)
2 Likes

I’m not sure what you want to achieve, but overloading a local function can be a way to build a function with multiple methods closing over some local state. For example:

function make_inc()
    c = Ref(0)
    inc(n) = c[]+=n

    inc() = inc(1)

    inc
end
julia> const inc = make_inc()
inc (generic function with 2 methods)

julia> inc()
1

julia> inc()
2

julia> inc(3)
5
2 Likes

Thanks, but not in this case. The use case is really just readability:

function helper(p1, p2, p3, v1, v2) ... end

function doer(p1, p2, p3)
    helper(v1, v2) = Main.helper(p1, p2, p3, v1, v2)

    helper(va, vb)
    helper(vc, vd)
    ...
end

(In retrospect, I probably should have put that in the first post)