Making an iterator that splats keys and values quickly into kwargs

Nice!

julia> Base.@assume_effects :foldable function my_merge_names(an::Tuple{Vararg{Symbol}}, bn::Tuple{Vararg{Symbol}})
           @nospecialize an bn
           names = Symbol[an...]
           for n ∈ bn
               n ∈ an || push!(names, n)
           end
           (names...,)
       end
my_merge_names (generic function with 1 method)

julia> @btime my_merge_names((:a,:b,:c),(:d,:e,:f))
  1.000 ns (0 allocations: 0 bytes)
(:a, :b, :c, :d, :e, :f)

I need more practice figuring out how to translate a function like merge_names into a @generated form… the manual examples were basically just reimplementations of multiple dispatch.

Yes absolutely! This is just as performant, and doesn’t rely on black magic:

julia> function my_merge_names(an::Tuple{Vararg{Symbol}}, bn::Tuple{Vararg{Symbol}})
           @nospecialize an bn
           names = reduce(bn; init=an) do acc, k
               k ∈ an ? acc : (acc..., k)
           end
           (names...,)
       end
my_merge_names (generic function with 1 method)

julia> @btime my_merge_names((:a,:b,:c),(:d,:e,:f))
  1.000 ns (0 allocations: 0 bytes)
(:a, :b, :c, :d, :e, :f)

Trying a sugary generator approach…

julia> function my_merge_names(an::Tuple{Vararg{Symbol}}, bn::Tuple{Vararg{Symbol}})
           @nospecialize an bn
           (an..., (k for k ∈ bn if k ∉ an)...)
       end
my_merge_names (generic function with 1 method)

julia> @btime my_merge_names((:a,:b,:c),(:d,:e,:f))
  2.000 ns (0 allocations: 0 bytes)
(:a, :b, :c, :d, :e, :f)

Almost as good. I wonder where the extra 1ns is coming from…