How does a nested function display its local name only when assigned to a matching global name?

v1.8.3 MWE:

julia> function gh(n)
         g() = n
         h = () -> n
         g, h
       end
gh (generic function with 1 method)

julia> g2, h2 = gh(1)
(var"#g#2"{Int64}(1), var"#1#3"{Int64}(1))

julia> g, h = g2, h2 # displays g when assigned to global name g
(g, var"#1#3"{Int64}(1))

julia> g2, h2 # even affects display via other global names
(g, var"#1#3"{Int64}(1))

julia> g = 1 # reassign g to something else
1

julia> g, h, g2, h2 # display back to before
(1, var"#1#3"{Int64}(1), var"#g#2"{Int64}(1), var"#1#3"{Int64}(1))
1 Like

I agree that it seems weird but only at first sight.

And I think this is understandable: I wouldn’t like to be able to display names that are not part of the globals of that module. That would be confusing and would give the impression that I can do nondefinedname(...) - after all, this is how the globally defined functions are displayed (and used). Or even worse - there might already exist a global name that is identical to the name of the nested function. However, if the name is in the global scope (and refers to the same object), why not have the pretty display since no confusion is introduced?

Because there is an identity between the objects referred to by g and the other global name (g2 in the context), while g is also defined, it seems acceptable to have the other behavior you mention (e.g., affecting display via other global names).

The behavior is related to the MethodTable names.

Try this:

function gh(n)
    g() = n
    @info typeof(g).name.mt.name
    h = () -> n
    @info typeof(h).name.mt.name
    g, h
end

So, in the context of your MWE:

You’ll see that the MethodTable name for nested generic function g is set to :g.

Not the same for the anonymous functions (where you’ll have something like Symbol("#...").

Now, the show method for Function is actually checking if that name is also defined as a global variable - which is the case in your generic function but not in the case of the anonymous function: the result is that for the generic function show_sym is then used to handle the display (and g is a valid identifier, so it is displayed as it is).

There is a little more going on - which explains why g2 reverts to the old display when you reassign g (like checking the identity between the function to be displayed and the corresponding object from the module - but you can go into full details by exploring the method - see below).

Inspect this for more details.

P. S. The same behavior applies to Julia 1.9.2.

1 Like