The Julia Express

Bogumił Kamiński (http://bogumilkaminski.pl)

Contents

Introduction

Getting around

Basic literals and types

Complex literals and types

Strings

Programming constructs

Variable scoping

Modules

Operators

Essential general usage functions

Reading and writing data

Random numbers

Statistics and machine learning

Plotting

Macros

Taking it all together example

Inroduction

The Purpose of this document is to introduce programmers to Julia programming by example. This is a simplified exposition of the language.

If some packages are missing on your system use Pkg.add to require installing them. There are many add-on packages which you can browse at http://pkg.julialang.org/.

Major stuff not covered (please see the documentation):

  1. parametric types;
  2. parallel and distributed processing;
  3. advanced I/O operations;
  4. package management; see Pkg;
  5. interaction with system shell; see run;
  6. exception handling; see try;
  7. creation of coroutines; see Task;
  8. two-way integration with C and Fortran.

You can find current Julia documentation at http://julia.readthedocs.org/en/latest/manual/.

The code was executed using the following Julia version:

In [1]:
versioninfo()
Julia Version 0.5.0
Commit 3c9d753 (2016-09-19 18:14 UTC)
Platform Info:
  System: NT (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.7.1 (ORCJIT, broadwell)

Remember that you can expect every major version of Julia to introduce breaking changes.

Check https://github.com/JuliaLang/julia/blob/master/NEWS.md for release notes.

All sugestions how this guide can be improved are welcomed. Please contact me at bkamins@sgh.waw.pl.

Getting around

Running julia invokes interactive (REPL) mode. In this mode some useful commands are:

  1. ^D (exits Julia, also calling exit(c) quits with exit code c);
  2. ^C (interrupts computations);
  3. ? (enters help mode)
  4. ; (enters system shell mode)
  5. putting ; after the expression will disable showing of its value.

Examples of some essential functions in REPL (they can be also invoked in scripts):

In [2]:
apropos("apropos") # search documentation for "apropos" string
Base.Docs.stripmd
Base.Docs.apropos
In [3]:
@edit max(1,2) # show the definition of max function when invoked with arguments 1 and 2 in text editor
Unknown editor: no line number information passed.
The method is defined at line 280.
In [4]:
whos() # list of global variables and their types
                          Base  36753 KB     Module
                        Compat   5326 KB     Module
                          Core  13237 KB     Module
                        IJulia   6280 KB     Module
                          JSON   5402 KB     Module
                          Main  44350 KB     Module
                        Nettle   5311 KB     Module
                           ZMQ   5322 KB     Module
In [5]:
cd("D:/") # change working directory to D:/ (on Windows)
pwd() # get current working directory
Out[5]:
"D:\\"
In [6]:
include("file.jl") # execute source file, LoadError if execution fails
LoadError: could not open file D:\file.jl
while loading In[6], in expression starting on line 1

 in include_from_node1(::String) at .\loading.jl:488
In [7]:
clipboard([1,2]) # copy data to system clipboard
clipboard() # load data from system clipboard as string
Out[7]:
"[1,2]"
In [8]:
workspace() # clear worskspace - create new Main module (only to be used interactively)

You can execute Julia script by running julia script.jl.

Try saving the following example script to a file and run it (more examples of all the constructs used are given in following sections):

In [9]:
"Sieve of Eratosthenes function docstring"
function es(n::Int) # accepts one integer argument
    isprime = ones(Bool, n) # n-element vector of true-s
    isprime[1] = false # 1 is not a prime
    for i in 2:round(Int, sqrt(n)) # loop integers from 2 to sqrt(n)
        if isprime[i] # conditional evaluation
            for j in (i*i):i:n # sequence with step i
                isprime[j] = false
            end
        end
    end
    return filter(x -> isprime[x], 1:n) # filter using anonymous function
end
println(es(100)) # print all primes less or equal than 100
@time length(es(10^7)) # check function execution time and memory usage
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
  0.171362 seconds (147 allocations: 24.152 MB, 4.19% gc time)
Out[9]:
664579

Basic literals and types

Basic scalar literals (x::Type is a literal x with type Type assertion):

In [10]:
1::Int64 # 64-bit integer, no overflow warnings, fails on 32 bit Julia
Out[10]:
1
In [11]:
1.0::Float64 # 64-bit float, defines NaN, -Inf, Inf
Out[11]:
1.0
In [12]:
true::Bool # boolean, allows "true" and "false"
Out[12]:
true
In [13]:
'c'::Char # character, allows Unicode
Out[13]:
'c'
In [14]:
"s"::AbstractString # strings, allows Unicode, see also Strings
Out[14]:
"s"

All basic types are immutable. Specifying type assertion is optional (and usually it is not needed, but I give it to show how you can do it). Type assertions for variables are made in the same way and may improve code performance.

If you do not specify type assertion Julia will choose a default. Note that defaults might be different on 32-bit and 64-bit versions of Julia. A most important difference is for integers which are Int32 and Int64 respectively. This means that 1::Int32 assertion will fail on 64-bit version. Notably Int is either Int64 or Int32 depending on version (the same with UInt). There is no automatic type conversion (especially important in function calls). Has to be explicit:

In [15]:
Int64('a') # character to integer
Out[15]:
97
In [16]:
Int64(2.0) # float to integer
Out[16]:
2
In [17]:
Int64(1.3) # inexact error
LoadError: InexactError()
while loading In[17], in expression starting on line 1

 in Int64(::Float64) at .\sysimg.jl:53
In [18]:
Int64("a") # error no conversion possible
LoadError: MethodError: Cannot `convert` an object of type String to an object of type Int64
This may have arisen from a call to the constructor Int64(...),
since type constructors fall back to convert methods.
while loading In[18], in expression starting on line 1

 in Int64(::String) at .\sysimg.jl:53
In [19]:
Float64(1) # integer to float
Out[19]:
1.0
In [20]:
Bool(1) # converts to boolean true
Out[20]:
true
In [21]:
Bool(0) # converts to boolean false
Out[21]:
false
In [22]:
Bool(2) # conversion error
LoadError: InexactError()
while loading In[22], in expression starting on line 1

 in convert(::Type{Bool}, ::Int64) at .\bool.jl:6
 in Bool(::Int64) at .\sysimg.jl:53
In [23]:
Char(89) # integer to char
Out[23]:
'Y'
In [24]:
string(true) # cast bool to string (works with other types, note small caps)
Out[24]:
"true"
In [25]:
string(1,true) # string can take more than one argument and concatenate them
Out[25]:
"1true"
In [26]:
zero(10.0) # zero of type of 10.0
Out[26]:
0.0
In [27]:
one(Int64) # one of type Int64
Out[27]:
1

General conversion can be done using convert(Type, x):

In [28]:
convert(Int64, 1.0) # convert float to integer
Out[28]:
1

Parsing strings can be done using parse(Type, str):

In [29]:
parse(Int64, "1") # parse "1" string as Int64
Out[29]:
1

Automatic promotion ofmany arguments to common type (if any) using promote:

In [30]:
promote(true, BigInt(1)//3, 1.0) # tuple (see Tuples) of BigFloats, true promoted to 1.0
Out[30]:
(1.000000000000000000000000000000000000000000000000000000000000000000000000000000,3.333333333333333333333333333333333333333333333333333333333333333333333333333348e-01,1.000000000000000000000000000000000000000000000000000000000000000000000000000000)
In [31]:
promote("a", 1) # promotion to common type not possible
Out[31]:
("a",1)

Many operations (arithmetic, assignment) are defined in a way that performs automatic type promotion. One can verify type of argument:

In [32]:
typeof("abc") # String returned which is a AbstractString subtype
Out[32]:
String
In [33]:
isa("abc", AbstractString) # true
Out[33]:
true
In [34]:
isa(1, Float64) # false, integer is not a float
Out[34]:
false
In [35]:
isa(1.0, Float64) # true
Out[35]:
true
In [36]:
isa(1.0, Number) # true, Number is abstract type
Out[36]:
true
In [37]:
supertype(Int64) # supertype of Int64
Out[37]:
Signed
In [38]:
subtypes(Real) # subtypes of bastract type Real
Out[38]:
4-element Array{Any,1}:
 AbstractFloat       
 Integer             
 Irrational{sym}     
 Rational{T<:Integer}
In [39]:
subtypes(Int64)
Out[39]:
0-element Array{Any,1}

It is possible to performcalculations using arbitrary precision arithmetic or rational numbers:

In [40]:
BigInt(10)^1000 # big integer
Out[40]:
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
In [41]:
BigFloat(10)^1000 # big float, see documentation how to change default precision
Out[41]:
1.000000000000000000000000000000000000000000000000000000000000000000000000000004e+1000
In [42]:
123//456 # rational numbers are created using // operator
Out[42]:
41//152

Type hierarchy of all standard numeric types is given below:

In [43]:
function type_hierarchy(t::DataType, level = 0)
    println(" "^level, t)
    for x in subtypes(t)
        type_hierarchy(x, level+2)
    end
end
type_hierarchy(Number)
Number
  Complex{T<:Real}
  Real
    AbstractFloat
      BigFloat
      Float16
      Float32
      Float64
    Integer
      BigInt
      Bool
      Signed
        Int128
        Int16
        Int32
        Int64
        Int8
      Unsigned
        UInt128
        UInt16
        UInt32
        UInt64
        UInt8
    Irrational{sym}
    Rational{T<:Integer}
In [44]:
Any # all objects are of this type
Out[44]:
Any
In [45]:
Union{} # subtype of all types, no object can have this type
Out[45]:
Union{}
In [46]:
Void # type indicating nothing, subtype of Any
Out[46]:
Void
In [47]:
nothing # only instance of Void

Additionally #undef indicates an incompletely initialized instance.

Tuples

Tuples are immutable sequences indexed from 1:

In [48]:
() # empty tuple
Out[48]:
()
In [49]:
(1,) # one element tuple
Out[49]:
(1,)
In [50]:
("a", 1) # two element tuple
Out[50]:
("a",1)
In [51]:
('a', false)::Tuple{Char, Bool} # tuple type assertion
Out[51]:
('a',false)
In [52]:
x = (1, 2, 3)
Out[52]:
(1,2,3)
In [53]:
x[1] # 1 (element)
Out[53]:
1
In [54]:
x[1:2] # (1, 2) (tuple)
Out[54]:
(1,2)
In [55]:
x[4] # bounds error
LoadError: BoundsError: attempt to access (1,2,3)
  at index [4]
while loading In[55], in expression starting on line 1

 in getindex(::Tuple{Int64,Int64,Int64}, ::Int64) at .\tuple.jl:8
In [56]:
x[1] = 1 # error - tuple is not mutable
LoadError: MethodError: no method matching setindex!(::Tuple{Int64,Int64,Int64}, ::Int64, ::Int64)
while loading In[56], in expression starting on line 1
In [57]:
a, b = x # tuple unpacking a=1, b=2
println("$a $b")
1 2

Arrays

Arrays are mutable and passed by reference. Array creation:

In [58]:
Array(Char, 2, 3, 4) # 2x3x4 array of Chars
Out[58]:
2×3×4 Array{Char,3}:
[:, :, 1] =
 '\0'  '\0'  '\0'
 '\0'  '\0'  '\0'

[:, :, 2] =
 '\0'  '\0'  '\0'
 '\0'  '\0'  '\0'

[:, :, 3] =
 '\0'  '\x06'  '\0'
 '\0'  '\0'    '\0'

[:, :, 4] =
 '\b'  '\0'  '\0'
 '\0'  '\0'  '\0'
In [59]:
Array{Int64}(0, 0) # degenerate 0x0 array of Int64
Out[59]:
0×0 Array{Int64,2}
In [60]:
Array{Any}(2, 3) # 2x3 array of Any
Out[60]:
2×3 Array{Any,2}:
 #undef  #undef  #undef
 #undef  #undef  #undef
In [61]:
zeros(5) # vector of Float64 zeros
Out[61]:
5-element Array{Float64,1}:
 0.0
 0.0
 0.0
 0.0
 0.0
In [62]:
ones(5) # vector of Float64 ones
Out[62]:
5-element Array{Float64,1}:
 1.0
 1.0
 1.0
 1.0
 1.0
In [63]:
ones(Int64, 2, 1) # 2x1 array of Int64 ones
Out[63]:
2×1 Array{Int64,2}:
 1
 1
In [64]:
trues(3), falses(3) # tuple of vector of trues and of falses
Out[64]:
(Bool[true,true,true],Bool[false,false,false])
In [65]:
eye(3) # 3x3 Float64 identity matrix
Out[65]:
3×3 Array{Float64,2}:
 1.0  0.0  0.0
 0.0  1.0  0.0
 0.0  0.0  1.0
In [66]:
x = linspace(1, 2, 5) # iterator having 5 equally spaced elements
Out[66]:
5-element LinSpace{Float64}:
 1.0,1.25,1.5,1.75,2.0
In [67]:
collect(x) # converts iterator to vector
Out[67]:
5-element Array{Float64,1}:
 1.0 
 1.25
 1.5 
 1.75
 2.0 
In [68]:
1:10 # iterable from 1 to 10
Out[68]:
1:10
In [69]:
1:2:10 # iterable from 1 to 9 with 2 skip
Out[69]:
1:2:9
In [70]:
reshape(1:12, 3, 4) # 3x4 array filled with 1:12 values
Out[70]:
3×4 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}:
 1  4  7  10
 2  5  8  11
 3  6  9  12
In [71]:
fill("a", 2, 2) # 2x2 array filled with "a"
Out[71]:
2×2 Array{String,2}:
 "a"  "a"
 "a"  "a"
In [72]:
repmat(eye(2), 3, 2) # 2x2 identity matrix repeated 3x2 times
Out[72]:
6×4 Array{Float64,2}:
 1.0  0.0  1.0  0.0
 0.0  1.0  0.0  1.0
 1.0  0.0  1.0  0.0
 0.0  1.0  0.0  1.0
 1.0  0.0  1.0  0.0
 0.0  1.0  0.0  1.0
In [73]:
x = [1, 2] # two element vector
Out[73]:
2-element Array{Int64,1}:
 1
 2
In [74]:
resize!(x, 5) # resize x in place to hold 5 values (filled with garbage)
Out[74]:
5-element Array{Int64,1}:
      1
      2
 569348
      0
      0
In [75]:
[1] # vector with one element (not a scalar)
Out[75]:
1-element Array{Int64,1}:
 1
In [76]:
[x * y for x in 1:2, y in 1:3] # comprehension generating 2x3 array
Out[76]:
2×3 Array{Int64,2}:
 1  2  3
 2  4  6
In [77]:
Float64[x^2 for x in 1:4] # casting comprehension result to Float64
Out[77]:
4-element Array{Float64,1}:
  1.0
  4.0
  9.0
 16.0
In [78]:
[1 2] # 1x2 matrix (hcat function)
Out[78]:
1×2 Array{Int64,2}:
 1  2
In [79]:
[1 2]' # 2x1 matrix (after transposing)
Out[79]:
2×1 Array{Int64,2}:
 1
 2
In [80]:
[1, 2] # vector (concatenation)
Out[80]:
2-element Array{Int64,1}:
 1
 2
In [81]:
[1; 2] # vector (vcat function)
Out[81]:
2-element Array{Int64,1}:
 1
 2
In [82]:
[1 2 3; 1 2 3] # 2x3 matrix (hvcat function)
Out[82]:
2×3 Array{Int64,2}:
 1  2  3
 1  2  3
In [83]:
[1; 2] == [1 2]' # false, different array dimensions
Out[83]:
false
In [84]:
[(1, 2)] # 1-element vector
Out[84]:
1-element Array{Tuple{Int64,Int64},1}:
 (1,2)
In [85]:
collect((1, 2)) # 2-element vector by tuple unpacking
Out[85]:
2-element Array{Int64,1}:
 1
 2
In [86]:
[[1 2] 3] # append to a row vector (hcat)
Out[86]:
1×3 Array{Int64,2}:
 1  2  3
In [87]:
[[1; 2]; 3] # append to a column vector (vcat)
Out[87]:
3-element Array{Int64,1}:
 1
 2
 3

Vectors (1D arrays) are treated as column vectors.

Julia offers sparse and distributed matrices (see documentation for details).

Commonly needed array utility functions:

In [88]:
a = [x * y for x in 1:2, y in 1, z in 1:3] # 2x3 array of Int64; singelton dimension is dropped
Out[88]:
2×3 Array{Int64,2}:
 1  1  1
 2  2  2
In [89]:
a = [x * y for x in 1:2, y in 1:1, z in 1:3] # 2x1x3 array of Int64; singelton dimension is not dropped
Out[89]:
2×1×3 Array{Int64,3}:
[:, :, 1] =
 1
 2

[:, :, 2] =
 1
 2

[:, :, 3] =
 1
 2
In [90]:
ndims(a) # number of dimensions in a
Out[90]:
3
In [91]:
eltype(a) # type of elements in a
Out[91]:
Int64
In [92]:
length(a) # number of elements in a
Out[92]:
6
In [93]:
size(a) # tuple containing dimension sizes of a
Out[93]:
(2,1,3)
In [94]:
vec(a) # cast array to vetor (single dimension)
Out[94]:
6-element Array{Int64,1}:
 1
 2
 1
 2
 1
 2
In [95]:
squeeze(a, 2) # remove 2nd dimension as it has size 1
Out[95]:
2×3 Array{Int64,2}:
 1  1  1
 2  2  2
In [96]:
sum(a, 3) # calculate sums for 3rd dimensions, similarly: mean, std, prod, minimum, maximum, any, all
Out[96]:
2×1×1 Array{Int64,3}:
[:, :, 1] =
 3
 6
In [97]:
count(x -> x > 0, a) # count number of times a predicate is true, similar: all, any
Out[97]:
6

Array access functions:

In [98]:
a = linspace(0, 1) # LinSpace{Float64} of length 50
Out[98]:
50-element LinSpace{Float64}:
 0.0,0.0204082,0.0408163,0.0612245,0.0816327,…,0.938776,0.959184,0.979592,1.0
In [99]:
a[1] # get scalar 0.0
Out[99]:
0.0
In [100]:
a[end] # get scalar 1.0 (last position)
Out[100]:
1.0
In [101]:
a[1:2:end] # every second element from range, LinSpace{Float64}
Out[101]:
25-element LinSpace{Float64}:
 0.0,0.0408163,0.0816327,0.122449,…,0.857143,0.897959,0.938776,0.979592
In [102]:
a[repmat([true, false], 25)] # select every second element, Array{Float64,1}
Out[102]:
25-element Array{Float64,1}:
 0.0      
 0.0408163
 0.0816327
 0.122449 
 0.163265 
 0.204082 
 0.244898 
 0.285714 
 0.326531 
 0.367347 
 0.408163 
 0.44898  
 0.489796 
 0.530612 
 0.571429 
 0.612245 
 0.653061 
 0.693878 
 0.734694 
 0.77551  
 0.816327 
 0.857143 
 0.897959 
 0.938776 
 0.979592 
In [103]:
a[[1, 3, 6]] # 1st, 3rd and 6th element of a, Array{Float64,1}
Out[103]:
3-element Array{Float64,1}:
 0.0      
 0.0408163
 0.102041 
In [104]:
view(a, 1:2:50) # view into subsarray of a
Out[104]:
25-element SubArray{Float64,1,LinSpace{Float64},Tuple{StepRange{Int64,Int64}},true}:
 0.0      
 0.0408163
 0.0816327
 0.122449 
 0.163265 
 0.204082 
 0.244898 
 0.285714 
 0.326531 
 0.367347 
 0.408163 
 0.44898  
 0.489796 
 0.530612 
 0.571429 
 0.612245 
 0.653061 
 0.693878 
 0.734694 
 0.77551  
 0.816327 
 0.857143 
 0.897959 
 0.938776 
 0.979592 
In [105]:
endof(a) # last index of the collection a
Out[105]:
50

Observe the treatment of trailing singleton dimensions:

In [106]:
a = reshape(1:12, 3, 4)
Out[106]:
3×4 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}:
 1  4  7  10
 2  5  8  11
 3  6  9  12
In [107]:
a[:, 1:2] # 3x2 matrix
Out[107]:
3×2 Array{Int64,2}:
 1  4
 2  5
 3  6
In [108]:
a[:, 1] # 3 element vector
Out[108]:
3-element Array{Int64,1}:
 1
 2
 3
In [109]:
a[1, :] # 4 element vector
Out[109]:
4-element Array{Int64,1}:
  1
  4
  7
 10
In [110]:
a[1:1, :] # 1x4 matrix
Out[110]:
1×4 Array{Int64,2}:
 1  4  7  10
In [111]:
a[:, :, 1, 1] # works 3x4 matrix
Out[111]:
3×4 Array{Int64,2}:
 1  4  7  10
 2  5  8  11
 3  6  9  12
In [112]:
a[:, :, :, [true]] # wroks 3x4x1 matrix
Out[112]:
3×4×1 Array{Int64,3}:
[:, :, 1] =
 1  4  7  10
 2  5  8  11
 3  6  9  12
In [113]:
a[1, 1, [false]] # works 0-element Array{Int64,1}
Out[113]:
0-element Array{Int64,1}

Array assignment:

In [114]:
x = collect(reshape(1:8, 2, 4))
Out[114]:
2×4 Array{Int64,2}:
 1  3  5  7
 2  4  6  8
In [115]:
x[:, 2:3] = [1 2] # error; size mismatch
LoadError: DimensionMismatch("tried to assign 1×2 array to 2×2 destination")
while loading In[115], in expression starting on line 1

 in throw_setindex_mismatch(::Array{Int64,2}, ::Tuple{Int64,Int64}) at .\operators.jl:421
 in setindex_shape_check(::Array{Int64,2}, ::Int64, ::Int64) at .\operators.jl:478
 in macro expansion at .\multidimensional.jl:425 [inlined]
 in _unsafe_batchsetindex!(::Array{Int64,2}, ::Array{Int64,2}, ::Colon, ::UnitRange{Int64}) at .\multidimensional.jl:421
 in setindex!(::Array{Int64,2}, ::Array{Int64,2}, ::Colon, ::UnitRange{Int64}) at .\abstractarray.jl:832
In [116]:
x[:, 2:3] = repmat([1 2], 2) # OK
Out[116]:
2×2 Array{Int64,2}:
 1  2
 1  2
In [117]:
x[:, 2:3] = 3 # OK
Out[117]:
3

Arrays are assigned and passed by reference. Therefore copying is provided:

In [118]:
x = Array{Any}(2)
x[1] = ones(2)
x[2] = trues(3)
a = x
b = copy(x) # shallow copy
c = deepcopy(x) # deep copy
x[1] = "Bang"
x[2][1] = false
x
Out[118]:
2-element Array{Any,1}:
 "Bang"               
 Bool[false,true,true]
In [119]:
a # identical as x
Out[119]:
2-element Array{Any,1}:
 "Bang"               
 Bool[false,true,true]
In [120]:
b # only x[2][1] changed from original x
Out[120]:
2-element Array{Any,1}:
 [1.0,1.0]            
 Bool[false,true,true]
In [121]:
c # contents to original x
Out[121]:
2-element Array{Any,1}:
 [1.0,1.0]           
 Bool[true,true,true]

Array types syntax examples:

In [122]:
[1 2]::Array{Int64, 2} # 2 dimensional array of Int64
Out[122]:
1×2 Array{Int64,2}:
 1  2
In [123]:
[true; false]::Vector{Bool} # vector of Bool
Out[123]:
2-element Array{Bool,1}:
  true
 false
In [124]:
[1 2; 3 4]::Matrix{Int64} # matrix of Int64
Out[124]:
2×2 Array{Int64,2}:
 1  2
 3  4

Composite types

Composite types are mutable and passed by reference. You can define and access composite types:

In [125]:
type Point
    x::Int64
    y::Float64
    meta
end
p = Point(0, 0.0, "Origin")
Out[125]:
Point(0,0.0,"Origin")
In [126]:
p.x # access field
Out[126]:
0
In [127]:
p.meta = 2 # change field value
Out[127]:
2
In [128]:
p.x = 1.5 # error, wrong data type
LoadError: InexactError()
while loading In[128], in expression starting on line 1

 in convert(::Type{Int64}, ::Float64) at .\int.jl:239
In [129]:
p.z = 1 # error - no such field
LoadError: type Point has no field z
while loading In[129], in expression starting on line 1
In [130]:
fieldnames(p) # get names of instance fields
Out[130]:
3-element Array{Symbol,1}:
 :x   
 :y   
 :meta
In [131]:
fieldnames(Point) # get names of type fields
Out[131]:
3-element Array{Symbol,1}:
 :x   
 :y   
 :meta

You can define type to be immutable by replacing type by immutable. There are also union types (see documentation for details).

Dictionaries

Associative collections (key-value dictionaries):

In [132]:
x = Dict{Float64, Int64}() # empty dictionary mapping floats to integers
Out[132]:
Dict{Float64,Int64} with 0 entries
In [133]:
y = Dict("a"=>1, "b"=>2) # filled dictionary
Out[133]:
Dict{String,Int64} with 2 entries:
  "b" => 2
  "a" => 1
In [134]:
y["a"] # element retrieval
Out[134]:
1
In [135]:
y["c"] # error
LoadError: KeyError: key "c" not found
while loading In[135], in expression starting on line 1

 in getindex(::Dict{String,Int64}, ::String) at .\dict.jl:688
In [136]:
y["c"] = 3 # added element
Out[136]:
3
In [137]:
haskey(y, "b") # check if y contains key "b"
Out[137]:
true
In [138]:
keys(y), values(y) # tuple of iterators returning keys and values in y
Out[138]:
(String["c","b","a"],[3,2,1])
In [139]:
delete!(y, "b") # delete key from a collection, see also: pop!
Out[139]:
Dict{String,Int64} with 2 entries:
  "c" => 3
  "a" => 1
In [140]:
get(y,"c","default") # return y["c"] or "default" if not haskey(y,"c")
Out[140]:
3

Julia also supports operations on sets and dequeues, priority queues and heaps (please refer to documentation).

Strings

String operations:

In [141]:
"Hi " * "there!" # string concatenation
Out[141]:
"Hi there!"
In [142]:
"Ho " ^ 3 # repeat string
Out[142]:
"Ho Ho Ho "
In [143]:
string("a= ", 123.3) # create using print function
Out[143]:
"a= 123.3"
In [144]:
repr(123.3) # fetch value of show function to a string
Out[144]:
"123.3"
In [145]:
contains("ABCD", "CD") # check if first string contains second
Out[145]:
true
In [146]:
"\"\n\t\$" # C-like escaping in strings, new \$ escape
Out[146]:
"\"\n\t\$"
In [147]:
x = 123
"$x + 3 = $(x+3)" # unescaped $ is used for interpolation
Out[147]:
"123 + 3 = 126"
In [148]:
"\$199" # to get a $ symbol you must escape it
Out[148]:
"\$199"

PCRE regular expressions handling:

In [149]:
r = r"A|B" # create new regexp
Out[149]:
r"A|B"
In [150]:
ismatch(r, "CD") # false, no match found
Out[150]:
false
In [151]:
m = match(r, "ACBD") # find first regexp match, see documentation for details
Out[151]:
RegexMatch("A")

There is a vast number of string functions—please refer to documentation.

Programming constructs

The simplest way to create new variable is by assignment:

In [152]:
x = 1.0 # x is Float64
Out[152]:
1.0
In [153]:
x = 1 # now x is Int32 on 32 bit machine and Int64 on 64 bit machine
Out[153]:
1

Expressions can be compound using ; or begin end block:

In [154]:
x = (a = 1; 2 * a) # after: x = 2; a = 1
(x, a)
Out[154]:
(2,1)
In [155]:
y = begin
    b = 3
    3 * b
end # after: y = 9; b = 3
(y, b)
Out[155]:
(9,3)

There are standard programming constructs:

In [156]:
if false # if clause requires Bool test
    z = 1
elseif 1==2
    z = 2
else
    a = 3
end # after this a = 3 and z is undefined
(a, isdefined(:z))
Out[156]:
(3,false)
In [157]:
1==2 ? "A" : "B" # standard ternary operator
Out[157]:
"B"
In [158]:
i = 1
while true
    i += 1
    if i > 10
        break
    end
end
i
Out[158]:
11
In [159]:
for x in 1:10 # x in collection, can also use = here instead of in
    if 3 < x < 6
        continue # skip one iteration
    end
    println(x)
end # x is introduced in loop outer scope
x
1
2
3
6
7
8
9
10
Out[159]:
10

You can define your own functions:

In [160]:
f(x, y = 10) = x + y # new function f with y defaulting to 10; last result returned
f(3, 2) # simple call, 5 returned
Out[160]:
5
In [161]:
f(3) # 13 returned
Out[161]:
13
In [162]:
function g(x::Int, y::Int) # type restriction
return y, x # explicit return of a tuple
end
g(x::Int, y::Bool) = x * y # add multiple dispatch
g(2, true) # second definition is invoked
Out[162]:
2
In [163]:
methods(g) # list all methods defined for g
Out[163]:
2 methods for generic function g:
  • g(x::Int64, y::Bool) at In[162]:4
  • g(x::Int64, y::Int64) at In[162]:2
In [164]:
(x -> x^2)(3) # anonymous function with a call
Out[164]:
9
In [165]:
() -> 0 # anonymous function with no arguments
Out[165]:
(::#13) (generic function with 1 method)
In [166]:
h(x...) = sum(x)/length(x) - mean(x) # vararg function; x is a tuple
h(1, 2, 3) # result is 0
Out[166]:
0.0
In [167]:
x = (2, 3) # tuple
f(x) # error
LoadError: MethodError: no method matching +(::Tuple{Int64,Int64}, ::Int64)
Closest candidates are:
  +(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:138
  +(!Matched::Complex{Bool}, ::Real) at complex.jl:151
  +(!Matched::Char, ::Integer) at char.jl:40
  ...
while loading In[167], in expression starting on line 2

 in f(::Tuple{Int64,Int64}) at .\In[160]:1
In [168]:
f(x...) # OK - tuple unpacking
Out[168]:
5
In [169]:
s(x; a = 1, b = 1) = x * a / b # function with keyword arguments a and b
s(3, b = 2) # call with keyword argument
Out[169]:
1.5
In [170]:
x1(; x::Int64 = 2) = x # single keyword argument
x1() # 2 returned
Out[170]:
2
In [171]:
x2(; x::Bool = true) = x # no multiple dispatch for keyword arguments; function overwritten
x2() # true; old function was overwritten
Out[171]:
true
In [172]:
q(f::Function, x) = 2 * f(x) # simple function wrapper
q(x -> 2x, 10) # 40 returned, no need to use * in 2x (means 2*x)
Out[172]:
40
In [173]:
q(10) do x # creation of anonymous function by do construct, useful eg. in IO
    2 * x
end
Out[173]:
40
In [174]:
m = reshape(1:12, 3, 4)
map(x -> x ^ 2, m) # 3x4 array returned with transformed data
Out[174]:
3×4 Array{Int64,2}:
 1  16  49  100
 4  25  64  121
 9  36  81  144
In [175]:
filter(x -> bits(x)[end] == '0', 1:12) # a fancy way to choose even integers from the range
Out[175]:
6-element Array{Int64,1}:
  2
  4
  6
  8
 10
 12

As a convention functions with name ending with ! change their arguments in-place. See for example resize! in this document.

Default function argument beasts:

In [176]:
y = 10
f1(x=y) = x; f1() # 10
Out[176]:
10
In [177]:
f2(x=y,y=1) = x; f2() # 10
Out[177]:
10
In [178]:
f3(y=1,x=y) = x; f3() # 1
Out[178]:
1
In [179]:
f4(;x=y) = x; f4() # 10
Out[179]:
10
In [180]:
f5(;x=y,y=1) = x; f5() # error - y not defined yet :(
LoadError: UndefVarError: y not defined
while loading In[180], in expression starting on line 1

 in f5() at .\In[180]:1
In [181]:
f6(;y=1,x=y) = x; f6() # 1
Out[181]:
1

Variable scoping

The following constructs introduce new variable scope: function, while, for, try/catch, let, type.

You can define variables as:

  • global: use variable from global scope;
  • local: define new variable in current scope;
  • const: ensure variable type is constant (global only).

Special cases:

In [182]:
w # error, variable does not exist
LoadError: UndefVarError: w not defined
while loading In[182], in expression starting on line 1
In [183]:
f() = global w = 1
f() # after the call w is defined globally
w
Out[183]:
1
In [184]:
function fn(n)
    x = 0
    for i = 1:n
        x = i
    end
    x
end
fn(10) # 10; inside loop we use outer local variable
Out[184]:
10
In [185]:
function fn2(n)
    x = 0
    for i = 1:n
        local x
        x = i
    end
    x
end
fn2(10) # 0; inside loop we use new local variable
Out[185]:
0
In [186]:
function fn3(n)
    for i = 1:n
        local x # this local can be omitted; for introduces new scope
        x = i
    end
    x
end
fn3(10) # x fetched from global scope as it wase already defined
Out[186]:
(2,3)
In [187]:
const n = 2
n = 3 # warning, value changed
WARNING: redefining constant n
Out[187]:
3
In [188]:
n = 3.0 # error, wrong type
LoadError: invalid redefinition of constant n
while loading In[188], in expression starting on line 1
In [189]:
function fun() # no warning
    const x = 2
    x = true
end
fun() # true, no warning
Out[189]:
true

Global constants speed up execution.

The let rebinds the variable:

In [190]:
Fs = Array{Any}(2)
i = 1
while i <= 2
    j = i
    Fs[i] = () -> j
    i += 1
end
Fs[1](), Fs[2]() # (2, 2); the same binding for j
Out[190]:
(2,2)
In [191]:
Fs = Array{Any}(2)
i = 1
while i <= 2
    let j = i
        Fs[i] = () -> j
    end
    i += 1
end
Fs[1](), Fs[2]() # (1, 2); new binding for j
Out[191]:
(1,2)
In [192]:
Fs = Array{Any}(2)
i = 1
for i in 1:2
    j = i
    Fs[i] = () -> j
end
Fs[1](), Fs[2]() # (1, 2); for loops and comprehensions rebind variables
Out[192]:
(1,2)

Modules

Modules encapsulate code. Can be reloaded, which is useful to redefine functions and types, as top level functions and types are defined as constants.

In [193]:
module M # module name; can be replaced in one session
export xx # what module exposes for the world
xx = 1
y = 2 # hidden variable
end

whos(M) # list exported variables
                             M   1192 bytes  Module
                            xx      8 bytes  Int64
In [194]:
xx # not found in global scope
LoadError: UndefVarError: xx not defined
while loading In[194], in expression starting on line 1
In [195]:
M.y # direct variable access possible
Out[195]:
2
In [196]:
# import all exported variables
# load standard packages this way
using M

#import variable y to global scope (even if not exported)
import M.y
WARNING: import of M.y into Main conflicts with an existing identifier; ignored.

Operators

Julia follows standard operators with the following quirks:

In [197]:
true || false # binary or operator (singeltons only), || and && use short-circut evaluation
Out[197]:
true
In [198]:
[1 2] & [2 1] # bitwise and operator
Out[198]:
1×2 Array{Int64,2}:
 0  0
In [199]:
1 < 2 < 3 # chaining conditions is OK (singeltons only)
Out[199]:
true
In [200]:
[1 2] .< [2 1] # for vectorized operators need to add ’.’ in front
Out[200]:
1×2 BitArray{2}:
 true  false
In [201]:
x = [1 2 3]
2x + 2(x+1) # multiplication can be omitted between a literal and a variable or a left parenthesis
Out[201]:
1×3 Array{Int64,2}:
 6  10  14
In [202]:
y = [1, 2, 3]
Out[202]:
3-element Array{Int64,1}:
 1
 2
 3
In [203]:
x + y # error
LoadError: DimensionMismatch("dimensions must match")
while loading In[203], in expression starting on line 1

 in promote_shape(::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}, ::Tuple{Base.OneTo{Int64}}) at .\operators.jl:406
 in promote_shape(::Array{Int64,2}, ::Array{Int64,1}) at .\operators.jl:397
 in _elementwise(::Base.#+, ::Type{Int64}, ::Array{Int64,2}, ::Array{Int64,1}) at .\arraymath.jl:57
 in +(::Array{Int64,2}, ::Array{Int64,1}) at .\arraymath.jl:49
In [204]:
x .+ y # 3x3 matrix, dimension broadcasting
Out[204]:
3×3 Array{Int64,2}:
 2  3  4
 3  4  5
 4  5  6
In [205]:
x + y' # 1x3 matrix
Out[205]:
1×3 Array{Int64,2}:
 2  4  6
In [206]:
x * y # array multiplication, 1-element vector (not scalar)
Out[206]:
1-element Array{Int64,1}:
 14
In [207]:
x .* y # element-wise multiplication, 3x3 array
Out[207]:
3×3 Array{Int64,2}:
 1  2  3
 2  4  6
 3  6  9
In [208]:
x == [1 2 3] # true, object looks the same
Out[208]:
true
In [209]:
x === [1 2 3] # false, objects not identical
Out[209]:
false
In [210]:
z = reshape(1:9, 3, 3)
Out[210]:
3×3 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}:
 1  4  7
 2  5  8
 3  6  9
In [211]:
z + x # error
LoadError: DimensionMismatch("dimensions must match")
while loading In[211], in expression starting on line 1

 in promote_shape(::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}, ::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}) at .\operators.jl:406
 in promote_shape(::Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}, ::Array{Int64,2}) at .\operators.jl:397
 in _elementwise(::Base.#+, ::Type{Int64}, ::Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}, ::Array{Int64,2}) at .\arraymath.jl:57
 in +(::Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}, ::Array{Int64,2}) at .\arraymath.jl:49
