Style recommendation for enum as type

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")
1 Like