When writing code in Julia, I use REPL console frequently, mainly to understand how some functions or some expressions works in Julia. I usually create something like dummy matrices and vectors, and test the function/expression using that dummies. Fortunately, Julia’s REPL console provides many useful tricks for exploring how it works.

### ?Help

Getting help on a function in Julia is easy, just type ? followed by the name of the function to show the manual. Here’s an example

help?> eig
Base.eig(A,[irange,][vl,][vu,][permute=true,][scale=true]) -> D, V
Computes eigenvalues and eigenvectors of "A". See "eigfact()"
for details on the "balance" keyword argument.
julia> eig([1.0 0.0 0.0; 0.0 3.0 0.0; 0.0 0.0 18.0])
([1.0,3.0,18.0],
3x3 Array{Float64,2}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0)
"eig" is a wrapper around "eigfact()", extracting all parts of
the factorization to a tuple; where possible, using "eigfact()"
is recommended.
Base.eig(A, B) -> D, V
Computes generalized eigenvalues and vectors of "A" with respect
to "B".
"eig" is a wrapper around "eigfact()", extracting all parts of
the factorization to a tuple; where possible, using "eigfact()"
is recommended.

### Who’s there?

Julia’s REPL provides the function `whos()`

to display all the variables (and functions) in the environment. Take a look on this example:

julia> a = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> f(x) = x^2
f (generic function with 1 method)
julia> whos()
Base Module
Core Module
Main Module
a 3-element Array{Int64,1}
ans Function
f Function

If we want to see all functions inside a module, we can use `whos(ModuleName)`

. Executing `whos(Core)`

will show all functions/variables inside the Core module.

julia> whos(Core)
=== Function
ANY TypeVar
ASCIIString DataType
AbstractArray DataType
Any DataType
Array DataType
Bool DataType
........

We can search for functions using Regex, for example if we want to see all function in Base containing the word with “inv”:

julia> whos(Base, r"inv"i)
erfcinv Function
erfinv Function
inv Function
invdigamma Function
invmod Function
invperm Function
pinv Function

### Methods

In Julia, function is a collection of methods. Similar with the concept of *polymorphism* in Object Oriented Programming, in Julia, there can be many functions (methods) with the same name, but with different *signature*. The choice of which method to execute when we call a function is called *dispatch*. In Julia, the choice is based on the number of arguments passed to the function, and on the type of all arguments. If there are more than one methods satisfy the requirement, the one with the more specific types will be called. Here’s an example:

julia> f(x) = println("General method is called")
f (generic function with 1 method)
julia> f(x::Number) = println("Method for handling number")
f (generic function with 2 methods)
julia> f(x::Float64) = println("Method for handling floating point")
f (generic function with 3 methods)
julia> f(1)
Method for handling number
julia> f(1.0)
Method for handling floating point
julia> f([1, 2])
General method is called

Note that `f(1.0)`

satisfy both `f(x::Number)`

and `f(x::Float64)`

, but the more specific method is called.

Julia provides `methods()`

function to show all methods in a function.

julia> methods(eye)
# 7 methods for generic function "eye":
eye{T}(::Type{Diagonal{T}},n::Int64) at linalg/diagonal.jl:95
eye(T::Type{T<:Top},m::Integer,n::Integer) at array.jl:176
eye(m::Integer,n::Integer) at array.jl:182
eye(T::Type{T<:Top},n::Integer) at array.jl:183
eye(n::Integer) at array.jl:184
eye(S::SparseMatrixCSC{Tv,Ti<:Integer}) at sparse/sparsematrix.jl:414
eye{T}(x::AbstractArray{T,2}) at array.jl:185

We can also show all methods that are applicable to a variable using `methodwith()`

function. For example to show all methods that accept a `Matrix`

variable:

