Suppose a battle simulator has archers, pikemen, and knights. Each needs its own data and behavior, but all belong to the broader category of warrior. In Julia, an abstract type names that shared category; concrete subtypes represent the objects you can create. section 7.3 section 7.3.1
Listing 7.5 Definition of types in battle simulator
abstract type Warrior end #1
mutable struct Archer <: Warrior #2
name::String
health::Int
arrows::Int
end
mutable struct Pikeman <: Warrior
name::String
health::Int
end
mutable struct Knight <: Warrior
name::String
health::Int
mounted::Bool #3
end
The `Warrior` declaration establishes the category. Each `mutable struct` uses `<:` to become a concrete subtype and supplies its own fields. section 7.3.1
Create a warrior, not the category
`Archer("Robin Hood", 34, 24)` creates an object. `Warrior()` fails because abstract types have no constructors for instances. An abstract type also cannot declare fields: the shared `name` and `health` fields in the warrior types are a convention, not a requirement Julia enforces. section 7.3.1
Only an abstract type can be a supertype in a Julia subtype declaration; a concrete type cannot be subclassed. Related types can instead share an abstract supertype while functions provide behavior. Multiple dispatch selects a method from the types of all its arguments. section 7.3.1 section 7.5
Listing 8.14 Allowing a rocket to be the payload of another rocket
abstract type Rocket end #1
struct Payload <: Rocket #2
mass::Float64
end
struct StagedRocket <: Rocket
nextstage::Rocket #3
tank::Tank
engine::Engine
end
function Rocket(payload::Rocket, tank::Tank,
engine::Engine) #4
StagedRocket(payload, tank, engine)
end
thrust(r::Payload) = 0.0 # no engines
thrust(r::StagedRocket) = thrust(r.engine)
A rocket uses the same idea for composition: `Payload` and `StagedRocket` are concrete subtypes of abstract `Rocket`, and a stage’s `nextstage::Rocket` can refer to either kind. Separate `thrust` methods handle their different behavior. section 8.7
Use an abstract type when related concrete objects must fit one role without having identical representations. Paired with multiple dispatch, it lets code work with that shared role while retaining type-specific behavior. section 8.0 section 8.9
