Vector{NamedTuple} vs Vector{@NamedTuple}?

How can I open my function method to work on all NamedTuples collected into a Vector? I don’t understand why this isn’t working.

function multicall(f::Function, user_inputs::Vector{NamedTuple}; kwargs...)
    out = []
    for input in user_inputs
        result = f(input; kwargs...)
        push!(out, result)
    end
    return out
end
export multicall
julia> typeof(user_inputs)
Vector{@NamedTuple{fracture_operating_stress_file::String, fracture_residual_stress_file::String, crack_type::Symbol}} (alias for Array{@NamedTuple{fracture_operating_stress_file::String, fracture_residual_stress_file::String, crack_type::Symbol}, 1})

julia> multicall(compute_fracture_polys, user_inputs)
ERROR: MethodError: no method matching multicall(::typeof(compute_fracture_polys), ::Vector{@NamedTuple{…}})
The function `multicall` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  multicall(::Function, ::Vector{NamedTuple}; kwargs...)

The input was constructed within another function in a somewhat irregular way:

user_inputs = NamedTuple.(zip(allfiles...))

Does replacing it (the signature) with Vector{<:NamedTuple} work?

6 Likes

Hmm, yes that fixes it.

I knew about using that for abstract types like Vector{<:Real}, but I didn’t think it was applicable for a NamedTuple. I thought NamedTuple was concrete because

julia> subtypes(Real)
4-element Vector{Any}:
 AbstractFloat
 AbstractIrrational
 Integer
 Rational

julia> subtypes(Float64)
Type[]

julia> subtypes(NamedTuple)
Type[]

But I see now that it’s neither abstract nor concrete?

julia> isabstracttype(NamedTuple)
false

julia> isconcretetype(NamedTuple)
false

So I don’t know what that means.

Better MWE:

julia> function f(v::Vector{<:NamedTuple})
           return v
       end
f (generic function with 2 methods)

julia> nt = (; x=3, y=4)
(x = 3, y = 4)

julia> f([nt])
1-element Vector{@NamedTuple{x::Int64, y::Int64}}:
 (x = 3, y = 4)

@NamedTuple is a NamedTuple but NamedTuple is not a supertype of @NamedTuple?

julia> nt isa NamedTuple
true

julia> supertypes(typeof(nt))
(@NamedTuple{x::Int64, y::Int64}, Any)

I’m not following how this works.

NamedTuple is an UnionAll, not a DataType. Only DataType types may be concrete. (In fact, AFAIK only a Tuple type can be not concrete if it’s a DataType.)

There’s nothing special here about NamedTuple, so let’s take a simpler example, maybe that clears things up:

julia> struct S{P} end

julia> S isa UnionAll
true

julia> S{Int} isa DataType
true

julia> s = S{Int}()
S{Int64}()

julia> typeof(s) == S{Int} <: S
true

julia> isconcretetype(S)
false

julia> isconcretetype(S{Int})
true

Yeah, abstract and concrete aren’t opposites. A type is “abstract” if and only if it’s declared with abstract type.

4 Likes

You can reason your way to this realization. If you know that a value is a NamedTuple, then what is the type of its first element? Since you cannot answer that question (nor look it up anywhere), the type isn’t fully specified.

With a concrete type, all the type info is known, including the type of each element.

It’s the same for Vector, without knowing the eltype you and the compiler lack crucial information about how to handle it.

3 Likes