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