I'm trying to write a parametric struct where one of the parameters is a Boolean value type, and where the type of a member should depend on the value of this Boolean. The struct should also inherit from a parametric type, where the parameters again depend on the Boolean. Simplified, this looks something like this:
struct Test{D} <: AbstractDict{String, Union{String, D==true ? Number : Union{}}}
d::Dict{String, Union{String, D==true ? Number : Union{}}}
end
However, when I create an object with Test{true}(Dict{String, Union{String, Number}}()) the type parameter seems to always be ignored and I end up with d::Dict{String, String}.
Is what I'm trying to do even possible in Julia?
Apparently, one way to specify a type V, for both field type and supertype parameters, that depends on a constructor boolean value type parameter D, without specifying V in the constructor type parameter, is to:
new expression.struct TestC{D,V} <: AbstractDict{String, V}
d::AbstractDict{String, V}
TestC{true}() = new{true, Union{String, Number}}(Dict{String, Union{String, Number}}())
TestC{false}() = new{false, String}(Dict{String, String}())
TestC(aDict::S) where S <: AbstractDict{String, Union{String, Number}} = new{true, Union{String, Number}}(aDict)
TestC(aDict::S) where S <: AbstractDict{String, String} = new{false, String}(aDict)
end
import Base: iterate, length, get
Base.iterate(t::TestC) = iterate(t.d)
Base.iterate(t::TestC, i::Int64) = iterate(t.d, i)
Base.length(t::TestC) = length(t.d)
Base.get(t::TestC, k::String, dflt) = get(t.d, k, dflt)
import Test: @testset, @test
@testset begin
@test TestC{true, Union{String, Number}} == typeof(TestC{true}())
@test TestC{false, String} == typeof(TestC{false}())
@test TestC{true, Union{String, Number}} == typeof(TestC(Dict{String, Union{String, Number}}()))
@test TestC{false, String} == typeof(TestC(Dict{String, String}()))
@test "TestC{true, Union{Number, String}}(\"one\" => 1)" == string(TestC(Dict{String, Union{String, Number}}("one" => 1)))
@test 1 == TestC(Dict{String, Union{String, Number}}("one" => 1))["one"]
@test TestC{true, Union{String, Number}} <: AbstractDict{String, Union{String, Number}}
@test TestC{false, String} <: AbstractDict{String, String}
@test false == (TestC{true, Union{String, Number}} <: AbstractDict{String, String})
@test false == (TestC{false, String} <: AbstractDict{String, Union{String, Number}})
@test "TestC{true, Union{Number, String}}(\"one\" => 1)" == string(TestC(TestC(Dict{String, Union{String, Number}}("one" => 1))))
@test "TestC{false, String}()" == string(TestC(TestC{false}()))
end