DEV Community

Cover image for Learning Julia (6): expression and macro
Z. QIU
Z. QIU

Posted on

2 1

Learning Julia (6): expression and macro

Firstly I should cite one paragraph of presentation copied from Julia official doc:

"The strongest legacy of Lisp in the Julia language is its metaprogramming support. Like Lisp, Julia represents its own code as a data structure of the language itself. Since code is represented by objects that can be created and manipulated from within the language, it is possible for a program to transform and generate its own code. This allows sophisticated code generation without extra build steps, and also allows true Lisp-style macros operating at the level of abstract syntax trees(AST). In contrast, preprocessor "macro" systems, like that of C and C++, perform textual manipulation and substitution before any actual parsing or interpretation occurs. Because all data types and code in Julia are represented by Julia data structures, powerful reflection capabilities are available to explore the internals of a program and its types just like any other data."

As far as I understand today, code written in Julia would be firstly parsed by compiler as Expr, Symbol and QuoteNode that are structured as ASTs. Compiler then executes them in the same way how function eval() works. In this point of view, everything in Julia is Expression.

Below are my learning notes.

ex = :(a + b)           # define an expression as :(expression)
println("ex: ", typeof(ex))    # Expr

x = :(ab)               # see what it gives if there is no operator or functions in expression
println("x: ", typeof(x))    # Symbol

println(ex.head, ", ", ex.args)


println("dump(ex):  ") 
dump(ex) ##  equivalent to Meta.@dump :expr


# to define multiple-line expression, one should use: quote ... end
ex1 = quote
a + b
end
println("ex1: ", typeof(ex1))
Enter fullscreen mode Exit fullscreen mode

Execution output:

Alt Text

Expression can be parsed from a string (as our code in src files or typed in terminal are all strings):

ex = :(a + b)
expr_str = "a + b"
ex2 = Meta.parse(expr_str)


println("ex2: ", typeof(ex2))

println("ex == ex2?? answer is : ", ex == ex2)
println("dump(ex2):  ") 
dump(ex2) 

Enter fullscreen mode Exit fullscreen mode

Execution output:
Alt Text

It's also possible to define expression by using Expr()

ex = :(a + b)
ex3 = Expr(:call, :+, :a::Symbol, :b::Symbol)
println("ex == ex3?? answer is : ", ex == ex3)
println("dump(ex3):  ") 
dump(ex3) 

Enter fullscreen mode Exit fullscreen mode

Alt Text

We can use dollar symbol '$' to refer to content of a variable, same as in Linux terminal.


a = 1;
ex4 = :($a + b)   #  $a yields 1, however if a is not yet defined, there will be an error


println("dump(ex4): ")

dump(ex4) 
Enter fullscreen mode Exit fullscreen mode

Execution output:
Alt Text

With all the stuffs presented above, now it is easy to understand macro in Julia. I try to define a macro named sayhello with a "name" variable as input. Let's see how it works.

macro sayhello(name)
    return :( println("Hello, ", $name) )
end

@sayhello("jemaloQ")

#=
We can view the quoted return expression using the function macroexpand (important note: this is an extremely useful tool for debugging macros):
=#
ex = macroexpand(Main, :(@sayhello("jemaloQ")) )
println("type of ex: ", typeof(ex), ", ex: ", ex)
eval(ex)
Enter fullscreen mode Exit fullscreen mode

Execution output:
Alt Text

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up