In [212]:
z .+ x # x broadcasted vertically
Out[212]:
3×3 Array{Int64,2}:
 2  6  10
 3  7  11
 4  8  12
In [213]:
z .+ y # y broadcasted horizontally
Out[213]:
3×3 Array{Int64,2}:
 2  5   8
 4  7  10
 6  9  12
In [214]:
# explicit broadcast of singelton dimensions
# function + is called for each array element
broadcast(+, [1 2], [1; 2])
Out[214]:
2×2 Array{Int64,2}:
 2  3
 3  4

Many typical matrix transformation functions are available (see documentation).

In [215]:
show(collect(1:100)) # show text representation of an object
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]
In [216]:
eps() # distance from 1.0 to next representable Float64
Out[216]:
2.220446049250313e-16
In [217]:
nextfloat(2.0) # next float representable, similarly provided prevfloat
Out[217]:
2.0000000000000004
In [218]:
isequal(NaN, NaN) # true
Out[218]:
true
In [219]:
NaN == NaN # false
Out[219]:
false
In [220]:
NaN === NaN # true
Out[220]:
true
In [221]:
isequal(1, 1.0) # true
Out[221]:
true
In [222]:
1 == 1.0 # true
Out[222]:
true
In [223]:
1 === 1.0 # false
Out[223]:
false
In [224]:
isfinite(Inf) # false, similarly provided: isinf, isnan
Out[224]:
false
In [225]:
fld(-5, 3), mod(-5, 3) # (-2, 1), division towards minus infinity
Out[225]:
(-2,1)
In [226]:
div(-5, 3), rem(-5, 3) # (-1, -2), division towards zero
Out[226]:
(-1,-2)
In [227]:
find(x -> mod(x, 2) == 0, 1:8) # find indices for which function returns true
Out[227]:
4-element Array{Int64,1}:
 2
 4
 6
 8
