Julia 1.10 introduces "Tuple field type cannot be Union{}" error in AlgebraOfGraphics.jl

Hi All -

I’m trying to fix an error introduced in AlgebraOfGraphics by Julia 1.10 and I’m having a hard time understanding what is actually happening. The error is now thrown any time the function AlgebraOfGraphics.density() is used, and I think it’s happening at one of the following lines:

_kde(data::NTuple{1, Any}; kwargs...) = kde(data...; kwargs...)
_kde(data::Tuple; kwargs...) = kde(data; kwargs...)

As a result of the following update to julia: make Tuple{Union{}} unconstructable by vtjnash · Pull Request #49111 · JuliaLang/julia · GitHub

But I’m just kind of lost as to 1. why this change was made and 2. what we’re supposed to do instead. Any help would be appreciated!

Can you post a full stack trace? I don’t see where this is trying to construct Tuple{Union{}} just from looking at it

Here’s a (modified) example from the AlgebraOfGraphics tutorial that will trigger the error:

using PalmerPenguins, DataFrames, AlgebraOfGraphics

penguins = dropmissing(DataFrame(PalmerPenguins.load()))

penguin_bill = data(penguins) * mapping(
    :bill_length_mm => (t -> t / 10) => "bill length (cm)",
    :bill_depth_mm => (t -> t / 10) => "bill depth (cm)",
)

plt = penguin_bill * density(npoints=50) * mapping(col = :species)

axis = (width = 225, height = 225)

draw(plt; axis = axis)

And the resulting stack trace:

ERROR: LoadError: Tuple field type cannot be Union{}
Stacktrace:
  [1] map(f::Function, d::Dictionaries.Indices{Union{}})
    @ Dictionaries C:\Users\Randy\.julia\packages\Dictionaries\7aBxp\src\map.jl:91
  [2] unnest(vs::Vector{@NamedTuple{}}, indices::Dictionaries.Indices{Union{}})
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layer.jl:81
  [3] unnest_dictionaries(vs::Vector{@NamedTuple{}})
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layer.jl:84
  [4] map(f::AlgebraOfGraphics.var"#192#193"{@NamedTuple{datalimits::Tuple{Tuple{Float64, Float64}, Tuple{Float64, Float64}}, npoints::Int64}}, processedlayer::ProcessedLayer)
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layer.jl:101
  [5] (::AlgebraOfGraphics.DensityAnalysis{MakieCore.Automatic, MakieCore.Automatic, MakieCore.Automatic})(input::ProcessedLayer)
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\transformations\density.jl:30
  [6] process(layer::Layer)
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\processing.jl:102
  [7] iterate
    @ Base .\generator.jl:47 [inlined]
  [8] collect(itr::Base.Generator{Layers, typeof(AlgebraOfGraphics.process)})
    @ Base .\array.jl:832
  [9] map
    @ Base .\abstractarray.jl:3301 [inlined]
 [10] ProcessedLayers(a::Layer)
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layers.jl:41
 [11] compute_axes_grid(d::Layer; axis::@NamedTuple{width::Int64, height::Int64}, palettes::@NamedTuple{})
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layers.jl:114
 [12] compute_axes_grid
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layers.jl:110 [inlined]
 [13] compute_axes_grid(fig::Makie.Figure, d::Layer; axis::@NamedTuple{width::Int64, height::Int64}, palettes::@NamedTuple{})
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layers.jl:100
 [14] compute_axes_grid
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\algebra\layers.jl:97 [inlined]
 [15] #240
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:21 [inlined]
 [16] update
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:10 [inlined]
 [17] plot!(fig::Makie.Figure, d::Layer; axis::@NamedTuple{width::Int64, height::Int64}, palettes::@NamedTuple{})
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:21
 [18] plot!
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:16 [inlined]
 [19] (::AlgebraOfGraphics.var"#244#245"{@NamedTuple{width::Int64, height::Int64}, @NamedTuple{}, @NamedTuple{}, @NamedTuple{}, @NamedTuple{}, Layer})(f::Makie.Figure)
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:48
 [20] update
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:10 [inlined]
 [21] #draw#243
    @ AlgebraOfGraphics C:\Users\Randy\.julia\packages\AlgebraOfGraphics\yhdjr\src\draw.jl:47 [inlined]
 [22] top-level scope
    @ c:\Users\Randy\.julia\dev\TidierPlots\scratch\density_test.jl:14
in expression starting at c:\Users\Randy\.julia\dev\TidierPlots\scratch\density_test.jl:14

Ah, I see. You should report this bug to Dictionaries then. It is using an unstable private API (Core.Compiler.return_type) and appear to be not fully implementing the Base.map API correctly (the return type depends on inference. While, I think the usual implementations use @default_eltype?

That likely won’t help with getting away from internals:

help?> Base.@default_eltype
  │ Warning
  │
  │  The following bindings may be internal; they may change or be removed in future versions:
  │
  │    •  Base.@default_eltype

  No documentation found for private symbol.

which in the end also uses Core.Compiler.return_type:

julia> @macroexpand Base.@default_eltype([19293])
quote
    #= array.jl:743 =#
    if [19293] isa Base.Generator && ([19293]).f isa Base.Type
        #= array.jl:744 =#
        var"#7#T" = ([19293]).f
    else
        #= array.jl:746 =#
        var"#7#T" = (Base.Core).Compiler.return_type(Base._iterator_upper_bound, Base.Tuple{Base.typeof([19293])})
    end
    #= array.jl:748 =#
    Base.promote_typejoin_union(var"#7#T")
end

I think for the case in Dictionaries.jl (link) there isn’t really anything else to do other than rely on inference. The question is rather - what introduced that Union{} in the first place, seeing as its also present in the frames before Dictionaries.jl?

Looking up the stackframes, I think it’s this that introduces the Union{} somehow:

I don’t know about the internals of AlgebraOfGraphics, but I think the question is why this causes map(_ , outputs) to be a Vector{@NamedTuple{}}.