Creating custom type of enumerations of symbols

Is it possible in julia to create a named-type that is an enumeration of symbol values?

for example a type named Mode that constists solely of symbols :a, :b, and c for example.

I tried constructing it with Val and Union but failed with type conversion errors.

Is this the sort of thing you are talking about?

julia> struct fun{a,b,c} end

julia> fun{:a,:b,:c}()
fun{:a,:b,:c}()

julia> typeof(ans)
fun{:a,:b,:c}

julia> f(::fun{a,b,c}) where {a,b,c} = (a,b,c)
f (generic function with 1 method)

julia> f(fun{:a,:b,:c}())
(:a, :b, :c)

@enum someenumtype A B C
A

No - I want a typed symbol that contains only specific symbols – not any symbol

A B and C aren’t symbols - I.e. :a

That is what my example in fact does. fun{:a,:b,:c}() is an instance of the fun{:a,:b,:c} type, which specifically has :a and :b and :c in its type, not any symbols.

julia> typeof(fun{:a,:b,:c}()) == typeof(fun{:x,:y,:z}())
false

This example shows that the types are indeed considered different if the symbols change.

Maybe:

struct ConstrainedSymbol{T}
	a::Symbol

	ConstrainedSymbol(a) = ConstrainedSymbol{Any}(a)
	ConstrainedSymbol{Any}(a) = new{Any}(a)
	ConstrainedSymbol{T}(a) where {T} = a in T ? new{T}(a) : throw("Symbol :$a is not in the supported set of symbols $T.")
end
Base.convert(::Type{Symbol}, s::ConstrainedSymbol) = s.a
Base.Symbol(s::ConstrainedSymbol) = s.a
julia> s = ConstrainedSymbol{(:a, :b)}(:a)
ConstrainedSymbol{(:a, :b)}(:a)

julia> s = ConstrainedSymbol{(:a, :b)}(:b)
ConstrainedSymbol{(:a, :b)}(:b)

julia> s = ConstrainedSymbol{(:a, :b)}(:c)
ERROR: "Symbol :c is not in the supported set of symbols (:a, :b)."
Stacktrace:
 [1] ConstrainedSymbol{(:a, :b)}(::Symbol) at .\REPL[1]:6
 [2] top-level scope at none:0

julia> s = ConstrainedSymbol(:c)
ConstrainedSymbol{Any}(:c)

julia> Symbol(s)
:c

Doesn’t that look exceeding overly complicated to me and a type with fixed symbols???

It seems you have a specific idea in mind. If you can post your attempt, perhaps people can guide you better along your line of thought.

It is not currently possible to define a subtype of Symbol which only includes some symbols, although the idea has been proposed as a more convenient alternative to the current enum implementation.

Thank you. I hope that they do. Without a type-safe symbol subtype the runtime errors are unavoidable.

Julia only checks types at runtime…

As pointed out above, Julia is not type safe in that way anyway. What is your use case? There is probably a better (more Julian) way to do what you’re trying to do. For example, instead of passing around a mode argument that is either :a, :b or :c and then have different functionality depending on that mode, it’d probably be cleaner to pass around functions directly, or structs that contain this functionality.

far enough - For example, assume a function circle(p1, p2, p3, … pn, mode::ModeType) where p1 - pn are parameters and ModeType is ideally just an enumeration of :fill or :outline

the user would call the function circle(p1, p2, …. pn, :fill)

all of the parameters are typed (i.e. p1::P1Type) ensuring that they are checked at runtime. The idea is to limit the mode parameter to the two symbols :fill and :outline - and not for example a misspelled symbol or any other symbol for that matter.

Does this really not work for your application?

julia> struct Mode{s} end

julia> function circle(args,::Mode{s}) where s
             (args,s ∈ [:fill,:outline] ? s : throw(error("wrong Mode, $s")))
         end
circle (generic function with 1 method)

julia> circle("stuff",Mode{:fill}())
("stuff", :fill)

julia> circle("stuff",Mode{:filler}())
ERROR: wrong Mode, filler
Stacktrace:
 [1] circle(::String, ::Mode{:filler}) at ./REPL[20]:1
 [2] top-level scope at none:0

the circle method specializes on the Mode type parameter, :fill. I believe, this should be able to do it.

that’s the best solution I’ve seen yet. I’d accept that as a readable solution.

Here’s another alternative:

julia> @enum Mode fill outline

julia> circle(radius::Float64, mode::Mode) = println("$radius - $mode");

julia> circle(3.14, outline)
3.14 - outline

julia> circle(3.14, dashed)
ERROR: UndefVarError: dashed not defined

julia> instances(Mode)
(fill::Mode = 0, outline::Mode = 1)

yes, but the limitation with this alternative is readability - it’s not instantly clear that ā€œoutlineā€ is a symbol and not a variable… that’ why I like the explicit :symbol in the construction.

Is this idea still active in discusion? I would like it very much

Hasn’t been implemented, no, nor designed really.