In [228]:
x = [1 2]; identity(x) === x # true, identity function
Out[228]:
true
In [229]:
info("Info") # print information, similarly warn and error (raises error)
INFO: Info
In [230]:
ntuple(x->2x, 3) # create tuple by calling x->2x with values 1, 2 and 3
Out[230]:
(2,4,6)
In [231]:
isdefined(:x) # if variable x is defined (:x is a symbol)
Out[231]:
true
In [232]:
y = Array{Any}(2); isassigned(y, 3) # if position 3 in array is assigned (not out of bounds or #undef)
Out[232]:
false
In [233]:
fieldtype(typeof(1:2),:start) # get type of the field in composite type (passed as symbol)
Out[233]:
Int64
In [234]:
fieldnames(typeof(1:2))
Out[234]:
2-element Array{Symbol,1}:
 :start
 :stop 
In [235]:
1:5 |> exp |> sum # function application chaining
Out[235]:
233.2041839862982
In [236]:
zip(1:3, 1:3) |> collect # convert iterables to iterable tuple and pass it to collect
Out[236]:
3-element Array{Tuple{Int64,Int64},1}:
 (1,1)
 (2,2)
 (3,3)
In [237]:
enumerate("abc") # create iterator of tuples (index, collection element)
Out[237]:
Enumerate{String}("abc")
In [238]:
collect(enumerate("abc"))
Out[238]:
3-element Array{Tuple{Int64,Char},1}:
 (1,'a')
 (2,'b')
 (3,'c')
