# Enum versus abstract typing

**URL:** <https://discourse.julialang.org/t/enum-versus-abstract-typing/47941>\
**Category:** Performance\
**Tags:** question, struct, enum\
**Created:** [October 7, 2020, 3:18pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941 "2020-10-07T15:18:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![davide-f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davide-f/32/33780_2.png) [@davide-f](https://discourse.julialang.org/u/davide-f)\
**Post date:** [October 7, 2020, 3:18pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/1 "2020-10-07T15:18:54Z")

</div>

Hi,

I am developing a code aiming at a good balance between speed, resources and generalizability.  
In my original code that was using only concrete assets, mainly, the code was relatively fast, about 68ms. Aiming to generalize it, I introduced more abstract typing and, however, the computational time increased to about 98ms; with increased allocation of resources (41.6MiB with respect to the previous 38.5).

In the original code I had 5 different types of enums, which in the new formulation have been replaced by 5 abstract types with subtypes.  
In the functions, I have to instantiate several vectors of the abstract types (which were enums previously) and I believe that the increased computational requirements are related to overhead in the initialization of such arrays.

For example, I developed the following test:

```julia
@enum xxx x = 1 y = 2

function prova2()

    a = Vector{xxx}(undef, 10000000)

    for i = 1:10000000
        a[i] = x
    end
end

abstract type aaa end
struct bbb <: aaa end
struct ccc <: aaa end

function prova3()

    a = Vector{aaa}(undef, 10000000)

    c = bbb()

    for i = 1:10000000
        a[i] = c
    end
end

@btime prova2()
@btime prova2()

@btime prova3()
@btime prova3()

```

The output on my computer is the following, which suggests that the generalizable implementation is about 50% more time consuming than the enum-version, most likely because enum are stored as Int32 while the struct version as Int64 (my machine is 64 bit)  
9.229 ms (2 allocations: 38.15 MiB)  
9.117 ms (2 allocations: 38.15 MiB)  
19.251 ms (2 allocations: 76.29 MiB)  
18.841 ms (2 allocations: 76.29 MiB)

Can you give me some suggestions on how to proceed to keep an efficient formulation while keeping a generalizable structure if possible?  
Should I use enums or an abstract type approach?

Thank you,  
Davide

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [October 7, 2020, 3:50pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/2 "2020-10-07T15:50:24Z")

</div>

If you can pass the type of variable you are willing to create, it is much faster:

```julia
function prova5(T)
    a = Vector{T}(undef, 10000000)
    c = T()
    for i = 1:10000000
        a[i] = c
    end
end

```

(this is 3 times faster and allocates much less than the enum option).

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [October 7, 2020, 4:06pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/3 "2020-10-07T16:06:38Z")

</div>

> [@davide-f](#):
>
> believe that the increased computational requirements are related to overhead in the initialization of such arrays.

By the way, I think that the increased computational time is associated to type instabilities, in both cases. (I was wrong, as shown below)

---

<div class="post-metadata">

**Author:** ![davide-f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davide-f/32/33780_2.png) [@davide-f](https://discourse.julialang.org/u/davide-f)\
**Post date:** [October 7, 2020, 4:14pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/4 "2020-10-07T16:14:52Z")

</div>

Thank you very much for your reply, but unlikely that does not solve my problem.  
In my enum implementation, the vector a would assume only a number of possible values (usually less than 3-4).

I propose another example in which I initialize the vector a to bbb() or ccc() whether the index i is odd (as an example).

```julia
abstract type aaa end
struct bbb <: aaa end
struct ccc <: aaa end

function prova6()
    a = Vector{aaa}(undef, 10000000)
    for i = 1:10000000
        a[i] = (mod(i, 2) == 1) ? bbb() : ccc()
    end
end

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [October 7, 2020, 4:29pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/5 "2020-10-07T16:29:38Z")

</div>

> [@davide-f](#):
>
> number of possible values

I am not familiar with `@enum` (I find it quite strange, to be truth). But do you want the positions of the `a` vector to contain `types` or something more specific, as numbers? I mean, the `enum` example and the other examples do not result in the same thing filling the vector `a`.

---

<div class="post-metadata">

**Author:** ![davide-f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davide-f/32/33780_2.png) [@davide-f](https://discourse.julialang.org/u/davide-f)\
**Post date:** [October 7, 2020, 4:52pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/6 "2020-10-07T16:52:55Z")

</div>

every element of a should represent a condition of the system, which can be represented either as a number, as an enum or as a type. At the bottom, there is the updated example using enum.

The use of enum seems quite similar to the C-equivalent version. I assume that behind enum there is a Int type or something like that.  
With julia, I would like to keep the speed of that implementation with eventually a better generalization capability as I have seen done by using abstraction. However, I see that performances drop.

in my formulation 30 ms are little, but I plan to significantly scale in dimensions and doubling the computational requirements could mean delay a lot.

```julia
@enum xxx x y

function prova7()
    a = Vector{xxx}(undef, 10000000)
    for i = 1:10000000
        a[i] = (mod(i, 2) == 1) ? x : y
    end
end

```

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [October 7, 2020, 4:57pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/7 "2020-10-07T16:57:43Z")

</div>

The right choice will depend on what exactly you want to do with your vector, but an `enum` seems like a good choice here given the information provided so far. In particular, you might find [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#The-dangers-of-abusing-multiple-dispatch-(aka,-more-on-types-with-values-as-parameters)) useful for some discussion about the trade-offs between using and abusing the type system.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [October 7, 2020, 5:25pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/8 "2020-10-07T17:25:57Z")

</div>

Take a look at these examples:

Using simply a `Int64` vector:

```julia
julia> function prova9()
           a = Vector{Int64}(undef, 10000000)
           for i = 1:10000000
               a[i] = (mod(i, 2) == 1) ? 1 : 2
           end
       end
prova9 (generic function with 1 method)

julia> @btime prova9()
  33.540 ms (2 allocations: 76.29 MiB)

```

Using your `@enum`:

```julia
julia> @enum xxx x = 1 y = 2

julia> function prova8()
           a = Vector{xxx}(undef, 10000000)
           for i = 1:10000000
               a[i] = (mod(i, 2) == 1) ? x : y
           end
       end
prova8 (generic function with 1 method)

julia> @btime prova8()
  18.336 ms (2 allocations: 38.15 MiB)

```

Enum is faster than a simple 64bit Integer vector for that. Actually it is equivalent to the function if it creates a 32bit integer array. The differences are therefore, not in the fact that the types are abstract, or in type instabilities (thus, what I said before was wrong).

Edit: Then, with `Int8` is even faster:

```julia
julia> function prova11()
           a = Vector{Int8}(undef, 10000000)
           for i = 1:10000000
               a[i] = (mod(i, 2) == 1) ? 1 : 2
           end
       end
prova11 (generic function with 1 method)

julia> @btime prova11()
  12.542 ms (2 allocations: 9.54 MiB)

```

which makes me wander if a custom implementation of a sort-of enum macro supported on a smaller integer would be the fastest option.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [October 7, 2020, 5:31pm UTC](https://discourse.julialang.org/t/enum-versus-abstract-typing/47941/9 "2020-10-07T17:31:22Z")

</div>

> [@lmiq](#):
>
> which makes me wander if a custom implementation of a sort-of enum macro supported on a smaller integer would be the fastest option.

`@enum` already supports this. You can add a `::Int8` to the `@enum` declaration to choose the underlying integer type:

```julia
julia> @enum xxx::Int8 x = 1 y = 2

julia> function prova8()
           a = Vector{xxx}(undef, 10000000)
           for i = 1:10000000
               a[i] = (mod(i, 2) == 1) ? x : y
           end
       end
prova8 (generic function with 1 method)

julia> @btime prova8()
  11.949 ms (2 allocations: 9.54 MiB)

```
