JULIA / CHAPTER 08

Parametric storage and flexible interfaces

Advanced

Keep concrete storage while accepting families of numeric inputs.

By the end of this chapter

  • Use type parameters in composite types
  • Explain invariant container parameters
  • Accept numeric vectors with a bounded element type

The idea

A parametric type records a relationship between its fields and a type parameter. Box{Int} and Box{Float64} are different concrete types, allowing each value’s representation to remain specific. A field declared with an unconstrained abstract type has a different storage contract from a field declared as T in a type parameterized by T. Prefer a representation that states the relationship your operations actually require.

Julia’s ordinary parametric types are invariant: Vector{Int} is not a subtype of Vector{Real}, even though Int is a subtype of Real. A method intended to accept a vector of any real element type can use AbstractVector{<:Real}. This describes a family of vector types without demanding that every caller construct a Vector{Real}. Keep accepted interfaces broad while keeping stored data appropriately concrete.

Julia example
struct Box{T}
    value::T
end
println(Box(3).value)
println(Box(3.0) isa Box{Float64})
println(Vector{Int} <: Vector{Real})
Result
3
true
false

Constructor inference produces concrete parameterizations. Subtyping of element types does not make the corresponding invariant vector types subtypes.

Try it yourself

Define a parametric reading type and a function accepting any AbstractVector whose elements are Real.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

A method should accept both Vector{Int} and Vector{Float64}. Which parameter annotation fits?