In [239]:
isempty("abc") # check if collection is empty
Out[239]:
false
In [240]:
'b' in "abc" # check if element is in a collection
Out[240]:
true
In [241]:
indexin(collect("abc"), collect("abrakadabra")) # [11, 9, 0] (’c’ not found), needs arrays
Out[241]:
3-element Array{Int64,1}:
 11
  9
  0
In [242]:
findin("abc", "abrakadabra") # [1, 2] (’c’ was not found)
Out[242]:
2-element Array{Int64,1}:
 1
 2
In [243]:
unique("abrakadabra") # return unique elements
Out[243]:
5-element Array{Char,1}:
 'a'
 'b'
 'r'
 'k'
 'd'
In [244]:
issubset("abc", "abcd") # check if every element in fist collection is in the second
Out[244]:
true
In [245]:
indmax("abrakadabra") # index of maximal element (3 - ’r’ in this case)
Out[245]:
3
In [246]:
findmax("abrakadabra") # tuple: maximal element and its index
Out[246]:
('r',3)
In [247]:
filter(x->mod(x,2)==0, 1:10) # retain elements of collection that meet predicate
Out[247]:
5-element Array{Int64,1}:
  2
  4
  6
  8
 10
In [248]:
dump(1:2:5) # show all user-visible structure of an object
StepRange{Int64,Int64}
  start: Int64 1
  step: Int64 2
  stop: Int64 5
