Time to create Union of types in Julia 1.9.0 vs Julia 1.8.5

  1. Version info
  2. Julia installation. Updated v1.8.5 to v1.9.0 as follows:
]add UpdateJulia
using UpdateJulia
update_julia()
  1. Issue
Julia Version 1.8.5
Commit 17cfb8e65e (2023-01-08 06:45 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 16 × 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, tigerlake)
  Threads: 4 on 16 virtual cores
Environment:
  JULIA_NUM_THREADS = 4
  JULIA_REVISE = auto

julia> types = [:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15];

julia> typesunion = Union{[Val{x} for x in types]...};

julia> struct obj{T<:typesunion}
         f::Int64
       end

julia> objtypesunion = Union{[obj{Val{x}} for x in types]...};

julia> @time objvec = objtypesunion[];
  0.006869 seconds (9.82 k allocations: 595.755 KiB, 94.53% compilation time)
Union{obj{Val{1}}, obj{Val{2}}, obj{Val{3}}, obj{Val{4}}, obj{Val{5}}, obj{Val{6}}, obj{Val{7}}, obj{Val{8}}, obj{Val{9}}, obj{Val{10}}, obj{Val{11}}, obj{Val{12}}, obj{Val{13}}, obj{Val{14}}, obj{Val{15}}}[]

The same code takes a lot of time to compile in Julia Version 1.9.0 as compared to Julia Version 1.8.5

julia> versioninfo()
Julia Version 1.9.0
Commit 8e63055292 (2023-05-07 11:25 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 16 × 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, tigerlake)
  Threads: 4 on 16 virtual cores
Environment:
  JULIA_NUM_THREADS = 4
  JULIA_REVISE = auto

julia> types = [:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15];

julia> typesunion = Union{[Val{x} for x in types]...};

julia> struct obj{T<:typesunion}
         a::Int64
       end

julia> objtypesunion = Union{[obj{Val{x}} for x in types]...};

julia> @time objvec = objtypesunion[]
 44.276539 seconds (48.91 M allocations: 2.915 GiB, 0.26% gc time, 100.00% compilation time)
Union{obj{Val{1}}, obj{Val{2}}, obj{Val{3}}, obj{Val{4}}, obj{Val{5}}, obj{Val{6}}, obj{Val{7}}, obj{Val{8}}, obj{Val{9}}, obj{Val{10}}, obj{Val{11}}, obj{Val{12}}, obj{Val{13}}, obj{Val{14}}, obj{Val{15}}}[]

The difference is not noticeable for the smaller number of types, but as the number of types increases, the compile time grows significantly.

Is this behavior expected from v1.9.0 Any suggestion to overcome this?

Other relevant links:

While you probably don’t want such lengthy Union types (Union-splitting stops at 3 types, I think), this is the kind of thing you should report as an issue.

As a side note, if you are frequently in need of vectors of union instances, this slack conversation about SumTypes.jl might be valuable: Slack

I would suggest checking out SumTypes.jl, Unityper.jl, and Expronicon.jl as libraries that might provide inspiration for your problem.

This is fixed in the upcoming 1.9.1 release already:

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.9.0 (2023-05-28)
 _/ |\__'_|_|_|\__'_|  |  release-1.9/a7348b7aa9d (fork: 342 commits, 199 days)
|__/                   |

julia> types = [:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15];

julia> typesunion = Union{[Val{x} for x in types]...};

julia> struct obj{T<:typesunion}
         a::Int64
       end

julia> objtypesunion = Union{[obj{Val{x}} for x in types]...};

julia> @time objvec = objtypesunion[]
  0.017479 seconds (5.71 k allocations: 381.589 KiB, 96.79% compilation time)
Union{obj{Val{1}}, obj{Val{2}}, obj{Val{3}}, obj{Val{4}}, obj{Val{5}}, obj{Val{6}}, obj{Val{7}}, obj{Val{8}}, obj{Val{9}}, obj{Val{10}}, obj{Val{11}}, obj{Val{12}}, obj{Val{13}}, obj{Val{14}}, obj{Val{15}}}[]
4 Likes

Thank you all for the solutions and suggestions.