Keyword arguments in a clojure


#1

How do you propogate keyword arguments?

function f(x,y; z = 1)
return x + y + z
end

Now i want a function g which fixes y at y = 1, but still allows the user to vary the keyword argument z.

g(x; (keyword arguments here)) = f(x, 1; (keyword arguments here))

I would like g to inherit the default keyword arguments of f as well, such that you can use g exactly like f but with the middle argument, y fixed at 1.


#2

You can use the ... splat notation for this. To catch keyword arguments, just put the splatted argument after the ;

julia> g(x; kw...) = f(x, 1; kw...)
g (generic function with 1 method)

julia> g(2)
4

julia> g(2, z=3)
6


#3

Thanks, this works, but i am worried about performance. It looks like the splatting version is significantly slower.

function f(x, y; z = 1)
    x + y + z 
end

g(x; kwargs...) = f(x, 1; kwargs...)

function gTest(x, N)
    for i in 1:N
        g(1)
    end
end

function fTest(x, N)
    for i in 1:N
        f(1, 1)
    end
end

N = 1_000_000 

@time fTest(1, N)
@time gTest(1, N)


 > 0.005996 seconds (1.30 k allocations: 72.532 KiB)
 > 0.102350 seconds (1.00 M allocations: 76.513 MiB, 11.23% gc time)
    

edit: this is on 0.6.2


#4

Keyword argument performance is hugely improved with Julia master (v0.7-), so this should improve in the future. Also, note that your benchmark is somewhat uninformative because your functions gTest and fTest reference a non-const global variable N. It’s much easier to just use BenchmarkTools.jl to get reliable results:

On Julia v0.6.2:

julia> using BenchmarkTools

julia> @btime f(1, 1)
  1.597 ns (0 allocations: 0 bytes)
3

julia> @btime g(1)
  20.791 ns (1 allocation: 80 bytes)
3

Interestingly, on Julia master, it looks like both functions are completely optimized out:

Julia 0.7.0-DEV.5049:

julia> @btime f(1, 1)
  0.017 ns (0 allocations: 0 bytes)
3

julia> @btime g(1)
  0.017 ns (0 allocations: 0 bytes)
3

#5

Great, thank you for the replies!

Yeah, I wonder if in 0.6.2, g was copying over the keyword argument in f or something. And now the compiler knows it doesn’t have to do that.

I really need to install 0.7.0 for these benchmarks.


#6

In v0.6 and earlier, keyword arguments were handled as dictionaries, so they inevitably allocated some memory and couldn’t be fully optimized out by the compiler. In v0.7 and above, they’re handled as named tuples (a new built-in type) which can be better optimized by the compiler. Here’s one of the relevant PRs: https://github.com/JuliaLang/julia/pull/24795