In [249]:
sort(rand(10)) # sort 10 uniform random variables
Out[249]:
10-element Array{Float64,1}:
 0.270829
 0.562223
 0.608463
 0.76566 
 0.806131
 0.836307
 0.842975
 0.86536 
 0.949632
 0.976556

Reading and writing data

For I/O details refer documentation. Basic operations:

  • readdlm, readcsv: read from file
  • writedlm, writecsv: write to a file

Warning! Trailing spaces are not discarded if delim=' ' in file reading.

Random numbers

Basic random numbers:

In [250]:
srand(1) # set random number generator seed to 1
rand() # generate random number from U[0,1)
Out[250]:
0.23603334566204692
In [251]:
rand(3, 4) # generate 3x4 matrix of random numbers from U[0,1]
Out[251]:
3×4 Array{Float64,2}:
 0.346517    0.488613  0.999905  0.555751
 0.312707    0.210968  0.251662  0.437108
 0.00790928  0.951916  0.986666  0.424718
In [252]:
rand(2:5, 10) # generate vector of 10 random integer numbers in range form 2 to 5
Out[252]:
10-element Array{Int64,1}:
 4
 2
 3
 4
 5
 5
 3
 4
 3
 5
In [253]:
randn(10) # generate vector of 10 random numbers from standard normal distribution
Out[253]:
10-element Array{Float64,1}:
  0.795949 
  0.670062 
  0.550852 
 -0.0633746
  1.33694  
 -0.0731486
 -0.745464 
 -1.22006  
 -0.0531773
 -0.165136 

