Hi I totally recognize this question. I often find myself wondering if I should write an @enum or just make an abstract type with “values” as subtypes. When I want to dispatch on the values, then I will now always write the abstract type myself. And almost always do I find a reason to dispatch on the values. And I often create a mapping to an Integer. But it just feels like an enum.
Here’s some example code that I often find myself writing. I would love some advice/discussion on the best pattern for these things. Maybe it’s just fine. I was totally influenced by this blog about julia dispatching enum versus type.
using Test
module MyModule
using InteractiveUtils
export SomeType, First, Second, Third, Fourth
abstract type SomeType end
struct First <: SomeType end
struct Second <: SomeType end
struct Third <: SomeType end
struct Fourth <: SomeType end
Base.Integer(T::Type{<:SomeType}) = Integer(T())
Base.Integer(::First) = 1
Base.Integer(::Second) = 2
Base.Integer(::Third) = 3
Base.Integer(::Fourth) = 4
const SomeTypeSet = subtypes(SomeType)
function Base.convert(::Type{SomeType}, x::Integer)
for e in SomeTypeSet
x==Integer(e) && return e()
end
end
SomeType(x::Integer) = convert(SomeType, x)
Base.isless(x1::SomeType, x2::SomeType) = isless(Integer(x1), Integer(x2))
Base.isless(x1::Type{<:SomeType}, x2::Type{<:SomeType}) = isless(x1(), x2())
end
@testset "this feels like an enum" begin
using .MyModule
# You want to use either the type or the instance of the type as values
# but you can also use both this way:
@test First() < Fourth()
@test First < Fourth
@test SomeType(3) == Third()
end
If you use these things as a property of a type, then it’s a trait right?
get_trait(::Type{MyFirstType}) = First()
If you use these things as a property of an instance of a type, then it feels like an enum. Like the color of a banana:
abstract type Color end
struct Yellow <: Color end
struct Brown <: Color end
mutable struct Banana
color::Color
weight::AbstractFloat
end
eat(b::Banana) = eat(b.color, b)
eat(::Yellow, ::Banana) = println("yummy")
eat(::Brown, ::Banana) = println("eeww")