# Kwargs allocating (?)

**URL:** https://discourse.julialang.org/t/kwargs-allocating/127326
**Category:** Performance
**Tags:** memory-allocation, kwargs
**Created:** [March 25, 2025, 12:08am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326 "2025-03-25T00:08:41Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)
#### Post date: [March 25, 2025, 12:08am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/1 "2025-03-25T00:08:41Z")

</div>

Hi there,

consider the following simple function:

```julia
    M = [1.0 2.0;
        3.0 4.0]
    n = size(M,1)
    I_n = Matrix{Float64}(I, n, n)
    A_temp = zeros(n, n)
    diff_temp = zeros(n, n)
    function inf_norm_diff_type_stable_no_allocs2(args, M, I_n, A_temp, diff)
        # Collect the scalar inputs into a vector
        for i in eachindex(A_temp)
            A_temp[i] = args[i]
        end
        # Compute the difference A*M - I
        mul!(diff, A_temp, M)
        @. diff -= I_n
        return mapreduce(x -> x^2, +, diff)
    end

```

As expected this has no allocations

```julia
@btime inf_norm_diff_type_stable_no_allocs2($(rand(4)), $(M), $(I_n), $(A_temp), $(diff_temp))
  21.314 ns (0 allocations: 0 bytes)

```

However, consider the following modification of passing some of the arguments as `kwargs`:

```julia
    function inf_norm_diff_type_stable(args...; M, I_n, A_temp, diff)
        # Collect the scalar inputs into a vector
        for i in eachindex(A_temp)
            A_temp[i] = args[i]
        end
        # Compute the difference A*M - I
        mul!(diff, A_temp, M)
        @. diff -= I_n
        return mapreduce(x -> x^2, +, diff)
    end
julia> @btime inf_norm_diff_type_stable($(rand()), $(rand()), $(rand()), $(rand()); M = $(M), I_n = $(I_n), A_temp = $(A_temp), diff = $(diff_temp))
  36.374 ns (5 allocations: 80 bytes)

```

It does allocate!  
Interestingly, the issue seems to come from the `@.` line since:

```julia
    function inf_norm_diff_type_stable2(args...; M, I_n, A_temp, diff)
        # Collect the scalar inputs into a vector
        for i in eachindex(A_temp)
            A_temp[i] = args[i]
        end
        # Compute the difference A*M - I
        mul!(diff, A_temp, M)
        #@. diff -= I_n
        return mapreduce(x -> x^2, +, diff)
    end
julia> @btime inf_norm_diff_type_stable2($(rand()), $(rand()), $(rand()), $(rand()); M = $(M), I_n = $(I_n), A_temp = $(A_temp), diff = $(diff_temp))
  12.929 ns (0 allocations: 0 bytes)

```

Comparing `@code_warntype` and `@code_lowered` outputs of each is not helping me to identify the issue. Can someone let me know what I’m missing here?

Thanks in advance!

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [March 25, 2025, 12:54am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/2 "2025-03-25T00:54:46Z")

</div>

You made another significant change other than keyword arguments, you changed `args` to `args...`, and that’s the real cause of your allocations:

```julia
julia> function inf_norm_diff_type_stable3(args; M, I_n, A_temp, diff)
           # Collect the scalar inputs into a vector
           for i in eachindex(A_temp)
               A_temp[i] = args[i]
           end
           # Compute the difference A*M - I
           mul!(diff, A_temp, M)
           @. diff -= I_n
           return mapreduce(x -> x^2, +, diff)
       end
inf_norm_diff_type_stable3 (generic function with 1 method)

julia> @btime inf_norm_diff_type_stable3($(rand(4)); M = $(M), I_n = $(I_n), A_temp = $(A_temp), diff = $(diff_temp))
  32.460 ns (0 allocations: 0 bytes)
14.74157464731775

```

Contrary to what `@code_warntype` and related methods assume (and should warn users about), the compiler does not automatically specialize (at least, not fully) a method over `Function`/`Type`/`Vararg` inputs, so `args[i]` is type-unstable. If you want to opt into specialization, you need method parameters, see the Performance Tips for examples.

As for why commenting out `@. diff -= I_n` resulted in zero allocations, I don’t know, I don’t think the for-loop becomes dead code.

---

<div class="post-metadata">

### Author: ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)
#### Post date: [March 25, 2025, 1:07am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/3 "2025-03-25T01:07:09Z")

</div>

Thanks! Useful to know that iterating over `Vararg` inputs is type-unstable. Its hard to tell from `@code_warntype` so thanks for letting me know.

I am still puzzled by why the type-instability seems to go aways when commenting out `@. diff -= I_n`

If anyone know why, it would be great.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [March 25, 2025, 1:27am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/4 "2025-03-25T01:27:28Z")

</div>

Quickly factchecking myself, `args[i]` might be type-stable, or at least potentially. It’s harder to see in the underlying method that moves all the keyword arguments to the front, but it does specialize over all these keyword arguments’ types, including `diff` and `I_n`, and the types of `args` elements, just not the number of them:

```julia
julia> methods(var"#inf_norm_diff_type_stable2#4")[1].specializations
MethodInstance for var"#inf_norm_diff_type_stable2#4"(::Matrix{Float64}, ::Matrix{Float64}, ::Matrix{Float64}, ::Matrix{Float64}, ::typeof(inf_norm_diff_type_stable2), ::Float64, ::Vararg{Float64})

```

Unfortunately `@code_llvm` also assumes full specialization, so that doesn’t help spot where and why there are allocations.

---

<div class="post-metadata">

### Author: ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)
#### Post date: [March 25, 2025, 1:31am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/5 "2025-03-25T01:31:18Z")

</div>

Thanks for factchecking yourself and taking the time to go deeper. Hopefully we get at why these allocations are happening in the end.

---

<div class="post-metadata">

### Author: ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)
#### Post date: [March 26, 2025, 3:58pm UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/6 "2025-03-26T15:58:42Z")

</div>

@Benny in the case where no one comes up with a reason, is it valid to open an issue about fusing not working when using Kwargs? It seems like specialization is not the issue.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [March 27, 2025, 4:21am UTC](https://discourse.julialang.org/t/kwargs-allocating/127326/7 "2025-03-27T04:21:00Z")

</div>

I’d agree
