Reading Functions, control flow, and macros
As you read this page, I suggest that you run the examples and experiment with them to familiarize yourself with the Julia REPL and to start getting a feel for the language.
Functions
Defining functions
There are 2 ways to define a new function:
Long form
function <name>(<arguments>)
<body>
end
Example:
function hello()
println("Hello")
end
Assignment form
<name>(<arguments>) = <body>
Example:
hello() = println("Hello")
The function hello defined with this compact syntax is exactly the same as the one we defined above with the longer syntax.
Calling functions
You call a function by running it followed by parentheses:
hello()
Returning the result
The value of the last expression is automatically returned, so return is unnecessary unless you want to return something else.
Look at these 5 functions:
function test1(x, y)
x + y
end
function test2(x, y)
return x + y
end
function test3(x, y)
x * y
end
function test4(x, y)
x * y
x + y
end
function test5(x, y)
return x * y
x + y
end
Now, try to guess the results of running:
test1(1, 2)
test2(1, 2)
test3(1, 2)
test4(1, 2)
test5(1, 2)
Then run these expressions to see whether you got it right.
Arguments
Our function hello did not accept any argument.
So running, for instance:
hello("Paul")
returns an error message.
To define a function which accepts arguments, we need to add them in the function definition as we did when we defined test1 to test5 .
So maybe we could do this?
function hello(name)
println("Hello name")
end
hello("Paul")
Oops. Not quite… This function works but does not give the result we wanted.
Here, we need to use string interpolation with the $ character:
function hello(name)
println("Hello $name")
end
hello("Paul")
We can also set default argument values: if no arguments are given, the function is evaluated with the defaults.
function hello(name = "you")
println("Hello $name")
end
hello("Paul")
hello()
Anonymous functions
Anonymous functions are functions which aren't given a name. You can create them this way in Julia:
function (<arguments>)
<body>
end
And in compact form:
<arguments> -> <body>
Example:
function (name)
println("Hello $name")
end
or
name -> println("Hello $name")
When would you want to use anonymous functions?
This is very useful for functional programming (when you apply a function—for instance map —to other functions to apply them in a vectorized manner which avoids repetitions).
Example:
map(name -> println("Hello $name"), ["Paul", "Lucie", "Sophie"]);
Pipes
The Julia pipe looks like this: |> and behaves as you would expect.
The following 2 expressions are equivalent:
println("Hello")
"Hello" |> println
Quick test:
sqrt(2) == 2 |> sqrt
Function composition
Done with the composition operator ∘ (in the REPL, type \circ then press <tab> ).
The following 2 expressions are equivalent:
<function2>(<function1>(<arguments>))
(<function2> ∘ <function1>)(<arguments>)
Example:
These are equivalent:
exp(+(-3, 1))
(exp ∘ +)(-3, 1)
function!()
! used after a function name indicates that the function modifies its arguments.
Example:
a = [-2, 3, -5]
sort(a)
a
sort!(a)
a
Broadcasting
To apply a function to each element of a collection rather than to the collection as a whole, Julia uses broadcasting.
a = [-3, 2, -5]
abs(a)
This doesn't work because the function abs only applies to single elements.
By broadcasting abs , you apply it to each element of a .
broadcast(abs, a)
The dot notation is equivalent:
abs.(a)
It can also be applied to the pipe, to unary and binary operators, etc.
a .|> abs
Try to understand the difference between the following 2 expressions:
abs.(a) == a .|> abs
abs.(a) .== a .|> abs
Methods
Julia uses multiple dispatch: functions can have several methods. When that is the case, the method applied depends on the types of all the arguments passed to the function (rather than only the first argument as is common in other languages).
methods(+)
let's you see that + has 166 methods!
Methods can be added to existing functions.
Try to understand the following example:
abssum(x::Int64, y::Int64) = abs(x + y)
abssum(x::Float64, y::Float64) = abs(x + y)
abssum(2, 4)
abssum(2.0, 4.0)
abssum(2, 4.0)
Control flow
Conditional statements
if
if <condition>
<do if true>
end
(If condition is false, do nothing).
Example:
function testsign(x)
if x >= 0
println("x is positive")
end
end
testsign(3)
testsign(0)
testsign(-2)
if else
if <condition>
<do if true>
else
<do if false>
end
Example:
function testsign(x)
if x >= 0
println("x is positive")
else
println("x is negative")
end
end
testsign(3)
testsign(0)
testsign(-2)
if elseif else
if <condition1>
<do if condition1 true>
elseif <condition2>
<do if condition1 false and condition2 true>
else
<do if condition1 and condition2 false>
end
Example:
function testsign(x)
if x > 0
println("x is positive")
elseif x == 0
println("x is zero")
else
println("x is negative")
end
end
testsign(3)
testsign(0)
testsign(-2)
Loops
while and for loops follow a syntax similar to that of functions:
for name = ["Paul", "Lucie", "Sophie"]
println("Hello $name")
end
for i = 1:3, j = 3:5
println(i + j)
end
Macros
Macros are a form of metaprogramming (the ability of a program to transform itself while running).
They resemble functions and just like functions, they accept as input a tuple of arguments. Unlike functions which return a value however, macros return an expression which is compiled directly (rather than at runtime).
Macro's names are preceded by @ (e.g. @time ).
Julia comes with many macros and you can create your own with:
macro <name>()
<body>
end