julia> methodswith(Matrix)
67-element Array{Method,1}:
size(a::Array{T,2}) at array.jl:20
-(A::Array{T,2},B::Diagonal{T}) at linalg/special.jl:90
-(A::Array{T,2},B::Bidiagonal{T}) at linalg/special.jl:90
-(A::Array{T,2},B::Tridiagonal{T}) at linalg/special.jl:90
-(A::Array{T,2},B::Triangular{T,S<:AbstractArray{T,2},UpLo,IsUnit}) at linalg/special.jl:90
-(A::Array{T,2},B::SymTridiagonal{T}) at linalg/special.jl:99
..............

### Which one?

In order to see which method will be chosen when we execute a function or expression, we can use `@which`

macro.

julia> @which f(4.0)
f(x::Float64) at none:1
julia> @which 1 + 2
+(x::Int64,y::Int64) at int.jl:33
julia> @which 1.0 + 2
+(x::Number,y::Number) at promotion.jl:158
julia> @which rand(1, 2)
rand(dims::Int64...) at random.jl:123

### Types-hierarchy

Since understanding Types-hierarchy is very important in Julia (it’s a key to master methods), we might want to know functions related to Type. Some basic type functions are `subtypes()`

, `super()`

`typeof()`

, `isa()`

, and `issubtype()`

. Below are the examples:

julia> typeof(1.0)
Float64
julia> super(Float64)
FloatingPoint
julia> subtypes(Number)
2-element Array{Any,1}:
Complex{T<:Real}
Real
julia> subtypes(Real)
5-element Array{Any,1}:
FixedPoint
FloatingPoint
Integer
MathConst{sym}
Rational{T<:Integer}
julia> isa(1.0, Real)
true
julia> isa(1.0, Integer)
false
julia> isa(1.0, Number)
true
julia> issubtype(Integer, FloatingPoint)
false
julia> issubtype(Integer, Number)
true

Note that some types has alias, for example `Array`

data type which contains `Vector`

(1-d array), `Matrix`

(2-d array) and higher dimension Array.

julia> Vector
Array{T,1}
julia> Matrix
Array{T,2}

### Compiler’s mind

Julia has built-in functions to see how the compiler parse the source code and translate it to lower representations of the code. Four macros `@code_lowered`

, `@code_typed`

, `@code_llvm`

, and `@code_native`

can be used to show four different levels of representation of the code from the highest to the lowest level.

julia> @code_lowered 1.0 + 2.0 + 3
1-element Array{Any,1}:
:($(Expr(:lambda, {:a,:b,:c}, {{},{{:a,:Any,0},{:b,:Any,0},{:c,:Any,0}},{}}, :(begin # operators.jl, line 82:
return (a + b) + c
end))))
julia> @code_lowered 3 * 2.0 + 1
1-element Array{Any,1}:
:($(Expr(:lambda, {:x,:y}, {{},{{:x,:Any,0},{:y,:Any,0}},{}}, :(begin # promotion.jl, line 158:
return (top(apply))(+,promote(x,y))
end))))
julia> @code_typed 3 * 2.0 + 1
1-element Array{Any,1}:
:($(Expr(:lambda, {:x,:y}, {{},{{:x,Float64,0},{:y,Int64,0}},{}}, :(begin # promotion.jl, line 158:
return box(Float64,add_float(x::Float64,box(Float64,sitofp(Float64,y::Int64))::Float64))::Float64
end::Float64))))
julia> @code_llvm 3 * 2.0 + 1
define double @"julia_+_3232"(double, i64) {
top:
%2 = sitofp i64 %1 to double, !dbg !9747
%3 = fadd double %2, %0, !dbg !9747
ret double %3, !dbg !9747
}
julia> @code_native 3 * 2.0 + 1
.text
Filename: promotion.jl
Source line: 158
push RBP
mov RBP, RSP
Source line: 158
vcvtsi2sd XMM1, XMM0, RDX
vaddsd XMM0, XMM1, XMM0
pop RBP
ret