Basic question about type alias

For the first time, I defined my own type alias and was surprised by the following behaviour:

const VecScalar{T<:Number} = Tuple{Vector{T}, T}

x::VecScalar{Float64} = ([1.0, 2.0], 3.0)  # works as expected.

x::VecScalar{Float64} = ([1, 2], 3.0) # was expecting to fail, but it works. Why?

I am surprised because I expected that all the elements in this alias type must be of the same T. Evidently, I am ignoring something very basic, so please bear with my ignorance.

How do I enforce that the elements in the vector are of the same type as the second element in tuple?

So you want to avoid type conversion from Int to Float64? You mean you want to type-annotate the right hand side of the equation instead of the left hand side?

julia> ([1, 2], 3.0)::VecScalar
ERROR: TypeError: in typeassert, expected Tuple{Vector{T}, T} where T<:Number, got a value of type Tuple{Vector{Int64}, Float64}
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1
1 Like

Sorry, I wasn’t clear enough. I thought my alias type definition would make sure that

x::VecScalar{Float64} = ([1, 2], 3.0)

fails, because the first element of the tuple, the vector, has elements of type Int while the second element of the tuple has type Float64. Clearly, my alias type does not enforce this.

How dow I have to modify my alias type in order to enforce this?

Check the output. The final result satisfies your type restriction because Int is converted to Float64. Your variable x will have the type you specified, with a single T.

I don’t think there is a way to avoid type conversion from the RHS → LHS.

3 Likes

@juliohm already gave the correct answer, but I wanted to clarify two things for other readers and add links to the docs:

  • as was mentioned, the :: syntax does two different things, depending on which side of an assignment it is used; in the OP it is used on the left-hand side, which behaves essentially like a convert call; but if used on on an expression (so on the right-hand side) it will assert the type of the given expression and error if it doesn’t match (see also Types · The Julia Language )
  • what looks additionally confusing about the second example from the op is that an assignment always returns the expression on the right-hand side (i.e. before any conversion happens), so it looks like this when run in a REPL
x::VecScalar{Float64} = ([1, 2], 3.0)
([1, 2], 3.0)

but as was pointed out, the value of x will be ([1.0, 2.0], 3.0) (see here)

Just thought that extra bit of info might be useful to someon.

5 Likes

Spot on:

This is indeed what really confused me. Your comments really help clarify the situation.

1 Like