# Why does \`@time\` macro allocate in a \`let\` block, a local scope?

**URL:** <https://discourse.julialang.org/t/why-does-time-macro-allocate-in-a-let-block-a-local-scope/97266>\
**Category:** General Usage\
**Tags:** benchmark, time\
**Created:** [April 9, 2023, 2:15am UTC](https://discourse.julialang.org/t/why-does-time-macro-allocate-in-a-let-block-a-local-scope/97266 "2023-04-09T02:15:44Z")\
**Posts on this page:** 1\
**Page:** 1

<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:** [April 9, 2023, 2:15am UTC](https://discourse.julialang.org/t/why-does-time-macro-allocate-in-a-let-block-a-local-scope/97266/1 "2023-04-09T02:15:45Z")

</div>

The Performance Tips has [a section](https://docs.julialang.org/en/v1/manual/performance-tips/#Measure-performance-with-%5B@time%5D(@ref)-and-pay-attention-to-memory-allocation) on using `@time` to identify excessive allocations and reduce usage of untyped global variables. When allocations were technically eliminated, it points out that “the 1 allocation [of 16 bytes] seen is from running the `@time` macro itself in global scope” and demonstrates that running `@time` in a function call removes that lingering allocation.

But what explains that allocation being present when running `@time` in a `let` block that doesn’t use untyped global variables? Here’s an adaptation of that section demonstrating this (v1.8.5):

```julia
x = rand(1000);

function sum_arg(y)
  s = zero(eltype(y))
  for i in y s += i end
  return s
end
time_sum(y) = @time sum_arg(y)

@time sum_arg(x) # 9.62k alloc, 520.796 KiB
@time sum_arg(x) # 1 alloc, 16 bytes

let y = x
@time sum_arg(y) # 1 alloc, 16 bytes????
end

time_sum(x) # 0 alloc

```

An annotation `@time sum_arg(x::Vector{Float64})`, `let y::Vector{Float64}=x`, or `let y=x::Vector{Float64}` would remove the 1 allocation. It makes sense for the globally scoped call, but I expected the `let` block to infer `y`’s type already because `let` blocks generally seem to do some type inference optimizations, though not as well as `function`s.
