Different ways to declare Enum datatype in Julia-Lang
Solution 1
It's the only (easy) way, yes. The answer, as often (or, rather, always) in Julia, can be found by looking at the source code. This can be a bit scary at first, but you get used to it after a while!
Normally to create an object of a given type, you call the type's constructor. So you might expect to be able to do
Enum(...)
and create an object of type Enum
.
In this case, however, Enum
is an abstract type, so you cannot do that.
What does @enum
do, then? The example from the manual is
julia> @enum FRUIT apple=1 orange=2 kiwi=3
This actually creates a completely new type, called FRUIT
, that is a subtype of Enum
, and objects of that type called apple
, orange
and kiwi
, which are converted to those numbers by calling Int(apple)
etc. This is done by generating the Julia code to do so, inside the macro.
In principle, you could, yourself, do all the work that the macro does, but the macro is there to make our life easier!
Edit:
Since Julia 0.7, enums can be defined using @enum
macros as you mentionned but can also be used with a begin block:
julia> @enum Fruit begin
apple = 1
orange = 2
kiwi = 3
end
julia> Fruit
Enum Fruit:
apple = 1
orange = 2
kiwi = 3
julia> apple
apple::Fruit = 1
julia> orange
orange::Fruit = 2
julia> kiwi
kiwi::Fruit = 3
julia> Int(orange)
2
julia> string(orange)
"orange"
Enums can also be defined with this begin block without specifying values (in such a case values are starting with 0, not 1)
julia> @enum Fruit begin
apple
orange
kiwi
end
julia> Fruit
Enum Fruit:
apple = 0
orange = 1
kiwi = 2
Solution 2
...and then there is the type abusing way of doing it; that I stumbled upon while thinking of types as names for sets:
typealias Sunday Val{:Sunday}
typealias Monday Val{:Monday}
typealias Tuesday Val{:Tuesday}
typealias Wednesday Val{:Wednesday}
typealias Thursday Val{:Thursday}
typealias Friday Val{:Friday}
typealias Saturday Val{:Saturday}
typealias Days Union{
Type{Sunday},
Type{Monday},
Type{Tuesday},
Type{Wednesday},
Type{Thursday},
Type{Friday},
Type{Saturday}
}
function daynumber(d::Days)
if d == Sunday return 0
elseif d == Monday return 1
elseif d == Tuesday return 2
elseif d == Wednesday return 3
elseif d == Thursday return 4
elseif d == Friday return 5
elseif d == Wednesday return 6
end
-1
end
> daynumber(Friday)
5
> daynumber(:Friday)
> MethodError:`daynumber` has no method matching (::Symbol)
Note that the use of symbols is just a pretty bit of reflection, and is completely superfluous. You can put anything in there, and then recover it through type inspection
> x = Saturday.parameters[1]
:Saturday
> typeof(x)
Symbol
> eval(x) == Saturday
true
I am pretty sure the documentation explicitly recommends against this. Nevertheless @code_warntype does not particularly balk at this construct.
In set theoretic terms, each day alias is a singleton type, and thus a name for a set of exactly one element. The "Union" of "Type"s is then the set theoretic union of single element sets, forming the enumerated finite set type.
...and yet more type mangling ways of doing enumeration
abstract Fruits{N} <: Enum
immutable Apples <: Fruits{1} end
immutable Oranges <: Fruits{2} end
immutable Bananas <: Fruits{3} end
fruitsalad{N}(x::Fruits{N}) = N
> anorange = Oranges()
> fruitsalad(anorange)
2
Again @code_warntype does not seem to mind this at all. Finally one last technique that also provides a protected namespace for the enumeration
immutable Fruits{N} <: Enum
apples::Fruits
bananas::Fruits
oranges::Fruits
function Base.call(::Type{Fruits})
new{"anything"}(
Fruits{"crunchy"}(),
Fruits{"mushy"}(),
Fruits{"tangy"}()
)
end
function Base.call{N}(::Type{Fruits{N}})
if N != "crunchy" && N != "mushy" && N != "tangy"
error("Invalid enumeration parameter")
end
new{N}()
end
end
fruitsalad{N}(x::Fruits{N}) = N
> fruitsalad(Fruits().apples)
"crunchy"
In this last example to access the convenience property that gives an instance of a specific fruit we had to first instantiate the general fruits type. In the parlance of object oriented design Julia has no sense of static properties of types. The properties of types are only available once an explicit instance of that type has been constructed. The thought being that anything that is statically available about a particular type should be represented in some form of method overloading.
Solution 3
You can use SuperEnum
(author here) to do some cool stuff:
using Pkg
Pkg.add("https://github.com/kindlychung/SuperEnum.jl")
using SuperEnum
@se Vehical plane train car truck
julia> Vehical.VehicalEnum
Enum Main.Vehical.VehicalEnum:
plane = 0
train = 1
car = 2
truck = 3
julia> Vehical.car
car::VehicalEnum = 2
julia> @se Lang zh=>"中文"*"Chinese" en=>"English" ja=>"日本语"
Main.Lang
julia> string(Lang.zh)
"中文Chinese"
Related videos on Youtube
Reza Afzalan
My studies is in Mechanical Engineering. I'm instructor of a mechanical laboratory in the south of Iran. My latest project is to develop a process simulation environment for trainees of petrochemical plants mostly in Julia-Lang and Java. love to program, do numerical engineering calculations. interested in Julia language, javafx and ...
Updated on June 30, 2020Comments
-
Reza Afzalan almost 4 years
Is using
@enum
the only way to declare Julia Enum datatype? If so why?