Reputation: 301
There's this function:
function Γ(state::Dict{Symbol, <:Tuple{Vararg{Symbol}}})::Vector{NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}}
kwargs = Dict(kwargs)
keys = [key for (key, value) ∈ state]
instances_vec = [value for (key, value) ∈ state]
data = Vector{Vector{Symbol}}()
function recursive(data, current, depth = 1)
if depth <= length(instances_vec)
for instance ∈ instances_vec[depth]
recursive(data, push!(copy(current), instance), depth + 1)
end
else
push!(data, current)
end
end
recursive(data, [])
return [(;zip(keys,configuration)...) for configuration ∈ data]
end
which when run like this:
identifiers = Dict(:Id=>(:One, :Two, :Three, :Four, :Five), :Nationality=>(:Brit, :German), :Color=>(:Red, :Blue, :Green))
Γ(identifiers)
gives the following error:
ERROR: MethodError: Cannot `convert` an object of type
NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}} to an object of type
NamedTuple{#s589,#s588} where #s588<:Tuple{Vararg{Symbol,N} where N} where #s589<:Tuple{Vararg{Symbol,N} where N}
The type of the returned is: Array{NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}},1}
and the type of (:Id, :Nationality, :Color)
is Tuple{Symbol,Symbol,Symbol}
so I don't see why this gives a conversion error when there is no need for conversion especially since:
typeof((:Id, :Nationality, :Color)) <: Tuple{Vararg{Symbol}} && Tuple{Symbol,Symbol,Symbol} <: Tuple{Vararg{Symbol}} = true
Upvotes: 4
Views: 349
Reputation: 20248
First, the conversion comes from the fact that the declaration of your function declares a return type. If you remove (or comment out) this type annotation
function Γ(state::Dict{Symbol, <:Tuple{Vararg{Symbol}}}) #::Vector{NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}}
kwargs = Dict() # <- there was a typo here in your minimal example
keys = [key for (key, value) ∈ state]
instances_vec = [value for (key, value) ∈ state]
data = Vector{Vector{Symbol}}()
function recursive(data, current, depth = 1)
if depth <= length(instances_vec)
for instance ∈ instances_vec[depth]
recursive(data, push!(copy(current), instance), depth + 1)
end
else
push!(data, current)
end
end
recursive(data, [])
return [(;zip(keys,configuration)...) for configuration ∈ data]
end
then everything is fine:
julia> identifiers = Dict(:Id=>(:One, :Two, :Three, :Four, :Five), :Nationality=>(:Brit, :German), :Color=>(:Red, :Blue, :Green))
Dict{Symbol,Tuple{Symbol,Symbol,Vararg{Symbol,N} where N}} with 3 entries:
:Id => (:One, :Two, :Three, :Four, :Five)
:Nationality => (:Brit, :German)
:Color => (:Red, :Blue, :Green)
julia> Γ(identifiers)
30-element Array{NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}},1}:
(Id = :One, Nationality = :Brit, Color = :Red)
(Id = :One, Nationality = :Brit, Color = :Blue)
(Id = :One, Nationality = :Brit, Color = :Green)
[...]
Note that typing the arguments of a function/method where necessary is considered good practice. However, code that provides type assertions for return values is often less idiomatic in Julia: the compiler is really good at figuring out what the return type is!
Now the reason why this conversion fails is because the element type provided in the signature is not consistent with the actual element type of the returned vector:
julia> elem = (Id = :One, Nationality = :Brit, Color = :Red)
(Id = :One, Nationality = :Brit, Color = :Red)
julia> typeof(elem)
NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}}
julia> elem isa NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}
false
For NamedTuple{A,B}
to match NamedTuple{<:Tuple{Vararg{Symbol}},
<:Tuple{Vararg{Symbol}}}
, both conditions below have to hold:
A <: Tuple{Vararg{Symbol}}
B <: Tuple{Vararg{Symbol}}
Here, we have:
A = (:Id, :Nationality, :Color)
B = Tuple{Symbol,Symbol,Symbol}
so that, like you said, the condition for B
holds:
julia> B <: Tuple{Vararg{Symbol}}
true
but not the condition for A
:
julia> A <: Tuple{Vararg{Symbol}}
ERROR: TypeError: in <:, expected Type, got Tuple{Symbol,Symbol,Symbol}
Stacktrace:
[1] top-level scope at REPL[10]:1
# A is a value of type Tuple{...}, not the type itself
julia> typeof(A) <: Tuple{Vararg{Symbol}}
true
Upvotes: 3