Julia syntax

Let's start with a quick overview of the basic syntax, emphasising differences with Python.

Variables

Variables in Julia are created as in Python, with a simple assignment operation; variable names can be arbitrary unicode characters. Many may be entered in LaTeX notation, using tab substitution: type \alpha<TAB>. There is also tab completion on partial names: \alp<TAB>


In [2]:
x = 3


Out[2]:
3

In [3]:
# variables can be any unicode characters
α = 3; β = 10


Out[3]:
10

In [4]:
# aside: last result is stored in 'ans' in the REPL/IJulia
typeof(ans)


Out[4]:
Int64

In [5]:
# There are some convenient built-ins
2*π


Out[5]:
6.283185307179586

A few primitive datatypes


In [6]:
x = 3
typeof(x)


Out[6]:
Int64

In [7]:
y = 3.0
typeof(y)


Out[7]:
Float64

In [8]:
z = 1. + 3.im
typeof(z)


Out[8]:
Complex{Float64} (constructor with 1 method)

In [9]:
w = true
typeof(w)


Out[9]:
Bool

Select Mathematical operators


In [10]:
# division is like in Python 3: Int/Int => Float
5 / 2


Out[10]:
2.5

In [11]:
# integer division
div(5, 2)


Out[11]:
2

In [12]:
# power is ^ not **
5^2


Out[12]:
25

In [13]:
# use ! instead of not
!true


Out[13]:
false

In [14]:
# Comparisons can be chained (as in python)
1 != 2 < 3 < 4


Out[14]:
true

Strings and printing


In [17]:
# Strings are double-quoted
s = "This is a string"

# characters are single-quoted
c = 'a'


Out[17]:
'a'

In [18]:
# String interpolation with $ (can contain any Julia expression!)
"2 + 2 = $(2 + 2)"


Out[18]:
"2 + 2 = 4"

In [19]:
name = "julia"
"Hi, I'm $name"


Out[19]:
"Hi, I'm julia"

In [20]:
# more complex expressions are wrapped in parentheses
μ = 3
"The sine of $μ is $(sin(μ))"


Out[20]:
"The sine of 3 is 0.1411200080598672"

In [24]:
# println() adds a newline, print() ommits it
println("x = ", x)
print("x = $x")


x = 3
x = 3

In [25]:
# formatted printing
@printf "%d is less than %4.2f" 4.5 5.3


5 is less than 5.30

Functions


In [26]:
# standard syntax
function f(x)
    return 2x^2 + 3x + 1
end

f(3)


Out[26]:
28

In [27]:
# one-line syntax
f(x) = 2x^2 + 3x + 1
g(x) = f(x) - (2x+1) * (x+1)

g(3.5)


Out[27]:
0.0

Arrays: an "equivalent" of Python lists and NumPy arrays

In Python, lists hold heterogeneous types and a numpy array holds homogeneous types.

In Julia, these can be unified thanks to the type system.


In [28]:
a = [3, 4, 5]


Out[28]:
3-element Array{Int64,1}:
 3
 4
 5

In [29]:
typeof(a)


Out[29]:
Array{Int64,1}

In Julia these objects are called Arrays. The curly braces indicate type parameters of the Array type. The first is the type of element contained in the Array (all must be of the same type) and the second the number of dimensions.

In NumPy this information is stored in attributes of the object rather than the type itself. Python:

>>> a = np.array([3, 4, 5])
>>> a.dtype
dtype('int64')
>>> a.ndim
1

In [30]:
# Array of heterogeneous types (similar to Python list or numpy "object" array)
[3., "hello", 2]


Out[30]:
3-element Array{Any,1}:
 3.0     
  "hello"
 2       

In [31]:
# [] tries to infer a type, {} is an Any Array
{3, 4, 5}


Out[31]:
3-element Array{Any,1}:
 3
 4
 5

In [32]:
# There's type promotion to a common type
[3., 4, 5]


Out[32]:
3-element Array{Float64,1}:
 3.0
 4.0
 5.0

In [33]:
# Explicitly set the type
Int64[3., 4, 5]


Out[33]:
3-element Array{Int64,1}:
 3
 4
 5

Multi-dimensional arrays

Square brackets with commas gives a one-dimensional vector. This is printed in a way that treats it as if it were a column vector (although there is in fact no difference between a one-dimensional row vector and column vector).


In [34]:
[1, 2, 3]


Out[34]:
3-element Array{Int64,1}:
 1
 2
 3

