# What are lower bounds for types?

Iβm trying to understand what lower bounds are for types. I ran the following code which shows which subtypes (recursively) of number satisfies/rejects `Int <: T <: Real` in hope of gaining an understanding, however Iβm still lost.

``````Number
ββ Complex
ββ Real
ββ AbstractFloat
β  ββ BigFloat
β  ββ Float16
β  ββ Float32
β  ββ Float64
ββ AbstractIrrational
β  ββ Irrational
ββ FixedPoint
β  ββ Fixed
β  ββ Normed
ββ Integer
β  ββ Bool
β  ββ Signed
β  β  ββ BigInt
β  β  ββ Int128
β  β  ββ Int16
β  β  ββ Int32
β  β  ββ Int64
β  β  ββ Int8
β  ββ Unsigned
β     ββ UInt128
β     ββ UInt16
β     ββ UInt32
β     ββ UInt64
β     ββ UInt8
ββ Rational
ββ TestStat
``````
``````function stype(input)
arr = []
append!(arr,subtypes(input))
for x in arr
z = subtypes(x)
if (z != Type[])
append!(arr,z)
end
end
arr
end

for T in stype(Number)
@show T, Int <: T <: Real
end
``````
``````(T, Int <: T <: Real) = (Complex, false)
(T, Int <: T <: Real) = (Real, true)
(T, Int <: T <: Real) = (AbstractFloat, false)
(T, Int <: T <: Real) = (AbstractIrrational, false)
(T, Int <: T <: Real) = (FixedPointNumbers.FixedPoint, false)
(T, Int <: T <: Real) = (Integer, true)
(T, Int <: T <: Real) = (Rational, false)
(T, Int <: T <: Real) = (StatsBase.TestStat, false)
(T, Int <: T <: Real) = (BigFloat, false)
(T, Int <: T <: Real) = (Float16, false)
(T, Int <: T <: Real) = (Float32, false)
(T, Int <: T <: Real) = (Float64, false)
(T, Int <: T <: Real) = (Irrational, false)
(T, Int <: T <: Real) = (FixedPointNumbers.Fixed, false)
(T, Int <: T <: Real) = (FixedPointNumbers.Normed, false)
(T, Int <: T <: Real) = (Bool, false)
(T, Int <: T <: Real) = (Signed, true)
(T, Int <: T <: Real) = (Unsigned, false)
(T, Int <: T <: Real) = (BigInt, false)
(T, Int <: T <: Real) = (Int128, false)
(T, Int <: T <: Real) = (Int16, false)
(T, Int <: T <: Real) = (Int32, false)
(T, Int <: T <: Real) = (Int64, true)
(T, Int <: T <: Real) = (Int8, false)
(T, Int <: T <: Real) = (UInt128, false)
(T, Int <: T <: Real) = (UInt16, false)
(T, Int <: T <: Real) = (UInt32, false)
(T, Int <: T <: Real) = (UInt64, false)
(T, Int <: T <: Real) = (UInt8, false)
``````

I donβt understand why `Int <: T <: Real` is only true for Real, Integer, Signed and Int64

`Int` is just an alias for `Int64` on 64-bit platforms and `Int32` on 32-bit platforms. Since you seem to be running a 64-bit Julia version, you get exactly the same results for `Int` as you get for `Int64`. Does that answer your question?

4 Likes

Note `Integer`is probably what you meant.

3 Likes

Yes, `Integer` is what I meant, however I still donβt understand what the lower bound means.

``````Integer <: Int64 <: Real
``````
``````false
``````

Why is this false? What does the lower bound mean?

`Int64` (which is a concrete type) is a subtype of `Integer` (which is an abstract type). The reverse cannot be true.

4 Likes

This makes sense, thank you for the explanation, however when would you use an upper bound with a lower bound?

I never use them. Iβve seen them used, but cannot remember what for.

2 Likes

One example would be `Missing<:T<: Integer` which is a way of writing `T<: Union{Missing, Integer}`. In general, lower bounds arenβt widely used.

2 Likes

I donβt think thatβs true:

``````julia> Missing <: Missing <: Integer
false

julia> Missing <: Int <: Integer
false
``````
1 Like

Lower bounds are sometimes useful though, for example if you want to check whether a vector can store missing values:

``````julia> [1, missing, 3] isa Vector{>:Missing}
true

julia> [1, 2, 3] isa Vector{>:Missing}
false
``````
3 Likes