Since Tuple{Int, String}
is the type of (123, "hello")
similarly Tuple{4, 5}
would be the type of a two-element tuple whose first value has type 4
and whose second value has type 5
. Of course, 4
and 5
are not the types of any values, so this is not actually the type of any value that can exist, but it's still a type, just an "uninhabited" one, i.e. one that doesn't have any instances. In general, Julia's type system is perfectly ok with types that are uninhabited.
We could prevent the object Tuple{4, 5}
from being constructed by insisting that the parameters of Tuple
must be types, but that just hasn't been done since there's no real harm in letting people construct this type object. Even if Julia did prevent you from constructing Tuple{4, 5}
by insisting that the arguments to Tuple
are types, this would still be valid syntax since, in general, the parameters to Tuple
are arbitrary expressions and 4
and 5
are perfectly valid expressions that just happen to evaluate to values that don't make much sense as parameters to Tuple
. Similarly, if I wrote Tuple{A, B}
that would be valid syntax even if we had A = 4
and B = 5
. So while we could prevent Tuple{4, 5}
from being constructed, this would always be valid syntax.
It should also be noted that even though the parameters to Tuple
don't make sense unless they are types, it is often useful for type parameters to be values, rather than types. For example, the type of [1 2; 3 4]
is Array{Int, 2}
where the second type parameter is an integer, indicating that the array is two-dimensional while the first parameter gives the element type of the array.