Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does an 'at' @ sign mean in Julia?

Tags:

syntax

julia

For example, here:

ys = lift(frequency, phase) do fr, ph
    @. 0.3 * sin(fr * xs - ph)
end

from here.


I am failing to interpret it as a macro definition or call.

like image 466
Dims Avatar asked Dec 05 '20 18:12

Dims


People also ask

What is a symbol in Julia?

This is the essence of a symbol: a symbol is used to represent a variable in metaprogramming. Once you have symbols as a data type, of course, it becomes tempting to use them for other things, like as hash keys. But that's an incidental, opportunistic usage of a data type that has another primary purpose.

What does && mean in Julia?

Short-Circuit Evaluation The && and || operators in Julia correspond to logical “and” and “or” operations, respectively, and are typically used for this purpose.

What is double colon in Julia?

There are two different ways to use the double colon “::” in Julia. First, it can be used to check to make sure a variable is of the correct type. Secondly, it can be used to force a local variable to always (locally) be of a certain data type. The syntax for making sure the variable is the correct type is “x::type”.

What is metaprogramming in Julia?

Metaprogramming may be defined as the programming in which we write Julia code to process and modify Julia code. With the help of Julia metaprogramming tools, one can write Julia programming code that modifies other parts of the source code file. These tools can even control when the modified code runs.


Video Answer


2 Answers

TLDR: @ invokes a macro. https://docs.julialang.org/en/v1/manual/metaprogramming/

One of julia's best features in my opinion are it's macros. They allow you to easily write functions that manipulate source code. @. for example turns 0.3 * sin(fr * xs - ph) into 0.3 .* sin(fr .* xs - ph). Another common example is @time which roughly would translate the same expression to

t1=time()
0.3 * sin(fr * xs - ph)
println(time()-t1)

Note that neither of these are achievable by a function, since functions have their inputs evaluated before they run, while macros instead operate on the code itself.

like image 187
Oscar Smith Avatar answered Sep 27 '22 23:09

Oscar Smith


I think it is worth to add that it is easy to learn what @. does by invoking help. Press ? then write @. and hit enter to get:

help?> @.
  @. expr

  Convert every function call or operator in expr into a "dot call" (e.g.
  convert f(x) to f.(x)), and convert every assignment in expr to a "dot
  assignment" (e.g. convert += to .+=).

  If you want to avoid adding dots for selected function calls in expr, splice
  those function calls in with $. For example, @. sqrt(abs($sort(x))) is
  equivalent to sqrt.(abs.(sort(x))) (no dot for sort).

  (@. is equivalent to a call to @__dot__.)

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> x = 1.0:3.0; y = similar(x);
  
  julia> @. y = x + 3 * sin(x)
  3-element Array{Float64,1}:
   3.5244129544236893
   4.727892280477045
   3.4233600241796016

where you also learn that @. is just a shorthand for @__dot__.

And if you want to find its definition write e.g.:

julia> @which @. 1
@__dot__(__source__::LineNumberNode, __module__::Module, x) in Base.Broadcast at broadcast.jl:1241

to get the exact information on location of its implementation or write @edit @. 1 and it will get opened-up in your editor.

Above I have commented on how to learn what @. does and how it is implemented. If you want to learn what is the effect of @. (or any macro in general) you can use the @macroexpand macro. Therefore if you write e.g.:

julia> @macroexpand @. coalesce(sin(@view x[:, 1]), 0.0)
:(coalesce.(sin.(true && (view)(x, :, 1)), 0.0))

you can see how @. macro rewrites your original expression coalesce(sin(x), 0.0). Note that in this case the expressions are not evaluated - you only get an equivalent expression with all macros removed.

If you wanted to see only @. macro expanded (assuming - as in an example above it is the outermost macro) then use:

julia> @macroexpand1 @. coalesce(sin(@view x[:, 1]), 0.0)
:(coalesce.(sin.(#= REPL[11]:1 =# @view(x[:, 1])), 0.0))

As you can see @macroexpand1 is not recursive and only expanded the outermost macro and left @view macro untouched.

like image 39
Bogumił Kamiński Avatar answered Sep 28 '22 01:09

Bogumił Kamiński