Advanced randomness form Distributions package:

In [254]:
using Distributions # load package
sample(1:10, 10) # single bootstrap sample from set 1-10
WARNING: Method definition redirect_stdin(Function, Any) in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1600 overwritten in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1600.
Out[254]:
10-element Array{Int64,1}:
  4
  3
  3
  8
  4
  5
  1
  9
  2
 10
In [255]:
b = Beta(0.4, 0.8) # Beta distribution with parameters 0.4 and 0.8
# see documentation for supported distributions
WARNING: Method definition redirect_stderr(Function, Any) in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1600 overwritten in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1600.
WARNING: Method definition redirect_stdout
Out[255]:
Distributions.Beta{Float64}(α=0.4, β=0.8)
In [256]:
mean(b) # expected value of distribution b
# see documentation for other supported statistics
(Function, Any) in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1600 overwritten in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1600.
WARNING: Method definition take!(Main.Base.AbstractIOBuffer)
Out[256]:
0.3333333333333333
In [257]:
rand(b, 100) # 100 independent random samples from distribution b
 in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1698 overwritten in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1698.
WARNING: Method definition isnull(Any) in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1678 overwritten in module Compat at C:\Users\bogumil.kaminski\.julia\v0.5\Compat\src\Compat.jl:1678.
Out[257]:
100-element Array{Float64,1}:
 0.66191    
 0.330293   
 0.283145   
 0.250579   
 0.0638634  
 0.0498457  
 0.0303621  
 0.00106341 
 7.44665e-5 
 0.598042   
 0.000751651
 0.381232   
 0.509084   
 ⋮          
 0.0459099  
 0.750168   
 0.024662   
 0.0146038  
 0.712225   
 0.0472612  
 0.821081   
 0.0552943  
 0.994703   
 0.258232   
 0.0668111  
 0.139352   

