Types
Let's define two different shapes and create an instance of each of them. We will also define a function for each shape that calculates its area.
abstract type Shape end
struct Square <: Shape
side::Float64
end
struct Circle <: Shape
radius::Float64
end
area(s::Square) = s.side^2
area(c::Circle) = Float64(pi)*c.radius^2
square = Square(1.20)
circle = Circle(1.60)
println("The area of the square is: $(area(square))")
println("The area of the circle is: $(area(circle))")
Using the type of a value
The following shows how the type of a value can be used to pick out one sub-type from a collection.
get_squares(shapes) = filter(x -> x isa Square, shapes)
get_circles(shapes) = filter(x -> x isa Circle, shapes)
shapes = [square, circle]
get_squares(shapes)
#= Output
1-element Vector{Shape}:
Square(1.2)
=#
get_circles(shapes)
#= Output
1-element Vector{Shape}:
Circle(1.6)
=#
The abstract type indicates that there is a type hierarchy. It has two descendants or sub-types, and both of them are final, i.e. they do not themselves have sub-types. This is a feature of Julia.
In this first example I am using the default constructor, provided by Julia. This constructor simply takes the same number of arguments as there are fields and assigns the arguments, in order, to the fields.
There are two default constructors, one where the types all match and another which does conversions as needed.
Methods which apply to the types are written externally to the type definition. This is different from some object-oriented languages where types have functions or methods built into the type itself. This is part of Julia's multiple dispatch system: new methods can be added to a type to enable using it with different types of input.
The default constructor actually constructs the object in memory by calling the function new(). The Julia documentation gives the following example of two equivalent types:
struct T1
x::Int64
end
struct T2
x::Int64
T2(x) = new(x)
end
The constructor in T2 is called an inner constructor. There can also be outer constructors, defined outside of the struct to accomplish other methods of constructing the object. Inside these outer constructors however there will be a call to the inner constructor.