To create explicit matrices, Matlab-style notation is used. If we omit the commas, something different happens: we now obtain a two-dimensional Array, i.e. a matrix, of size $1 \times n$. [Recall that in the standard notation for matrices, an $m \times n$ matrix has $m$ rows and $n$ columns.]


In [35]:
[1 2 3]


Out[35]:
1x3 Array{Int64,2}:
 1  2  3

In [36]:
# Semicolon can be used to write 2-d array literals
a = [1 2 3;
     4 5 6]


Out[36]:
2x3 Array{Int64,2}:
 1  2  3
 4  5  6

In [39]:
# Python-like syntax gives you something different!
a = [[1, 2, 3], [4, 5, 6]]


Out[39]:
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6

In [40]:
# Many numpy-like functions are available for creating arrays:
ones((2, 3))
zeros((2, 3))
trues((2, 3))
falses((2, 3))
Array(Float64, (2, 3))  # uninitialized
# ... and many more.


Out[40]:
2x3 Array{Float64,2}:
 3.5805e-316  3.5805e-316  5.89504e-316
 3.5805e-316  3.5805e-316  3.5805e-316 

Array Indexing

It's different than NumPy!


In [43]:
# The first item is at index 1, not 0
l = [3, 4, 5]
l[1]


Out[43]:
3

The syntax for ranges is similar to that for Python:


In [44]:
# ranges are inclusive at both ends
l[1:2]


Out[44]:
2-element Array{Int64,1}:
 3
 4

In [45]:
# end must be explicit
l[2:end]


Out[45]:
2-element Array{Int64,1}:
 4
 5

In [46]:
# indexing from the end
l[1:end-1]


Out[46]:
2-element Array{Int64,1}:
 3
 4

In [49]:
# append an element
push!(l, 6)


Out[49]:
5-element Array{Int64,1}:
 3
 4
 5
 6
 6

Ending a function name with "!" is a convention to tell the user that the funciton modifies its input(s).


In [52]:
# types are converted automatically if possible & exact
l = [3, 4, 5]
push!(l, 12.0)


Out[52]:
4-element Array{Int64,1}:
  3
  4
  5
 12

Array operations

Arrays work as mathematical vectors, with the sum of two vectors and scalar multiplication being defined:


In [53]:
a = [1.1, 2.2, 3.3]
b = [4.4, 5.5, 6.6]

a + b


Out[53]:
3-element Array{Float64,1}:
 5.5
 7.7
 9.9

In [54]:
3.5 * a


Out[54]:
3-element Array{Float64,1}:
  3.85
  7.7 
 11.55

By default, operations are matrix operations, not element-wise!


In [55]:
# matrix multiply doesn't work on two vectors:
a * b


`*` has no method matching *(::Array{Float64,1}, ::Array{Float64,1})
while loading In[55], in expression starting on line 2

