What is the dollar-sign prefix in function arguments used for in Julia?

Viewed 1218

When I searched about the '$' prefix in Julia, all I could find is that it is for string or expression interpolation. For example, here https://docs.julialang.org/en/v1/base/punctuation/. However, I have seen people' code like

add_broadcast!($y_d, $x_d)

as in this tutorial https://cuda.juliagpu.org/stable/tutorials/introduction/. Here the "$" sign cannot be interpolation, can it? There is nothing about such usage in the functions doc either https://docs.julialang.org/en/v1/manual/functions/. So I am very confused. Any idea is appreciated. Thanks!

1 Answers

The $ sign expressions like you have shown is non-standard Julia code and it typically appears only in expressions passed to macros. This is exactly the case in your example, where the full line is:

@btime add_broadcast!($y_d, $x_d)

which uses @btime macro from BenchmarkTools.jl. And if you go to Quick Start section there you can read:

If the expression you want to benchmark depends on external variables, you should use $ to "interpolate" them into the benchmark expression to avoid the problems of benchmarking with globals. Essentially, any interpolated variable $x or expression $(...) is "pre-computed" before benchmarking begins:

So in short with @btime you use $ to "interpolate" them into the benchmarked expression in order to get a correct benchmark results.

The $ sign is used with macros to interpolate also in other packages, e.g. DataFrameMacros.jl.


EDIT:

An example how not using $ affects execution time when referencing to non-const global variable:

julia> using BenchmarkTools

julia> x = 1
1

julia> @btime (y = 0; for _ in 1:10^6 y += x end; y) # slow and a lot of allocations
  22.102 ms (999489 allocations: 15.25 MiB)
1000000

julia> @btime (y = 0; for _ in 1:10^6 y += $x end; y) # loop is optimized out
  5.600 ns (0 allocations: 0 bytes)
1000000

julia> const z = 1
1

julia> @btime (y = 0; for _ in 1:10^6 y += z end; y) # loop is optimized out
  5.000 ns (0 allocations: 0 bytes)

You can think of it as follows. In the above example not using $ is as-if you have created and run the following function:

function temp1()
    y = 0
    for _ in 1:10^6
        y += x
    end
    y
end

And you get:

julia> @btime temp1()
  22.106 ms (999489 allocations: 15.25 MiB)
1000000

While using $ is as if defined x inside the body of the function like this:

function temp2()
    x = 1
    y = 0
    for _ in 1:10^6
        y += x
    end
    y
end

and now you have:

julia> @btime temp2()
  5.000 ns (0 allocations: 0 bytes)
1000000
Related