Parametric types and methods

An array can take elements of different types. Therefore, we can have, for example, arrays of the following types: Array{Int64,1}, Array{Int8,1}, Array{Float64,1}, or Array{String, 1}, and so on. That is why an Array is a parametric type; its elements can be of any arbitrary type T, written as Array{T, 1}.

In general, types can take type parameters, so that type declarations actually introduce a whole family of new types. Returning to the Point example of the previous section, we can generalize it to the following:

# see the code in Chapter 6parametric.jl
mutable struct Point{T}
x::T
y::T
end

This is conceptually similar to the generic types in Java or templates in C++.

This abstract type creates a whole family of new possible concrete types (but they are only compiled as needed at runtime), such as Point{Int64}, Point{Float64}, and Point{String}.

These are all subtypes of Point: Point{String} <: Point returns true. However, this is not the case when comparing different Point types, whose parameter types are subtypes of one another: Point{Float64} <: Point{Real} returns false.

To construct objects, you can indicate the type T in the constructor, as in p = Point{Int64}(2, 5), but this can be shortened to p = Point(2, 5). Or let's consider another example: p = Point("London", "Great-Britain").

If you want to restrict the parameter type T to only the subtypes of Real, this can be written as follows:

mutable struct Point{T <: Real}
x::T
y::T
end

Now, the statement p = Point("London", "Great-Britain") results in an ERROR: MethodError: `Point{T<:Real}` has no method matching Point{T<:Real}(::String, :String) error message, because String is not a subtype of Real.

In much the same way, methods can also optionally have type parameters immediately after their name and before the tuple of arguments. For example, to constrain two arguments to be of the same type T, run the following command:

add(x::T, y::T) where T = x + y

Now, add(2, 3) returns 5 and add(2, 3.0) returns an ERROR: MethodError: `add` has no method matching add(::Int64, ::Float64) error message.

Here, we restrict T to be a subtype of Number in add as follows:

add(x::T, y::T) where T <: Number = x + y

As another example, here is how to check whether a vecfloat function only takes a vector of floating point numbers as the input. Simply define it with a type parameter T as follows:

function vecfloat(x::Vector{T}) where T <: AbstractFloat 
# code
end

Inner constructors can also take type parameters in their definition.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.254.44