Grouping multiple varargs by type


#1

I was wondering if this is possible with the base julia features, something along the lines of function foo(f_args:T... , i_args::R...) where {T<: AbstractFloat, R<: Int} .

I understand that this is not necessary since there is the option to just run through the varargs and group them manually depending on their type, but it seems like a useful feature? This can probably be automated using a macro as well.


#2

Currently there can be only one Vararg and it has to be last. You can, however, write this as

foo(f_args::NTuple{NT,T}, i_args::NTuple{NI,Int}) where {NT,NI,T<:AbstractFloat}

but the user has to group them manually.


#3

Perhaps a generated function can sort them out and call the underlying grouped form @tim.holy suggested?


#4

It doesn’t have to be a generated function, you can use “lispy tuple programming”:

groupargs(x::T, y...) where T = ((x, keepT(T, y...)...), groupargs(dropT(T, y...)...)...)
groupargs() = ()
# Keep leading arguments as long as they are of type T
keepT(::Type{T}, x::T, y...) where T = (x, keepT(T, y...)...)
keepT(::Type{T}, y...) where T = ()
# Drop leading arguments if they are of type T
dropT(::Type{T}, x::T, y...) where T = (dropT(T, y...)...)
dropT(::Type{T}, y...) where T = y

julia> groupargs(1,2,3,1.0,2.0)
((1, 2, 3), (1.0, 2.0))

Sometimes generated functions are the only way forward, but lispy programming is often faster to compile (at least for reasonably short tuples) and is friendlier for static compilation (because the compiler can reason in advance about what the code does, unlike with generated functions where the returned Expr could be arbitrary). With suitable @inline annotations there shouldn’t be a performance hit.