Functions

  • julia is a compiled language
  • code is never interpreted
  • everything is compiled using llvm

Defintion


In [1]:
function plus2(x)
    x + 2
end


Out[1]:
plus2 (generic function with 1 method)

In [11]:
function plus2(x)
    return x+2
end


Out[11]:
plus2 (generic function with 1 method)

In [3]:
f(x) = x + 2


Out[3]:
f (generic function with 1 method)

lambda functions


In [12]:
f = function (x) x + 2 end


Out[12]:
(::#1) (generic function with 1 method)

In [13]:
f = x -> x +2


Out[13]:
(::#3) (generic function with 1 method)

Naming


In [5]:
f(x) = 2*x


Out[5]:
f (generic function with 1 method)

In [7]:
ϕ(x) = 2*x


Out[7]:
ϕ (generic function with 1 method)

In [4]:
2f(x) = 2*x


syntax: "2" is not a valid function argument name

Chaining


In [17]:
π |> sin |> exp


Out[17]:
1.0000000000000002

In [18]:
(exp∘sin)(π)


Out[18]:
1.0000000000000002

Optional Arguments


In [17]:
function logly(x,y=10)
    log(y,x)
end


Out[17]:
logly (generic function with 2 methods)

In [19]:
logly(4,2)


Out[19]:
2.0

In [20]:
function logly(y=10,x)
    log(y,x)
end


syntax: optional positional arguments must occur at end

Keyword Arguments


In [1]:
function logly(x; base=10)
    log(base,x)
end


Out[1]:
logly (generic function with 1 method)

In [26]:
logly(10)


Out[26]:
1.0

In [27]:
logly(8,base=2)


Out[27]:
3.0

Types of Arguments


In [2]:
logly("breakme",base=10)


MethodError: no method matching log(::Int64, ::String)
Closest candidates are:
  log(::Real) at math.jl:421
  log(::T<:Number, ::T<:Number) where T<:Number at math.jl:159
  log(::Number, ::Number) at math.jl:187
  ...

Stacktrace:
 [1] (::#kw##logly)(::Array{Any,1}, ::#logly, ::String) at ./<missing>:0

In [7]:
workspace()

In [17]:
function logly(x::Real;base::Real=10)
    log(base,x)
end


Out[17]:
logly (generic function with 1 method)

In [18]:
logly("foo",10)


MethodError: no method matching logly(::String, ::Int64)

In [19]:
function logly(x::Real;base::Real=10)::Real
    log(base,x)
end


Out[19]:
logly (generic function with 1 method)

Argument Passing

  • immutable types
    • basic types e.g. int, float, bool,
    • cannot be changed
    • passed by value
  • mutable types
    • arrays, user defined types
    • can be changed
    • passed by refrence
    • function may modify them

Immutable


In [11]:
function thumbsUp(x)
    x += 1
end


Out[11]:
thumbsUp (generic function with 1 method)

In [12]:
x = 1;
thumbsUp(x)
x


Out[12]:
1

Mutable


In [16]:
function multiThumbsUp(x)
    x[:] += 1
end


Out[16]:
multiThumbsUp (generic function with 1 method)

In [18]:
multiThumbsUp([0 2 2 6])


Out[18]:
4-element Array{Int64,1}:
 1
 3
 3
 7

In [ ]:
# convention: name of functions modifying the input should end with !

Vectorization


In [38]:
f(x) = 2*sin(x)-2;

In [41]:
f.([1,2,3])


Out[41]:
3-element Array{Float64,1}:
 -0.317058
 -0.181405
 -1.71776 

Multiple Return Values


In [33]:
function duplicate(x)
    (x,x+1)
end


Out[33]:
duplicate (generic function with 1 method)

In [36]:
y,z = duplicate(1);z


Out[36]:
2

Multiple Dispatch


In [42]:
function f(x::Float64)
    1
end
function f(x::Int64)
    0
end


Out[42]:
f (generic function with 3 methods)

In [44]:
f(1)


Out[44]:
0

In [45]:
f(1.0)


Out[45]:
1

In [46]:
function f(x::Float64,y::Int64)
    x*y
end
function f(x::Int64,y::Float64)
    x+y
end


Out[46]:
f (generic function with 5 methods)

In [49]:
f(2.0,2)


Out[49]:
4.0

In [50]:
f(2,3.0)


Out[50]:
5.0

In [51]:
f(2.0,2.0)


MethodError: no method matching f(::Float64, ::Float64)
Closest candidates are:
  f(::Int64, ::Float64) at In[46]:5
  f(::Float64, ::Int64) at In[46]:2
  f(::Float64) at In[42]:2
  ...

Note

  • no need to write a function for all possible types
  • in general types may be omitted
  • optimized machine code is generate for each combination of input types whenever it is encountered

In [2]:
# example
h(x,y) = x*y+2


Out[2]:
h (generic function with 1 method)

In [3]:
@code_native h(1,2)


	.section	__TEXT,__text,regular,pure_instructions
Filename: In[1]
	pushq	%rbp
	movq	%rsp, %rbp
Source line: 1
	imulq	%rsi, %rdi
	leaq	2(%rdi), %rax
	popq	%rbp
	retq
	nop

In [4]:
@code_native h(1.0,2.0)


	.section	__TEXT,__text,regular,pure_instructions
Filename: In[1]
	pushq	%rbp
	movq	%rsp, %rbp
Source line: 1
	mulsd	%xmm1, %xmm0
	movabsq	$4739742496, %rax       ## imm = 0x11A82BB20
	addsd	(%rax), %xmm0
	popq	%rbp
	retq
	nopl	(%rax,%rax)

In [5]:
@code_native h(1.0,2)


	.section	__TEXT,__text,regular,pure_instructions
Filename: In[1]
	pushq	%rbp
	movq	%rsp, %rbp
Source line: 1
	xorps	%xmm1, %xmm1
	cvtsi2sdq	%rdi, %xmm1
	mulsd	%xmm1, %xmm0
	movabsq	$4739743136, %rax       ## imm = 0x11A82BDA0
	addsd	(%rax), %xmm0
	popq	%rbp
	retq

Important note: The compiled code does NOT perform any type checking!


In [3]:
# view type information extracted by compiler
@code_typed h(1.0,2)


Out[3]:
CodeInfo(:(begin 
        return (Base.add_float)((Base.mul_float)(x, (Base.sitofp)(Float64, y)::Float64)::Float64, (Base.sitofp)(Float64, 2)::Float64)::Float64
    end))=>Float64

In [6]:
code_native(h,(Float64,Int32))


	.section	__TEXT,__text,regular,pure_instructions
Filename: In[2]
	pushq	%rbp
	movq	%rsp, %rbp
Source line: 2
	xorps	%xmm1, %xmm1
	cvtsi2sdl	%edi, %xmm1
	mulsd	%xmm1, %xmm0
	movabsq	$4911194656, %rax       ## imm = 0x124BAE220
	addsd	(%rax), %xmm0
	popq	%rbp
	retq
	nop

In [10]:
code_native(h,(Int32,Int64))


	.section	__TEXT,__text,regular,pure_instructions
Filename: In[2]
	pushq	%rbp
	movq	%rsp, %rbp
Source line: 2
	movslq	%edi, %rax
	imulq	%rsi, %rax
	addq	$2, %rax
	popq	%rbp
	retq
	nopw	%cs:(%rax,%rax)

In [11]:
code_llvm(h,(Int32,Int64))


define i64 @julia_h_61157(i32, i64) #0 !dbg !5 {
top:
  %2 = sext i32 %0 to i64
  %3 = mul i64 %2, %1
  %4 = add i64 %3, 2
  ret i64 %4
}

Dispatch on Values


In [70]:
fv(x,::Val{true})  = x+2
fv(x,::Val{false}) = x-5


Out[70]:
fv (generic function with 2 methods)

In [74]:
fv(1,Val(true))


Out[74]:
3

In [76]:
fv(1,Val(false))


Out[76]:
-4

Exercises

Task 1

Write a function implementing the following map $$ \begin{align} f \colon &\mathbb{R} \to \mathbb{R}\\ & x \mapsto x^2 + \frac{\sin(x+13)}{x} \end{align} $$

Task 2

Create a function $g$ mapping a function $f: \mathbb{R} \to \mathbb{R}$ to the function $h(x) = |f(x)|$.

With f being the function of task 1, you should get g(f)(-1) = 0.46342708199956506

Task 3

One options to calculate the inverse of a real number $x$ is given by the recurrence relation.

$$ y_{k+1} = 2y_k - y_k^2 x $$

with sattisfies $y_{k+1} \to \frac{1}{x}$ for $k \to \infty$.

Create a function newtonInv calculating the inverse of a given value $x$ using this iterations. The arguments of the function should be

  • x (real number to be inverted)
  • y0 (starting value for iteration, optional, default: 0.1)
  • iterations (number of iterations to performed, optional, default: 10, keyword option)

Bonus Task: Modify the function such that it has an option "relTol" specifying a relative tolerance (default: 1e-8). Instead of performing a fixed amount of iterations, the modified function should iterate until the solution satisfies the given tolernace.

Task 4

Write a function crossSwap!(x,y) which exchanges x[1] with y[end] and x[end] with y[1].

Task 5

Create a function f(x,+/-1) mapping the interval [-1,1] to right(+1) respectively left part of the unit circle in the complex plane.

$$ \begin{align*} f(x, 1) = e^{ \pi i \frac{x}{2}}\\ f(x,-1) = e^{ \pi i (\frac{x}{2} + 1)} \end{align*} $$