Search code examples
juliafirst-class-functions

In Julia, why do scope rules for functions appear inconsistent compared to other first class objects?


The Julia docs state that functions are first class objects. I understand that to mean that I ought to be able to use and define them in the same way I would plain old data types.

I'm therefore surprised that

function a(b::Int64)
    if b > 0
        c = 1
    else
        c = -1
    end
end
a(2)

works beautifully, whilst

function d(e::Int64)
    if e > 0
        println("Positive argument")
        function f()
            println("Return positive")
            return e
        end
    else
        println("Negative argument")
        function f()
            println("Return negative")
            return e
        end
    end
    return f
end

works when used, but does something very counter intuitive:

>>> g = d(2)
Positive argument
(::f) (generic function with 1 method)
>>> g()
Return negative
2

Or alternately:

>>> g = d(-2)
Negative argument
ERROR: UnderVarError: f not defined

which is perhaps more useful than returning something unexpected, but none the less is even more confusing.

I would expect that the version of f from the appropriate branch would be returned. Where has my understanding of how function definitions in Julia work gone wrong?


Solution

  • I can show you how to solve the problem, but the actual behavior you describe is a known issue https://github.com/JuliaLang/julia/issues/15602.

    In general if you do this:

    function d(e::Int64)
        if e > 0
            println("Positive argument")
            f = function()
                println("Return positive")
                return e
            end
        else
            println("Negative argument")
            f = function()
                println("Return negative")
                return e
            end
        end
        return f
    end
    

    all works fine. The difference is that you create an anonymous function and assign it to a variable.