Statistics and machine learning

Visit http://juliastats.github.io/ for the details (in particular R-like data frames).

Starting with Julia version 0.4 there is a core language construct Nullable that allows to represent missing value (similar to HaskellMaybe).

In [258]:
u1 = Nullable(1) # contains value
u2 = Nullable{Int64}() # missing value
get(u1) # OK
Out[258]:
1
In [259]:
get(u2) # error - missing
LoadError: NullException()
while loading In[259], in expression starting on line 1

 in get(::Nullable{Int64}) at .\nullable.jl:62
In [260]:
isnull(u1) # false
Out[260]:
false
In [261]:
isnull(u2) # true
Out[261]:
true

Plotting

There are several plotting packages for Julia: Winston, Gadfly and PyPlot.

In [262]:
using Gadfly
srand(1) # second plot
x, y = randn(100), randn(100)
plot(x = x, y = y)
Out[262]:
x -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 -9.0 -8.8 -8.6 -8.4 -8.2 -8.0 -7.8 -7.6 -7.4 -7.2 -7.0 -6.8 -6.6 -6.4 -6.2 -6.0 -5.8 -5.6 -5.4 -5.2 -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 7.2 7.4 7.6 7.8 8.0 8.2 8.4 8.6 8.8 9.0 -10 -5 0 5 10 -9.0 -8.5 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 -9.0 -8.8 -8.6 -8.4 -8.2 -8.0 -7.8 -7.6 -7.4 -7.2 -7.0 -6.8 -6.6 -6.4 -6.2 -6.0 -5.8 -5.6 -5.4 -5.2 -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 7.2 7.4 7.6 7.8 8.0 8.2 8.4 8.6 8.8 9.0 -10 -5 0 5 10 -9.0 -8.5 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 y

