What is `Core.Box()`?


#1

While debugging, this is something I see quite often. I didn’t find any trace in the docs and really curious about its function. Any pointer or hint is appreciated!


#2

This has to do with ‘boxing’ data, which is e.g. required when the concrete type of some variable in a function body cannot be determined from the types of the inputs of a function (type instability). See https://docs.julialang.org/en/stable/manual/performance-tips/#Avoid-changing-the-type-of-a-variable-1 for an example (although Core.Box doesn’t actually show up in the lowered code here). In this case, the actual type of the data is only known at runtime, and so Julia has to store a type tag identifying the runtime type along with the actual data. Boxed variables are heap-allocated and tracked by the garbage collector.

Seeing Core.Box in the output of code_warntype is usually a sign that inference can’t determine the concrete type of some variable, and can be a source of performance issues.

Here’s a case where Core.Box shows up in lowered code in Julia 0.6.1 (from https://github.com/JuliaLang/julia/issues/19668#issuecomment-268523270):

julia> struct KWArg
           x::Int
           KWArg(;x::Int=1) = new(x)
       end

julia> kwarg(;x::Int=1) = x
kwarg (generic function with 1 method)

julia> @code_lowered KWArg()

CodeInfo(:(begin 
        nothing
        return ((Core.getfield)($(QuoteNode(Core.Box(#call#3))), :contents))(1, #self#)
    end))

(Note: I actually found it hard to find cases where an explicit Core.Box shows up in lowered code for functions on 0.6.1.)

This is where Core.Box is defined on current master: https://github.com/JuliaLang/julia/blob/56b9593d8c25b839511e33e1fb06b58f95ce15df/base/boot.jl#L301-L305. Note the Any type of the contents, and the @nospecialize in the constructor.


#3

No it’s totally unrelated to inference.

It’s added to the code when the frontend (parser) need a variable that can be mutated by multiple functions. (and in the case you show I’m 90% sure there was an issue for it). It does hurt inference but it is NOT caused by bad inference.

For the user, it’s basically the same as Base.RefValue{Any}. You should not use it which is why it’s not in the document.


#4

Thanks for clearing that up. I guess I was confusing the concept of boxing in general with Core.Box.

Yeah, I linked to your issue comment.


#5

Thanks!


#6

Thanks too, buddy!