C/CPS 506
Comparative Programming Languages Prof. Alex Ufkes
Topic 4: Functions & control flow in Elixir
Notice!
Obligatory copyright notice in the age of digital delivery and online classrooms:
The copyright to this original work is held by Alex Ufkes. Students registered in course C/CPS 506 can use this material for the purposes of this course but no other use is permitted, and there can be no sale or transfer or use of the work for any other purpose without explicit permission of Alex Ufkes.
Alex Ufkes, 2020, 2021 2
Course Administration
Alex Ufkes, 2020, 2021
3
Lab 3 description is posted
Assignment description and tester for Smalltalk is posted If you liked Smalltalk, you can start working on the Smalltalk version.
Today
Alex Ufkes, 2020, 2021
4
Continuing Elixir:
Basic types, lists and tuples
Function and module basics
Named and anonymous functions
Elixir Syntax: Basic Types
Typing literals into the shell will echo them back, assuming they are valid.
Decimal, binary, octal, and hexadecimal integers
Alex Ufkes, 2020, 2021 5
Elixir Syntax: Basic Types
Typing literals into the shell will echo them back, assuming they are valid.
More accurately:
Alex Ufkes, 2020, 2021
6
Everything in Elixir is an expression, even single literals. Evaluating a literal simply results in that value.
In the interactive shell, the return value is printed for us. :ok is the return value of IO.puts. The actual printing to the screen is a side effect!
Elixir Syntax: Basic Types
Alex Ufkes, 2020, 2021
7
Floating point, Boolean, strings
Floating Point
Floating point numbers in Elixir are 64-bit, double precision
Elixir supports scientific notation
Rounding and truncate functions
Alex Ufkes, 2020, 2021
8
Floating Point
Floating point numbers in Elixir are 64-bit, double precision
Notice:
We can omit parentheses around function arguments.
Multiple arguments are still separated by commas.
Alex Ufkes, 2020, 2021 9
Boolean
Comparison operator works the way were used to
We can check if a value is Boolean using the is_boolean function
Alex Ufkes, 2020, 2021
10
Types, Values, Truthiness
In Elixir we have Boolean values true and false. Not all languages have a Boolean type.
C does not have a Boolean type. It still supports Boolean expressions, of course. In C, numeric 0 is considered False, and everything else is considered True.
In Java, we have Boolean. Logical operators are only valid with Boolean operands.
Elixir complicates things by combining both approaches:
We have Boolean True and False, but values of every other type are considered either true or false.
Alex Ufkes, 2020, 2021 11
Boolean:
true, false
Boolean Expressions
With these operators:
non-false and non-nil are true.
nil and false are false.
0 is considered true!
iex> gh && false Except
Alex Ufkes, 2020, 2021
12
false
iex> gh || false
The result isnt true or false Its the value that decided the result of true or false
gh
&&, ||, !
What we get is the value that determined the truthiness of the expression
Test Type
Elixir is dynamically typed!
Type errors occur at run-time, not at compile time.
I.e., attempting some operation on incompatible types
results in a run-time error.
A static type system catches type errors at compile time
Alex Ufkes, 2020, 2021
13
Basic Arithmetic
Addition, multiplication
Division:
Notice 5.0, despite integer operands
/ operator returns floating point in Elixir
Alex Ufkes, 2020, 2021
14
Basic Arithmetic
div and rem functions
div:
Result of integer division
Like / in Java
rem:
Remainderoperator
Requiresintegerarguments
Alex Ufkes, 2020, 2021
15
Precedence?
Its fairly typical:
https://hexdocs.pm/elixir/master/operators.html
Alex Ufkes, 2020, 2021 16
div and rem are functions:
Elixir allows us to drop the brackets
Even with multiple arguments.
Can make precedence hard to decipher.
Alex Ufkes, 2020, 2021
17
Likewise for round and trunc and is_boolean
Function Arity
Elixir functions are described in terms of their name and arity? Arity refers to the number of arguments a function takes
Elixir functions are commonly described by the following notation: name/arity
Alex Ufkes, 2020, 2021
18
round/1
rem/2
trunc/1
div/2
is_boolean/1
This is not language syntax, just a documentation style.
Alex Ufkes, 2020, 2021 19
More Types: Atoms
Atoms:
A constant whose name is its value:
iex> :hello
:hello
iex> :world
:world
iex> :hello == :world
false
Boolean literals are Atoms:
iex> :true == true
true
iex> :false == false
true
iex> is_boolean(:false)
true
Alex Ufkes, 2020, 2021
20
Elixir atoms are the equivalent of Smalltalk symbols. Atoms with same value exist only once in memory.
More Types: Strings
Can have line breaks in them:
iex> Hello,
> World!
Hello,
World!
iex> Hello,
World
Hello,
World
We can use IO.puts/1 to print a string:
iex> IO.puts Hello
World!
Hello
World! :ok
IO.puts/1 returns the atom :ok after printing
Alex Ufkes, 2020, 2021
21
Newline is evaluated when we use the puts function.
Strings in Elixir are represented by sequences of bytes.
However. Unicode characters beyond 255 require two bytes to represent:
iex> byte_size Hello 5
iex> byte_size Hello 6
iex> String.length Hello 5
More Types: Strings Unicode: length VS number of bytes
Use String.length/1 to find the number of characters.
Alex Ufkes, 2020, 2021
22
More Types: Strings Interpolation, concatenation
iex> name = Alex
Alex
iex> Hello, #{name}! Hello, Alex!
iex> name = Alex
Alex
iex> Hello, <> name Hello, Alex
Alex Ufkes, 2020, 2021
23
Interpolation
Concatenation
Type Summary
Integer:
+, -, *, /
div/2, rem/2
>, >=, <, <=, ==, != 2, -7, 0x1F, 0o777, 0b10101Float: 2.0, 1.1e-3, 3.14e7Boolean:true, falseAtom: :Hello, :world, :false, :trueString: Hello, World!, 123, tr
ue Alex Ufkes, 2020, 2021 24Concatenation <>, interpolation #{}
Collections: Lists
Use [ ] to define a list of values.
Like Smalltalk, values can be anything (heterogeneous).
Operating on lists is central in functional languages
iex> [1, 2, true, 3, false]
[1, 2, true, 3, false]
iex> length [1, 2, 3] 3
Lists are implemented in Elixir as linked lists.
Use length/1 to print the number of items in the list.
Alex Ufkes, 2020, 2021
25
Lists are implemented in Elixir as linked lists. Heads Tails
iex> list = [1, 3.14, true, Hello, :World]
[1, 3.14, true, Hello, :World]
iex> hd list 1
iex> tl list
[3.14, true, Hello, :World]
Return first element of list
Return all but first element of a list
Alex Ufkes, 2020, 2021 26
Lists are implemented in Elixir as linked lists. Heads Tails
iex(30)> hd [1] 1
iex(31)> tl [1] []
Alex Ufkes, 2020, 2021
27
List Concatenation & Subtraction
iex> list = [1, 2, true, :Hello, World, false, 5] [1, 2, true, :Hello, World, false, 5]
iex> list [true, false]
[1, 2, :Hello, World, 5]
iex> list ++ [6]
[1, 2, true, :Hello, World, false, 5, 6]
iex> list [:Hello, abcd]
[1, 2, true, World, false, 5]
Safe to attempt removal of an item not in the list!
Alex Ufkes, 2020, 2021 28
Huh?
Alex Ufkes, 2020, 2021
29
iex> [104, 101, 108, 108, 111] hello
When the Erlang shell sees a list of printable Unicode values, it displays them as a list of characters.
Collections: Tuples
A sequence of values whose elements are stored contiguously in memory
iex> tup = {1, 2, :three} {1, 2, :three}
iex> elem tup, 0
1
iex> elem tup, 1
2
iex> elem tup, 2
:three
iex> elem tup, 3
** (ArgumentError) argument error
:erlang.element(4, {1, 2, :three})
This means we can directly access individual elements using elem/2:
Alex Ufkes, 2020, 2021 30
Lists & Tuples are Immutable Operations result in new lists/tuples:
iex> tup
{1, 2, :three}
iex> put_elem(tup, 1, 55)
{1, 55, :three}
iex> tup
{1, 2, :three}
Bind a new label (or re-bind tuple) to save the result.
tup = put_elem(tuple, 1, 55)
put_elem/3 returned a different tuple. The original hasnt changed.
Alex Ufkes, 2020, 2021
31
put_elem/3 to change an element
Elixir Variables are Immutable
When we say: x=1
The value 1 is created in memory xis a label for the value 1
If we then say: x=2
We are NOT changing the value 1 in memory.
We are creating the value 2 at a different place in memory
xis now a label for the value 2
This is called re-binding.
We change the label, not the value.
Alex Ufkes, 2020, 2021
32
Elixir Variables are Immutable x=1
x=2
12
Alex Ufkes, 2020, 2021
33
Elixir Variables are Immutable x=1
x=2
12
Garbage:
Alex Ufkes, 2020, 2021
34
Elixir Variables are Immutable
In imperative languages, variables can be thought of as containers.
We can put whatever we want into the container (if the type
system allows it, of course)
Reassigning a variable means mutating the value in the container
In Elixir and other functional languages, variables are labels.
We can change the value that we apply the label to, but we cant
change the value itself.
Alex Ufkes, 2020, 2021 35
Lists or Tuples?
Lists in Elixir are linked lists:
Linear time to access and append, constant time to pre-pend
Use to store a collection of values
Tuples are contiguous:
Constant time to access, linear time to update
Use when size and contents are fixed at compile time.
Not meant to be iterated over, direct element access only.
Both are immutable, updating creates new list/tuple. However:
If we change one element in a 10-element tuple, we dont
actually duplicate values for the 9 unchanged elements.
Behind the scenes, elements can be shared.
Alex Ufkes, 2020, 2021 36
Lists or Tuples?
Alex Ufkes, 2020, 2021
37
Just like Python:
Fixed, small number of elements, need fast random access? Use a tuple.
Large number of elements, changing in size over time, dont need random access? Use a list.
Always keep in mind the cost of operations on arrays VS linked lists (C/CPS305)
Functions
Alex Ufkes, 2020, 2021
38
Alex Ufkes, 2020, 2021
39
Recall: First Class VS Higher Order
Higher Order functions
Can accept a first-class functions as an arguments
Can return a first-class function
First Class functions
Can be passed to higher order functions as arguments Can be returned from higher order functions
Named Functions Defined within a module
Alex Ufkes, 2020, 2021
40
Modules can contain multiple functions
Modules can be compiled independently, making functions available for later use.
Named functions are not first class!
o Cannot be passed as arguments, cannot be returned Named functions of same name can have different arity, unlike anonymous functions (coming up)
Modules and Named Functions
Module name:
defmodule Greeter do def hello(name) do
Hello, <> name
end
end
Alex Ufkes, 2020, 2021 41
Function name and argument list
Function expressions
Erlang bytecode
Alex Ufkes, 2020, 2021 42
In a script file (.exs)
Alex Ufkes, 2020, 2021 43
Named Functions
Named functions (and modules) can be defined in a script, but then we cant use them later (without including their source code)
Alex Ufkes, 2020, 2021
44
Named functions (and modules) can be defined in a script, but then we cant use them later (without including their source code)
Define Greeter module in the file Greeter.ex
Compile it with elixirc:
Alex Ufkes, 2020, 2021 45
As long as the script is in the same folder, we can invoke functions from Greeter:
Alex Ufkes, 2020, 2021 46
Private Functions, Default Arguments
Private function:
Can only be invoked inside Greeter module
defmodule Greeter do
defp hello(), do: Hello
def greet(name \ Bill), do: hello() <> name
end
Default argument:
If no argument is provided, name will be Bill
Alex Ufkes, 2020, 2021 47
Alex Ufkes, 2020, 2021 48
Return Values
We dont have an imperative-style return statement in Elixir
The result of the final expression is returned.
Four expressions
defmodule Silly do def print() do
Hello ,
World!
end end
IO.puts Silly.print() World!
Alex Ufkes, 2020, 2021
49
Overloading
Alex Ufkes, 2020, 2021 50
Multiple Modules
Alex Ufkes, 2020, 2021
51
Anonymous Functions
Can be created live, inline:
iex> add = fn a, b -> a + b end
Anonymous functions can still be named.
They are first class
Can be passed to another
function and invoked there.
Function parameters
Alex Ufkes, 2020, 2021 52
Function behavior
Anonymous Functions
Invoke using the dot operator:
iex> add = fn (a, b) -> a + b end #Function<12.99386804/2 in :erl_eval.expr/5>
iex> add.(1, 2) 3
iex> add.(8, 9)
17
Arguments are passed in the usual manner
Cant use this syntax with anonymous functions:
iex> add 8, 9
** (CompileError) iex:8: undefined function add/2
Alex Ufkes, 2020, 2021 53
Shorthand
Alex Ufkes, 2020, 2021
54
iex> add = &(&1 + &2) &:erlang.+/2
iex> add.(3, 4) 7
iex> add.(8, -4)
4
Function Composition
(Maybe) not the most readable
Alex Ufkes, 2020, 2021
55
Function Composition
The pipe operator:
x = inc.(inc.(inc.(inc.(0))))
Can be written as:
x = 0 |> inc.() |> inc.() |> inc.() |> inc.()
Result becomes first argument of next function call
Very useful with Enums and Streams (next class)
Alex Ufkes, 2020, 2021
56
Higher Order & First Class Functions
Higher order functions:
Functions that return functions or accept them as arguments
Named functions are higher order in Elixir
First class functions:
First class functions can be passed as arguments into other functions
Anonymous functions are first class in Elixir
Alex Ufkes, 2020, 2021 57
Higher Order & First Class Functions
A function accepting a function as an argument?
defmodule UserMath do
def hof(val, func) do
func.(val)
end end
Two arguments:
A numeric value and a function
(Or so our function assumes)
Invoke func with val as argument
If func is not actually a function?
We will get a run-time type error
if/when we try to use it as such.
Alex Ufkes, 2020, 2021
58
Higher Order & First Class Functions
A function accepting a function as an argument?
defmodule UserMath do
def hof(val, func) do
func.(val)
end end
Anonymous function to do some operation
Recall only anonymous functions can be args
Alex Ufkes, 2020, 2021 59
Pass value 8 and function sq to hof
Same Thing?
No! the result of pow() is passed as an argument, not the function itself.
Are we not passing a function to another function here?
Alex Ufkes, 2020, 2021 60
In Summary:
Alex Ufkes, 2020, 2021
61
Continuing Elixir:
Lists and tuples
Function and module basics
Named and anonymous functions
Alex Ufkes, 2020, 2021 62
Reviews
There are no reviews yet.