Macros

You can define macros (see documentation for details). Useful standard macros.

Assertions:

In [263]:
@assert 1 == 2 "ERROR" # 2 macro arguments; error raised
LoadError: AssertionError: ERROR
while loading In[263], in expression starting on line 1
In [264]:
using Base.Test # load Base.Test module
@test 1 == 2 # similar to assert; error
Test Failed
  Expression: 1 == 2
   Evaluated: 1 == 2
LoadError: There was an error during testing
while loading In[264], in expression starting on line 2

 in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at .\test.jl:397
 in do_test(::Base.Test.Returned, ::Expr) at .\test.jl:281
In [265]:
@test_approx_eq 1 1.1 # error
LoadError: assertion failed: |1 - 1.1| <= 2.220446049250313e-12
  1 = 1
  1.1 = 1.1
  difference = 0.10000000000000009 > 2.220446049250313e-12
while loading In[265], in expression starting on line 1

 in error(::String, ::String, ::Vararg{Any,N}) at .\error.jl:22
 in test_approx_eq(::Int64, ::Float64, ::Float64, ::String, ::String) at .\test.jl:863
 in test_approx_eq(::Int64, ::Float64, ::String, ::String) at .\test.jl:873
In [266]:
@test_approx_eq_eps 1 1.1 0.2 # no error

Function vectorization:

In [267]:
t(x::Float64, y::Float64 = 1.0) = x * y
Out[267]:
t (generic function with 2 methods)
In [268]:
t(1.0, 2.0) # OK
Out[268]:
2.0
In [269]:
t([1.0 2.0]) # error
LoadError: MethodError: no method matching t(::Array{Float64,2})
Closest candidates are:
  t(!Matched::Float64, !Matched::Float64) at In[267]:1
  t(!Matched::Float64) at In[267]:1
while loading In[269], in expression starting on line 1
In [270]:
t.([1.0 2.0]) # OK
Out[270]:
1×2 Array{Float64,2}:
 1.0  2.0
In [271]:
t([1.0 2.0], 2.0) # error
LoadError: MethodError: no method matching t(::Array{Float64,2}, ::Float64)
Closest candidates are:
  t(!Matched::Float64, ::Float64) at In[267]:1
while loading In[271], in expression starting on line 1
In [272]:
t.([1.0 2.0], 2.0) # OK
Out[272]:
1×2 Array{Float64,2}:
 2.0  4.0
In [273]:
t.(2.0, [1.0 2.0]) # OK
Out[273]:
1×2 Array{Float64,2}:
 2.0  4.0

Benchmarking:

In [274]:
@time [x for x in 1:10^6].' # print time and memory
  0.054473 seconds (13.03 k allocations: 15.823 MB, 17.54% gc time)
Out[274]:
1×1000000 Array{Int64,2}:
 1  2  3  4  5  6  7  8  9  10  11  12  …  999997  999998  999999  1000000
In [275]:
@timed [x for x in 1:10^6].' # return value, time and memory
Out[275]:
(
[1 2 … 999999 1000000],

0.042444649,16591726,0.007871801,Base.GC_Diff(16591726,2,0,13028,0,0,7871801,1,0))
In [276]:
@elapsed [x for x in 1:10^6] # return time
Out[276]:
0.047802306
In [277]:
@allocated [x for x in 1:10^6] # return memory
Out[277]:
8000096
In [278]:
tic() # start timer
Out[278]:
0x0000795bf2c8904c
In [279]:
toc() # stop timer and print time
elapsed time: 0.259225911 seconds
Out[279]:
0.259225911
In [280]:
tic()
toq()
Out[280]:
0.000116633