Interfaces & conditionals
Last updated on 2023-09-15 | Edit this page
Estimated time: 60 minutes
Overview
Questions
- “How to use conditionals?”
- “What is an interface?”
Objectives
Conditionals
Before starting to work in a new document, Melissa has to:
Activate her environment
Activating project at `~/projects/trebuchet`
Importing the package under its modified name
Defining the structures
JULIA
mutable struct Trebuchet <: AbstractVector{Float64}
counterweight::Float64
release_angle::Float64
end
struct Environment
wind::Float64
target_distance::Float64
end
Base.size(::Trebuchet) = tuple(2)
Now that Melissa knows that she has to add a method for
getindex(trebuchet::Trebuchet, i::Int)
she thinks about the implementation.
If the index is 1
she wants to get the
counterweight
field and if the index is 2
she
wants to get release_angle
and since these are the only two
fields she wants to return an error if anything else comes in. In Julia
the keywords to specify conditions are if
,
elseif
and else
, closed with an
end
. Thus she writes
JULIA
function Base.getindex(trebuchet::Trebuchet, i::Int)
if i === 1
return trebuchet.counterweight
elseif i === 2
return trebuchet.release_angle
else
error("Trebuchet only accepts indices 1 and 2, yours is $i")
end
end
And tries again:
OUTPUT
2-element Trebuchet:
500.0
0.7853981633974483
Notice, that the printing is different from our
trebuchet
in the former
episode.
Interfaces
Why is that? By subtyping Trebuchet
as
AbstractVector
we implicitly opted into a widespread
interface in the Julia language: AbstractArray
s.
An interface is a collection of methods that should be implemented by
all subtypes of the interface type in order for generic code to work.
For example, the Julia
manual lists all methods that a subtype of
AbstractArray
need to implement to adhere to the
AbstractArray
interface:
-
size(A)
returns a tuple containing the dimensions ofA
-
getindex(A, i::Int)
returns the value associated with indexi
-
setindex!(A, v, i::Int)
writes a new valuev
at the indexi
(optional)
Now, that Melissa implemented the mandatory methods for this
interface for the Trebuchet
type, it will work with every
function in Base
that accepts an
AbstractArray
. She tries a few things that now work without
her writing explicit code for it:
OUTPUT
2-element Vector{Float64}:
1000.0
1.5707963267948966
OUTPUT
250000.61685027508
OUTPUT
2×2 Matrix{Float64}:
250000.0 392.699
392.699 0.61685
That is, it now behaves like you would expect from an ordinary matrix.
Now she goes about implementing the missing optional method for
setindex!
of the AbstractArray
interface.
Implement setindex!
Write the missing method for
setindex(trebuchet::Trebuchet, v, i::Int)
similar to
Melissas getindex
function.
With the new Trebuchet
defined with a complete
AbstractArray
interface, Melissa tries her new method to
modify a counterweight by index:
OUTPUT
2
OUTPUT
2-element Trebuchet:
2.0
0.7853981633974483
Key Points
- “Interfaces are informal”
- “Interfaces facilitate code reuse”
- “Conditions use
if
,elseif
,else
andend
”