In [56]:
# it works if we transpose a:
println(a')
a' * b


[1.1 2.2 3.3]
Out[56]:
1-element Array{Float64,1}:
 38.72

In [57]:
# Instead, there are explicit element-wise operators
a .* b


Out[57]:
3-element Array{Float64,1}:
  4.84
 12.1 
 21.78

In [59]:
# You can do array-wise operations:
a.^2 .+ b.^2


Out[59]:
3-element Array{Float64,1}:
 20.57
 35.09
 54.45

In [60]:
# unicode dot and cross-products
a  b


Out[60]:
38.72

In [61]:
a × b


Out[61]:
3-element Array{Float64,1}:
 -3.63
  7.26
 -3.63

Array comprehensions

There is an equivalent of list comprehensions in Python, as follows. Note that the array construction syntax is quite flexible.


In [62]:
squares = [i^2 for i in [1:2:10, 7]]


Out[62]:
6-element Array{Any,1}:
  1
  9
 25
 49
 81
 49

In [63]:
sums = [i+j for i=1:5, j=1:5]


Out[63]:
5x5 Array{Int64,2}:
 2  3  4  5   6
 3  4  5  6   7
 4  5  6  7   8
 5  6  7  8   9
 6  7  8  9  10

Special modes: Help & Shell


In [64]:
help(size)


INFO: Loading help data...
Base.size(A)

   Returns a tuple containing the dimensions of A

In [65]:
# This also works [note the special mode in the command-line REPL]
?size


syntax: extra token "size" after end of expression
while loading In[65], in expression starting on line 2

In [ ]:
# Shell commands
;ls

In [66]:
# commands in general
run(`echo hello`)


hello

Control flow: drop the colon (:) and add end

White space in Julia is not significant. Commands on one line can be separated by ;. Blocks must finish with end


In [68]:
i = 0
while i < 5
    print("$i\t")
    i += 1
end


0	1	2	3	4	

In [69]:
total = 0
for i = 1:10
    total += i
end
println("Sum is $total")


Sum is 55

In [71]:
a = ["hi", "bye"]
for item in a
    println(item)
end


hi
bye

Here, 1:10 is a range object which may be iterated over.


In [70]:
typeof(1:10)


Out[70]:
UnitRange{Int64} (constructor with 1 method)

Use help or ? to get help:

Short-circuit evaluation


In [72]:
a = 3
a < 5 && println("Small")   # evaluate the second statement only if the first is true;  semantics of if-then

a > 10 || println("Small")  # semantics of if not-then


Small
Small

In [73]:
a == 3 ? println("Hello") : println("Not true")


Hello

Tuples


In [74]:
(1, 2)


Out[74]:
(1,2)

In [75]:
typeof(ans)


Out[75]:
(Int64,Int64)

In [76]:
a, b = 1, 2


Out[76]:
(1,2)

Dictionaries


In [77]:
# Dictionaries store mappings
# create an empty dictionary
d = Dict()


Out[77]:
Dict{Any,Any} with 0 entries

In [81]:
# You can create a dictionary using a literal
d = ["one"=> 1, "two"=>2]


Out[81]:
Dict{ASCIIString,Int64} with 2 entries:
  "two" => 2
  "one" => 1

In [82]:
# Look up values with []
d["one"]


Out[82]:
1

In [83]:
d["four"] = 4


Out[83]:
4

In [84]:
# Get all keys
keys(d)


Out[84]:
KeyIterator for a Dict{ASCIIString,Int64} with 3 entries. Keys:
  "two"
  "four"
  "one"

In [85]:
# Get all values
values(d)


Out[85]:
ValueIterator for a Dict{ASCIIString,Int64} with 3 entries. Values:
  2
  4
  1

File I/O

Simple file input and output is easy:


In [86]:
outfile = open("test.txt", "w")


Out[86]:
IOStream(<file test.txt>)

In [87]:
for i in 1:10
    println(outfile, "The value of i is $i")
end

close(outfile)

In [88]:
;cat test.txt


The value of i is 1
The value of i is 2
The value of i is 3
The value of i is 4
The value of i is 5
The value of i is 6
The value of i is 7
The value of i is 8
The value of i is 9
The value of i is 10

In [89]:
infile = open("test.txt", "r")


Out[89]:
IOStream(<file test.txt>)

In [90]:
lines = readlines(infile)


Out[90]:
10-element Array{Union(ASCIIString,UTF8String),1}:
 "The value of i is 1\n" 
 "The value of i is 2\n" 
 "The value of i is 3\n" 
 "The value of i is 4\n" 
 "The value of i is 5\n" 
 "The value of i is 6\n" 
 "The value of i is 7\n" 
 "The value of i is 8\n" 
 "The value of i is 9\n" 
 "The value of i is 10\n"

In [91]:
x = rand(5,5)


Out[91]:
5x5 Array{Float64,2}:
 0.145043   0.482136  0.502633  0.827301  0.0773628
 0.270498   0.427969  0.6956    0.261793  0.557632 
 0.36314    0.962799  0.622805  0.758735  0.382411 
 0.729764   0.403605  0.155983  0.486897  0.790483 
 0.0912498  0.425641  0.108973  0.202462  0.777564 

In [92]:
# There's a basic built-in text file reader and writer
writedlm("random.txt", x)
;cat random.txt


.1450434811866943	.4821363938872383	.5026331174005498	.8273014171620061	.07736278802190677
.27049785575324203	.42796893052261487	.6956000471466579	.261792915675946	.5576318206313249
.36313959794679906	.962798605783362	.6228046783136565	.7587349388141493	.3824107610513461
.7297641846349092	.40360530173784404	.155982807497423	.4868970288801464	.7904833180136224
.09124982906284496	.42564109430578356	.10897287753808715	.20246230977722735	.7775644341103995

In [93]:
y = readdlm("random.txt")  # note that tab completion works for files


Out[93]:
5x5 Array{Float64,2}:
 0.145043   0.482136  0.502633  0.827301  0.0773628
 0.270498   0.427969  0.6956    0.261793  0.557632 
 0.36314    0.962799  0.622805  0.758735  0.382411 
 0.729764   0.403605  0.155983  0.486897  0.790483 
 0.0912498  0.425641  0.108973  0.202462  0.777564 

In [94]:
# clean uup
;rm random.txt
;rm test.txt