Yes, this is correct and expected behaviour. Vector{Pair{Any, Any}} is a concrete type that can be instantiated, it would be a vector of pairs of different types. Concrete types cannot have subtypes, therefore Vector{Pair{Int, Int}} cannot be its subtype.
This has to do with invariant and contravariant types, you can read more about this here: Types · The Julia Language
In particular, you can find this warning in the docs:
This last point is very important: even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real} .
Thank you for the very quick replies. It seems odd that Tuple is covariant, while Pair is invariant; I understand that covariance is special-cased, but why isn’t a type as fundamental as Pair - not unlike Tuple - made covariant?
I am currently working with a library that asserts types with constraints::Vector{Pair{Any,Any}}, so I need to enforce the Any quite awkwardly:
A type like Vector cannot really be covariant: one cannot pass e.g. Vector{Int} everywhere where Vector{Any} is expected. This function would fail if you could pass Vector{Int} to it:
f(x::Vector{Any}) = push!(x, "abc")
but it works for Vector{Any}.
If you do need to create a Vector{Pair{Any, Any}} containing pairs of a single type (do you really need it?), it’s possible much less awkwardly: Pair{Any, Any}[1 => 2].
Apparently, Tuple is abstract unless its parameters are concrete, so you cannot instantiate it. I am not sure if that makes it contravariant or not, but at least there is nothing preventing it to have subtypes.
Yes, or, alternatively:
[Pair{Any, Any}(1,2)]
This is a common idiom in Julia, btw, for any type, T, you can create a Vector{T} by writing T[...]
it might not be bad. sometimes this is what you need to prevent ridiculous amounts of compiler specialization. that said, 90% of the time, this is bad.