How do method definitions work inside functions?

I’m trying to understand how method definitions work inside functions. (Is this mentioned anywhere in the documentation?) From this post I learned that all method definitions for a given local function f are combined to an anonymous functions, and each definition is replaced by assigning this anonymous function to f. It doesn’t matter where the method definitions occur inside the enclosing function. For example, the function

function a()
    f() = 0
    return f
    f(x) = x
end

returns a function with two methods. If there are two methods with the same signature, then the first one is ignored, and the user gets a warning.

However, there are cases where this explanation doesn’t seem to work (with Julia 1.6.1). For instance, I get

function b1()
    if true
        f() = 0
    else
        f(x) = x
    end
end

b1()  # generic function with 2 methods  (as expected)

but

function b2()
    if false
        f() = 0
    else
        f(x) = x
    end
end

b2()  # UndefVarError: f not defined

The picture gets even confusing if one adds empty functions. Here are some examples:

function c1()
    function f end
    return f
end

c1()  # generic function with 0 methods  (as expected)

function c2()
    function f end
    return f
    f() = 0
end

c2()  # UndefVarError: f not defined

function c3()
    g = function f end
    return g
end

c3()  # generic function with 0 methods  (as expected)

function c4()
    g = function f end
    return g
    f() = 0
end

c4()  # nothing  (which is not even a function)

function c5()
    if false
        f() = 0
    else
        function f end
    end
end

c5()  # nothing

Is this the intended behavior? If yes, what are the rules behind this?

See the following issue and a lot of issues that mention it:

TL;DR: you should not define local methods in different branches, but not all of them error or give an easy to interpret error message.

3 Likes
2 Likes