juliadollar-sign

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


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!


Solution

  • 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