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…