SlideShare una empresa de Scribd logo
1 de 63
Descargar para leer sin conexión
ALL ABOUT...
FUNCTIONS
Created by Michal Bigos
(everywhere)@teliatko
AGENDA
Basic syntax
Arguments and parameters
Generic functions
Function as values
Closures
Partial application, curring and composition
Partial Functions
Syntactic sugar
Changes in Scala 2.12
BASIC SYNTAX
BASIC SYNTAX: PARAMETER TYPES & RESULT
TYPE
You must specify the types of all parameters.
def factorial(n: Long): Long = // expression or block
// non-recursive, result type is inferred
def factorial(n: Long) = {
var r = 1
for (i <- 1 to n) r = r * i
r
}
If the function is not recursive, you need not specify the
result type.
BASIC SYNTAX: EXPRESSIONS & BLOCKS
If the body of the function requires more than one
expression, use a block { }.
def factorial(n: Long) = { // more than 1 expresions
var r = 1L
for (i <- 1 to n) r = r * i
r // <-- last expression, compiler infers result type
}
The last expression of the block becomes the value that the
function returns.
BASIC SYNTAX: RECURSIVE FUNCTIONS
With a recursive function, you must specify the return type.
// recursive, result type has to be specified
def factorial(n: Long): Long = {
if (n <= 0) 1
else n * factorial(n - 1)
}
otherwise...
// same recursive function definition without return type
def factorial(n: Long) = // ...
<console>:14: error: recursive method factorial needs result type
else n * factorial(n - 1)
BASIC SYNTAX: RECURSIVE FUNCTIONS (2)
Almost each recursive function can be written as tail
recursive one.
// recusive, tail recursive
@scala.annotation.tailrec
def factorial(n: Long, acc: Long = 1): Long =
if (n <= 0) acc
else factorial(n - 1, n * acc)
Annotation @tailrec is not mandatory and just verifies
that the method will be compiled with tail call optimization.
<console>:15: error: could not optimize @tailrec annotated method factorial:
else n * factorial(n - 1)
ARGUMENTS & PARAMETERS
ARGS & PARAMS: PARAMETER LISTS
Function can have zero or more parameter lists.
def name: String = ...
def toString(): String = ...
def ifTrueDo(ex: Boolean)(code: => Unit): Unit = ...
Call side.
name
toString // parens can be ommited
toString()
ifTrue(true)( println("Moin") )
ARGS & PARAMS: DEFAULT AND NAMED
ARGUMENTS
You can provide default arguments for functions that are
used when you do not specify explicit values.
def show(value: String, left: String = "(", right: String = ")"): String
Call side.
// uses defaults for both parameters
show("Moin")
// sets left in order how args are defined, right is default
show("Moin", "{")
// sets only right as named argument
show("Moin", right = "}")
// named arguments need not be in the same order as the parameters
show(right = "}", left = "{", value = "Moin")
Named arguments can make a function call more readable.
ARGS & PARAMS: DEFAULT AND NAMED
ARGUMENTS (2)
Each parameter list can contain default arguments.
import Radix._ // imports type Radix and object Decimal
def add(n1: Long, rdx1: Radix = Decimal)(n2: Long, rdx2: Radix = Decimal
Default arguments can be intermixed with normal ones.
Normal ones still have to provided on call side.
def show(prefix: String = "(", value: String, sufix: String = ")"): String
show("Moin")
<console>:9: error: not enough arguments for method show: (prefix: String
Unspecified value parameter value.
// successful forces the user to use name arguments
show(value = "Moin")
Convention is to use default arguments in the end of
parameter list.
ARGS & PARAMS: DEFAULT ARGUMENTS
OVERLOADING
When function uses default arguments, it cannot be
overloaded with another function with default arguments.
def show(prefix: String = "(", value: String): String = ...
def show(value: Int, repeat: Int = 1): Int = ...
<console>:6: error: in object Shows, multiple overloaded alternatives
object Shows {
def show(value: Int, repeat: Int): Int = ... // compiles
ARGS & PARAMS: VARIABLE ARGUMENTS
Syntax for variable arguments. Use * behind type.
def sum(ns: Int*): Int = {
val _ns: Seq[Int] = ns // internaly it is Seq
...
}
Parameter allowing variable arguments has to be last one in
parameter list.
def sum(ns: Int*, n: Int): Int = ...
<console>:7: error: *-parameter must come last
def sum(ns: Int*, n: Int): Int = ...
ARGS & PARAMS: VARIABLE ARGUMENTS (2)
sum(0, 1, 2) // any number of arguments
sum() // even none
If you already have a sequence of values, you cannot pass it
directly to function with variable arguments.
val ns = Seq(0, 1, 2, 3, 4, 5)
sum(ns) // Seq cannot be used directly
<console>:10: error: type mismatch;
found : Seq[Int]
required: Int
sum(ns: _*) // successful
sum( (0 to 5): _* ) // successful
_* tells the compiler that you want the parameter to be
expanded as a sequence of arguments.
GENERIC FUNCTIONS
GENERIC FUNCTIONS: TYPE PARAMETERS
Functions like classes and traits can have type parameters.
def show[T](value: T): String = ...
def add[F, S, R](first: F, second: S): R = ...
There can be only one type parameter list for function.
GENERIC FUNCTIONS: TYPE PARAMETER
BOUNDS
Sometimes it is useful to place restrictions on function type
parameters.
def lessThan[T <: Comparable[T]](first: T, second: T): Boolean = {
first.compareTo(second) < 0
}
lessThan("Ahoi", "Moin")
<: is called upper bounds and means that T has to be a
subtype of Comparable[T].
GENERIC FUNCTIONS: TYPE PARAMETER
BOUNDS (2)
It is also possible to specify lower bounds.
Expressed as >: declare a type to be a supertype of another
type.
case class Node[+T](h: T, t: Node[T]) {
// work when Node is invariant
// def prepend(elem: T): Node[T] = Node(elem, this)
def prepend[U >: T](elem: U): Node[U] = Node(elem, this)
}
Typical usage is when type parameter of enclosing class is
covariant.
GENERIC FUNCTIONS: TYPE PARAMETER
BOUNDS (3)
It is possible to have both bounds for one type parameter.
T <: Upper >: Lower
But ... it is not possible to have multiple upper or lower
bounds.
It is still possible to require that type parameter implements
multiple traits.
T <: Comparable[T] with Serializable with Clonable
GENERIC FUNCTIONS: IMPLICIT PARAMETERS
Function can have parameter list marked as implicit.
sealed trait Affix
case class Prefix(value: String) extends Affix
case class Sufix(value: String) extends Affix
def show(value: String)(implicit prefix: Prefix, sufix: Sufix): String
Function can still be called with explicit arguments...
show("Moin")(Prefix("("), Sufix(")"))
GENERIC FUNCTIONS: IMPLICIT PARAMETERS
(2)
But the compiler can look for default values to supply with
the function call.
object Affixes {
implicit val prefix = Prefix("(")
implicit def sufix = Sufix(")")
}
import Affixes._ // i.e. import of implicit values
show("Moin")
Default value has to be val or def declared as implicit.
Usual implicits resolution mechanism is applied.
GENERIC FUNCTIONS: CONTEXT BOUNDS
For parameter list with 1 implicit parameter there is a
syntactic sugar called context bound.
// suppose that Prefix uses type parameter for value
case class Prefix[T](value: T) extends Affix
// generic definition of show will look like
def show[T](value: T)(implicit prefix: Prefix[T]): String = {
prefix.value // accessing implicit parameter, directly
...
}
// shorthand version defined via context bound
def show[T : Prefix](value: T): String = {
val prefix = implicitly[Prefix[T]] // retrieving implicit parameter
prefix.value // accessing implicit parameter
...
}
Context bound is important concept by encoding type
classes in scala.
GENERIC FUNCTIONS: CONTEXT BOUNDS (2)
You can define multiple contexts for one type parameter T.
case class Prefix[T](value: T) extends Affix
case class Sufix[T](value: T) extends Affix
def show[T : Prefix : Sufix](value: T): String = ...
def show[T <: Comparable[T] : Prefix : Sufix](value: T): String = ...
If more than 1 type parameter is required, context
bounds cannot be used.
case class Infix[T1, T2](left: T1, right: T2) extends Affix
// def show[T1, T2 : Infix] won't compile
def show[T1, T2](left: T1, right: T2)(implicit infix: Infix[T1, T2]):
GENERIC FUNCTIONS: TYPE CONSTRAINTS
Scala Predef defines type constraints. Purpose is to
contraint type parameters.
// usage
def show[T](value: T)(implicit ev: T =:= String): String = ...
// call side
show("Moin")
show(1)
<console>:17: error: Cannot prove that Int =:= String.
show(1)
A =:= B, which means A must be equal to B
A <:< B, which meand A must be subtype of B
FUNCTIONS AS VALUES
FUNCTIONS AS VALUES: FUNCTIONS AS
VALUES
Functions are "first-class citizens" in Scala.
You can:
call a function
store a function into the variable
pass a function into another function as an argument
FUNCTIONS AS VALUES: ANNONYMOUS
FUNCTIONS
Scala provides lightweight syntax for annonymous
functions.
(x: Int) => x + 1
It is called function literal.
val addOne = (x: Int) => x + 1 // assignment to variable
Just like numbers or strings have literals: 3 or "Moin",
functions have too.
FUNCTIONS AS VALUES: ANNONYMOUS
FUNCTIONS (2)
Behind the scenes, compiler will convert it into annonymous
class definition.
val addOne = new Function1[Int, Int] {
def apply(x: Int): Int = x + 1 // special rule for apply
}
addOne(2)
addOne.apply(2)
Provided are traits from Function0 until Function22.
// compiled into Function2[Int, String, String]
(x: Int, y: String) => x + "-" + y
// compiled into Function0[String]
() => "Moin"
FUNCTIONS AS VALUES: FUNCTIONS WITH
FUNCTIONS PARAMETERS
Functions can take other fuctions as parameters or return
them as results.
// function as parameter
def fiftyPercent(fn: Double => Double): Double = fn(0.5)
// function as result
def multiplyBy(factor: Int) = (x: Int) => x * factor
// supplying function as argument
fiftyPercent( (x: Double) => x * x )
val twice = multiplyBy(2) // assignment to variable
twice(2) // call
Such functions are called high-order functions.
Syntax Double => Double represents function
type which can be used as parameter type or result type.
FUNCTIONS AS VALUES: PARAMETER
INFERENCE
By passing annonymous function to another function, Scala
deduces types when possible.
def fiftyPercent(fn: Double => Double): Double = fn(0.5)
fiftyPercent( (x: Double) => x * x )
fiftyPercent( (x) => x * x ) // type is inferred to be Double
fiftyPercent( x => x * x ) // parens can be omitted
For function with 1 parameter it is possible to omit ().
FUNCTIONS AS VALUES: TYPE INFERENCE
High-order functions can use type parameters too.
def dropWhile[A](l: List[A], f: A => Boolean): List[A] = ...
val numbers = List(1, 2, 3)
dropWhile(numbers, (x: Int) => x < 2) // Int is required
Type parameters are inferred from le to right across
parameter lists.
def dropWhile[A](l: List[A])(f: A => Boolean): List[A] = ...
val numbers = List(1, 2, 3)
dropWhile(numbers, x => x < 2)
To help compiler use multiple parameter lists.
CLOSURES
CLOSURES
Scala allows you to define function inside any scope:
package, class, object or even in another function.
In body of function it is possible to access any variables from
an enclosing scope.
def show(items: List[String], sufix: String): String = {
// inner function, which accesses sufix from enclosing scope
def loop(items: List[String], buffer: StringBuilder) =
if (items.isEmpty) buffer
else {
buffer.append(head).append(sufix)
loop(items.tail, buffer)
}
loop(items, StringBuilder.newBuilder).toString
}
Such function which access variables from enclosing scope
is called closure.
CLOSURES (2)
Variables accesed from enclosing scope of closure are
called free variables.
def multiplyBy(factor: Int) = (x: Int) => x * factor
val doubled = multiplyBy(2)
val tripled = multiplyBy(3)
def calc(n: Int) = doubled(n) + tripled(n)
Free variables are bound lexically on call side.
PARTIAL APPLICATION, CURRYING
AND COMPOSITION
PARTIAL APPLICATION
Scala allow you to apply the functions partially. That
means applying some but not all the arguments of the
function.
// helper which applies A in any (A, B) => C function
def partial[A, B, C](a: A, fn: (A, B) => C): B => C =
(b: B) => fn(a, b)
val multiply = (x: Int, y: Int) => x * y
// partialy applied multiply, to always multiply by 2
val doubled = partial(2, multiply)
doubled: Int => Int = $$Lambda$1197/1032689422@2fac80a8
The process is called partial application and result
is partially applied function.
PARTIAL APPLICATION (2)
Partial application is so common, that Scala
dedicated syntax for that.
def divide(x: Int, y: Int): Int = x / y
val oneByN = divide(1, _: Int) // applying 1st argument
oneByN: Int => Int = $$Lambda$1336/1775639151@2696b687
val nBy100 = divide(_: Int, 100) // applying 2nd argument
nBy100: Int => Int = $$Lambda$1337/1973093841@ea45a5b
_: Type represents "hole", yet not applied argument.
PARTIAL APPLICATION (3)
Partial application also allows to obtain normally defined
function as value.
def divide(x: Int, y: Int): Int = x / y
// Not applying any of the arguments
val division = divide(_: Int, _: Int)
val division = divide _ // shorter way
Technically we are converting method into instance of
Function object.
CURRYING
Function with more parameters can be expressed as chain of
one-parameter functions and vice versa.
// helper which transforms (A, B) => C into A => B => C
def curry[A, B, C](fn : (A, B) => C): A => B => C =
(a: A) => (b: B) => fn(a, b)
// helper which transforms A => B => C into (A, B) => C
def uncurry[A, B, C](fn: A => B => C): (A, B) => C =
(a: A, b: B) => fn(a)(b)
val multiply = (x: Int, y: Int) => x * y
val multiplyChain = curry(multiply) // Int => Int => Int
val againMultiply = uncurry(multiplyChain)
multiplyChain(2)(3)
val doubled = multiplyChain(2) // partially applied function
CURRYING (2)
It can be useful in relation to partial application.
def divide(x: Int, y: Int): Int = x / y
val multiply = (x: Int, y: Int) => x * y
val oneByN = (divide _).curried(1) // divide(1, _: Int)
oneByN: Int => Int = $$Lambda$1336/1775639151@2696b687
val twice = multiply.curried(2) // multiply(2, _: Int)
twice: Int => Int = scala.Function2$$Lambda$1411/1255024717@236861da
curried is provided by all Function* traits.
COMPOSITION
Another very useful operation over functions is function
composition.
// helper which composes two functions
def compose[A, B, C](f: A => B, g: B => C): A => C =
(a: A) => g(f(a))
val addOne = (x: Int) => x + 1
val multiplyBy100 = (x: Int) => x * 100
val plus1Muliplied100 = compose(addOne, multiplyBy100)
It composes 2 functions A => B and B => C into A => B.
Types of the functions must be in alignment.
COMPOSITION (2)
Function composition is such a useful thing that, Scala
standard library provides methods for function composition.
val addOne = (x: Int) => x + 1
val multiplyBy100 = (x: Int) => x * 100
val plus1Muliplied100 = addOne.andThen(multiplyBy100)
val multiply100plus1 = addOne.compose(multiplyBy100)
They are only defined in trait Function1, thus function
with more parameters must be curried first.
PARTIAL FUNCTIONS
PARTIAL FUNCTIONS: CONCEPT
Concept comes from mathematics, where we talk about
total and partial functions.
// total function, defined for each Int
def addOne(i: Int) = i + 1
// partial function, undefined for 0
def divideOne(d: Int) = 1 / d
PARTIAL FUNCTIONS: DEFINITION
Set of case statements within { } is partial
function.
// another form of annonymous function
val divideOne: PartialFunction[Int, Int] = {
case d: Int if d != 0 => 42 / d
}
// it is translated into (more or less)
val divideOne = new PartialFunction[Int, Int] {
def apply(d: Int) = 1 / d
def isDefinedAt(d: Int) = d != 0
}
PartialFunction is trait which extends Function1
PARTIAL FUNCTIONS: USAGE
Usage and transformations.
val plusMinus: PartialFunction[Char, Int] = {
case '+' => 1
case '-' => -1
}
// application like total function
scala> plusMinus('+')
res15: Int = 1
scala> plusMinus('o') // undefined
scala.MatchError: o (of class java.lang.Character)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254)
// check if defined
scala> plusMinus.isDefinedAt('0')
res16: Boolean = false
PARTIAL FUNCTIONS: USAGE (2)
Usage (part 2)
// substitute undefined values
scala> plusMinus.applyOrElse('o', (_: Char) => 0)
res21: Int = 0
// conversion to total functions
scala> plusMinus.lift
res22: Char => Option[Int] = <function1>
PARTIAL FUNCTIONS: USAGE (3)
True benefit.
// supplying PartialFunction into call where Function1 is expected
someMap.foreach {
// ... destructuring for free
case (k, v) => println(k + " -> " + v)
}
case class Greeting(greeting: String)
List(Greeting("Moin"), Int).collect {
case Greeting(greeting) =>
println(greeting)
greeting
}
Pattern matching like casting-done-right, guards, and
destructuring for free.
SYNTACTIC SUGAR
SYNTACTIC SUGAR: CALL BY NAME
PAREMETERS
Sequence of statements can be modeled as function with no
parameters.
// code parameter has type `Function0`
def runInThread(code: () => Unit): Thead = {
...
code()
...
}
// you have to supply function () => Unit
runInThread(() => println("Moin"))
SYNTACTIC SUGAR: CALL BY NAME
PAREMETERS (2)
Usually parameters are called by value, i.e. value of the
parameter is evaluated before it is given to function.
// call by name parameter
def runInThread(code: => Unit): Thread = ...
// no need for ()
runInThread(println("Moin"))
=> before paremeter type says compiler that parameter is
called by name.
Its value is not evaluated before it is given to function. It is
considered lazy on call side.
SYNTACTIC SUGAR: CALL BY NAME
PAREMETERS (3)
Evaluation of call by name parameter happens
everytime the parameter is accessed.
def until(condition: => Boolean)(code: => Unit): Unit = {
while(!condition) { // evaluated by aech access
code // no parens necessary
}
}
var x = 0
until(x == 10)({ x += 1; println(x) }) // loop is terminated
SYNTACTIC SUGAR: CONTROL ABSTRACTIONS
Caller can use { } instead of ( ) for any parameter list
with just one parameter.
def until(condition: => Boolean)(code: => Unit): Unit = {
while(!condition) { // evaluated by aech access
code // no parens necessary
}
}
var x = 0
until (x == 10) {
x += 1
println(x)
}
until { x == 20 } { x += 1; println(x) }
This allows to write control abstractions, i. e.
functions which looks like build in language keywords.
SYNTACTIC SUGAR: CONTROL ABSTRACTIONS
(2)
Using return to return a value from an anonymous
function.
def indexOf(str: String, ch: Char): Int = {
var i = 0
until (i == str.length) { // closure
// will return from enclosing functions
if (str(i) == ch) return i
i += 1
}
return -1
}
indexOf("Moin", 'o')
res8: Int = 1
SYNTACTIC SUGAR: CONTROL ABSTRACTIONS
(3)
Use return judiciously.
If it is used in a named function it has to provide result type.
scala> def show(value: String, sufix: String = "") = { return value + sufix }
<console>:11: error: method show has return statement; needs result type
def show(value: String, sufix: String = "") = { return value + sufix }
Very fragile construct.
// return expression is captured and not evaluated
def somewhereDeepInTheCodebase: () => Int = () => return () => 1
// passed thru a lot of code
val x = somewhereDeepInTheCodebase
// finally used
x()
scala.runtime.NonLocalReturnControl // !!! RESULT !!!
// Btw. NonLocalReturnControl extends NoStackTrace
// i.e. so you are given no clue about origin.
CHANGES IN SCALA 2.12
Taken from official .release notes
SCALA 2.12: FUNCTION LITERALS
Type checker accepts a function literal as a valid expression
for any Single Abstract Method (SAM) type
scala> val r: Runnable = () => println("Run!")
r: Runnable = $$Lambda$1073/754978432@7cf283e1
scala> r.run()
SCALA 2.12: FUNCTION LITERALS (2)
Only lambda expressions are converted to SAM type
instances, not arbitrary expressions of FunctionN.
scala> val f = () => println("Faster!")
scala> val fasterRunnable: Runnable = f
<console>:12: error: type mismatch;
found : () => Unit
required: Runnable
SCALA 2.12: FUNCTION LITERALS (2)
Scala's built-in FunctionN traits are compiled to SAM
interfaces.
scala> val addOne = (n: Int) => n + 1
addOne: Int => Int = $$Lambda$1342/671078904@642c6461
scala> val addTwo = (n: Int) => n + 3
addTwo: Int => Int = $$Lambda$1343/205988608@5f6494c0
scala> addOne andThen addTwo
res14: Int => Int = scala.Function1$$Lambda$1335/1630903943@464aeb09
SCALA 2.12: PARAMETER INFERENCE
The parameter type in a lambda expression can be omitted
even when the invoked method is overloaded.
scala> trait MyFun { def apply(x: Int): String }
scala> object T {
| def m(f: Int => String) = 0
| def m(f: MyFun) = 1
| }
scala> T.m(x => x.toString)
res0: Int = 0
Note that though both methods are applicable, overloading
resolution selects the one with the Function1 argument
type.
SCALA 2.12: BREAKING CHANGES
Overloading resolution has been adapted to prefer methods
with Function-typed arguments over methods with
parameters of SAM types.
scala> object T {
| def m(f: () => Unit) = 0
| def m(r: Runnable) = 1
| }
scala> val f = () => ()
scala> T.m(f)
res0: Int = 0
In Scala 2.11, the first alternative was chosen because it is
the only applicable.
In Scala 2.12, both methods are applicable, but most specific
alternative is picked.
SCALA 2.12: BREAKING CHANGES
SAM conversion precedes implicits.
trait MySam { def i(): Int }
implicit def convert(fun: () => Int): MySam = new MySam { def i() = 1 }
val sam1: MySam = () => 2 // Uses SAM conversion, not the implicit
sam1.i() // Returns 2
Note that SAM conversion only applies to lambda
expressions, not to arbitrary expressions with Scala
FunctionN types
val fun = () => 2 // Type Function0[Int]
val sam2: MySam = fun // Uses implicit conversion
sam2.i() // Returns 1
THANK YOU

Más contenido relacionado

La actualidad más candente

python Function
python Function python Function
python Function Ronak Rathi
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()daewon jeong
 
handling input output and control statements
 handling input output and control statements handling input output and control statements
handling input output and control statementsRai University
 
Functions in C++
Functions in C++Functions in C++
Functions in C++home
 
Diploma ii cfpc u-4 function, storage class and array and strings
Diploma ii  cfpc u-4 function, storage class and array and stringsDiploma ii  cfpc u-4 function, storage class and array and strings
Diploma ii cfpc u-4 function, storage class and array and stringsRai University
 
Dti2143 chapter 5
Dti2143 chapter 5Dti2143 chapter 5
Dti2143 chapter 5alish sha
 
Functions in python slide share
Functions in python slide shareFunctions in python slide share
Functions in python slide shareDevashish Kumar
 
User defined functions in C programmig
User defined functions in C programmigUser defined functions in C programmig
User defined functions in C programmigAppili Vamsi Krishna
 
Btech i pic u-4 function, storage class and array and strings
Btech i pic u-4 function, storage class and array and stringsBtech i pic u-4 function, storage class and array and strings
Btech i pic u-4 function, storage class and array and stringsRai University
 
Functions torage class and array and strings-
Functions torage class and array and strings-Functions torage class and array and strings-
Functions torage class and array and strings-aneebkmct
 
Functions in python
Functions in pythonFunctions in python
Functions in pythoncolorsof
 
Mcai pic u 4 function, storage class and array and strings
Mcai pic u 4 function, storage class and array and stringsMcai pic u 4 function, storage class and array and strings
Mcai pic u 4 function, storage class and array and stringsRai University
 
12 computer science_notes_ch01_overview_of_cpp
12 computer science_notes_ch01_overview_of_cpp12 computer science_notes_ch01_overview_of_cpp
12 computer science_notes_ch01_overview_of_cppsharvivek
 

La actualidad más candente (20)

python Function
python Function python Function
python Function
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()
 
Functions in C
Functions in CFunctions in C
Functions in C
 
handling input output and control statements
 handling input output and control statements handling input output and control statements
handling input output and control statements
 
C++ theory
C++ theoryC++ theory
C++ theory
 
Functions in C++
Functions in C++Functions in C++
Functions in C++
 
Diploma ii cfpc u-4 function, storage class and array and strings
Diploma ii  cfpc u-4 function, storage class and array and stringsDiploma ii  cfpc u-4 function, storage class and array and strings
Diploma ii cfpc u-4 function, storage class and array and strings
 
Dti2143 chapter 5
Dti2143 chapter 5Dti2143 chapter 5
Dti2143 chapter 5
 
Recursion in c
Recursion in cRecursion in c
Recursion in c
 
Functions in python slide share
Functions in python slide shareFunctions in python slide share
Functions in python slide share
 
User defined functions in C programmig
User defined functions in C programmigUser defined functions in C programmig
User defined functions in C programmig
 
Btech i pic u-4 function, storage class and array and strings
Btech i pic u-4 function, storage class and array and stringsBtech i pic u-4 function, storage class and array and strings
Btech i pic u-4 function, storage class and array and strings
 
Functions torage class and array and strings-
Functions torage class and array and strings-Functions torage class and array and strings-
Functions torage class and array and strings-
 
C Theory
C TheoryC Theory
C Theory
 
Python functions
Python functionsPython functions
Python functions
 
C Programming Unit-3
C Programming Unit-3C Programming Unit-3
C Programming Unit-3
 
Functions in python
Functions in pythonFunctions in python
Functions in python
 
Mcai pic u 4 function, storage class and array and strings
Mcai pic u 4 function, storage class and array and stringsMcai pic u 4 function, storage class and array and strings
Mcai pic u 4 function, storage class and array and strings
 
Savitch Ch 17
Savitch Ch 17Savitch Ch 17
Savitch Ch 17
 
12 computer science_notes_ch01_overview_of_cpp
12 computer science_notes_ch01_overview_of_cpp12 computer science_notes_ch01_overview_of_cpp
12 computer science_notes_ch01_overview_of_cpp
 

Similar a All About ... Functions

Functions in C++
Functions in C++Functions in C++
Functions in C++home
 
functioninpython-1.pptx
functioninpython-1.pptxfunctioninpython-1.pptx
functioninpython-1.pptxSulekhJangra
 
User defined function in C.pptx
User defined function in C.pptxUser defined function in C.pptx
User defined function in C.pptxRhishav Poudyal
 
Python functions part12
Python functions  part12Python functions  part12
Python functions part12Vishal Dutt
 
functions modules and exceptions handlings.ppt
functions modules and exceptions handlings.pptfunctions modules and exceptions handlings.ppt
functions modules and exceptions handlings.pptRajasekhar364622
 
Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0Sheik Uduman Ali
 
04_python_functions.ppt You can define functions to provide the required func...
04_python_functions.ppt You can define functions to provide the required func...04_python_functions.ppt You can define functions to provide the required func...
04_python_functions.ppt You can define functions to provide the required func...anaveenkumar4
 
C language presentation
C language presentationC language presentation
C language presentationbainspreet
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala Knoldus Inc.
 
Python programming - Functions and list and tuples
Python programming - Functions and list and tuplesPython programming - Functions and list and tuples
Python programming - Functions and list and tuplesMalligaarjunanN
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming iiPrashant Kalkar
 

Similar a All About ... Functions (20)

Functions in C++
Functions in C++Functions in C++
Functions in C++
 
Python Functions.pptx
Python Functions.pptxPython Functions.pptx
Python Functions.pptx
 
Python Functions.pptx
Python Functions.pptxPython Functions.pptx
Python Functions.pptx
 
functioninpython-1.pptx
functioninpython-1.pptxfunctioninpython-1.pptx
functioninpython-1.pptx
 
functions- best.pdf
functions- best.pdffunctions- best.pdf
functions- best.pdf
 
User defined function in C.pptx
User defined function in C.pptxUser defined function in C.pptx
User defined function in C.pptx
 
Python functions part12
Python functions  part12Python functions  part12
Python functions part12
 
User Defined Functions
User Defined FunctionsUser Defined Functions
User Defined Functions
 
functions modules and exceptions handlings.ppt
functions modules and exceptions handlings.pptfunctions modules and exceptions handlings.ppt
functions modules and exceptions handlings.ppt
 
Functions
FunctionsFunctions
Functions
 
Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0Let Us Learn Lambda Using C# 3.0
Let Us Learn Lambda Using C# 3.0
 
04_python_functions.ppt You can define functions to provide the required func...
04_python_functions.ppt You can define functions to provide the required func...04_python_functions.ppt You can define functions to provide the required func...
04_python_functions.ppt You can define functions to provide the required func...
 
functions.pptx
functions.pptxfunctions.pptx
functions.pptx
 
C language presentation
C language presentationC language presentation
C language presentation
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Functions in C++
Functions in C++Functions in C++
Functions in C++
 
Python programming - Functions and list and tuples
Python programming - Functions and list and tuplesPython programming - Functions and list and tuples
Python programming - Functions and list and tuples
 
Scala functions
Scala functionsScala functions
Scala functions
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
functions
functionsfunctions
functions
 

Más de Michal Bigos

Scala eXchange 2013 Report
Scala eXchange 2013 ReportScala eXchange 2013 Report
Scala eXchange 2013 ReportMichal Bigos
 
Functional Domain Modeling
Functional Domain ModelingFunctional Domain Modeling
Functional Domain ModelingMichal Bigos
 
Dependency injection in scala
Dependency injection in scalaDependency injection in scala
Dependency injection in scalaMichal Bigos
 
Option, Either, Try and what to do with corner cases when they arise
Option, Either, Try and what to do with corner cases when they ariseOption, Either, Try and what to do with corner cases when they arise
Option, Either, Try and what to do with corner cases when they ariseMichal Bigos
 
Integration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDBIntegration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDBMichal Bigos
 

Más de Michal Bigos (6)

Scala eXchange 2013 Report
Scala eXchange 2013 ReportScala eXchange 2013 Report
Scala eXchange 2013 Report
 
Functional Domain Modeling
Functional Domain ModelingFunctional Domain Modeling
Functional Domain Modeling
 
SBT Crash Course
SBT Crash CourseSBT Crash Course
SBT Crash Course
 
Dependency injection in scala
Dependency injection in scalaDependency injection in scala
Dependency injection in scala
 
Option, Either, Try and what to do with corner cases when they arise
Option, Either, Try and what to do with corner cases when they ariseOption, Either, Try and what to do with corner cases when they arise
Option, Either, Try and what to do with corner cases when they arise
 
Integration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDBIntegration Testing With ScalaTest and MongoDB
Integration Testing With ScalaTest and MongoDB
 

Último

SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 

Último (20)

SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 

All About ... Functions

  • 1. ALL ABOUT... FUNCTIONS Created by Michal Bigos (everywhere)@teliatko
  • 2. AGENDA Basic syntax Arguments and parameters Generic functions Function as values Closures Partial application, curring and composition Partial Functions Syntactic sugar Changes in Scala 2.12
  • 4. BASIC SYNTAX: PARAMETER TYPES & RESULT TYPE You must specify the types of all parameters. def factorial(n: Long): Long = // expression or block // non-recursive, result type is inferred def factorial(n: Long) = { var r = 1 for (i <- 1 to n) r = r * i r } If the function is not recursive, you need not specify the result type.
  • 5. BASIC SYNTAX: EXPRESSIONS & BLOCKS If the body of the function requires more than one expression, use a block { }. def factorial(n: Long) = { // more than 1 expresions var r = 1L for (i <- 1 to n) r = r * i r // <-- last expression, compiler infers result type } The last expression of the block becomes the value that the function returns.
  • 6. BASIC SYNTAX: RECURSIVE FUNCTIONS With a recursive function, you must specify the return type. // recursive, result type has to be specified def factorial(n: Long): Long = { if (n <= 0) 1 else n * factorial(n - 1) } otherwise... // same recursive function definition without return type def factorial(n: Long) = // ... <console>:14: error: recursive method factorial needs result type else n * factorial(n - 1)
  • 7. BASIC SYNTAX: RECURSIVE FUNCTIONS (2) Almost each recursive function can be written as tail recursive one. // recusive, tail recursive @scala.annotation.tailrec def factorial(n: Long, acc: Long = 1): Long = if (n <= 0) acc else factorial(n - 1, n * acc) Annotation @tailrec is not mandatory and just verifies that the method will be compiled with tail call optimization. <console>:15: error: could not optimize @tailrec annotated method factorial: else n * factorial(n - 1)
  • 9. ARGS & PARAMS: PARAMETER LISTS Function can have zero or more parameter lists. def name: String = ... def toString(): String = ... def ifTrueDo(ex: Boolean)(code: => Unit): Unit = ... Call side. name toString // parens can be ommited toString() ifTrue(true)( println("Moin") )
  • 10. ARGS & PARAMS: DEFAULT AND NAMED ARGUMENTS You can provide default arguments for functions that are used when you do not specify explicit values. def show(value: String, left: String = "(", right: String = ")"): String Call side. // uses defaults for both parameters show("Moin") // sets left in order how args are defined, right is default show("Moin", "{") // sets only right as named argument show("Moin", right = "}") // named arguments need not be in the same order as the parameters show(right = "}", left = "{", value = "Moin") Named arguments can make a function call more readable.
  • 11. ARGS & PARAMS: DEFAULT AND NAMED ARGUMENTS (2) Each parameter list can contain default arguments. import Radix._ // imports type Radix and object Decimal def add(n1: Long, rdx1: Radix = Decimal)(n2: Long, rdx2: Radix = Decimal Default arguments can be intermixed with normal ones. Normal ones still have to provided on call side. def show(prefix: String = "(", value: String, sufix: String = ")"): String show("Moin") <console>:9: error: not enough arguments for method show: (prefix: String Unspecified value parameter value. // successful forces the user to use name arguments show(value = "Moin") Convention is to use default arguments in the end of parameter list.
  • 12. ARGS & PARAMS: DEFAULT ARGUMENTS OVERLOADING When function uses default arguments, it cannot be overloaded with another function with default arguments. def show(prefix: String = "(", value: String): String = ... def show(value: Int, repeat: Int = 1): Int = ... <console>:6: error: in object Shows, multiple overloaded alternatives object Shows { def show(value: Int, repeat: Int): Int = ... // compiles
  • 13. ARGS & PARAMS: VARIABLE ARGUMENTS Syntax for variable arguments. Use * behind type. def sum(ns: Int*): Int = { val _ns: Seq[Int] = ns // internaly it is Seq ... } Parameter allowing variable arguments has to be last one in parameter list. def sum(ns: Int*, n: Int): Int = ... <console>:7: error: *-parameter must come last def sum(ns: Int*, n: Int): Int = ...
  • 14. ARGS & PARAMS: VARIABLE ARGUMENTS (2) sum(0, 1, 2) // any number of arguments sum() // even none If you already have a sequence of values, you cannot pass it directly to function with variable arguments. val ns = Seq(0, 1, 2, 3, 4, 5) sum(ns) // Seq cannot be used directly <console>:10: error: type mismatch; found : Seq[Int] required: Int sum(ns: _*) // successful sum( (0 to 5): _* ) // successful _* tells the compiler that you want the parameter to be expanded as a sequence of arguments.
  • 16. GENERIC FUNCTIONS: TYPE PARAMETERS Functions like classes and traits can have type parameters. def show[T](value: T): String = ... def add[F, S, R](first: F, second: S): R = ... There can be only one type parameter list for function.
  • 17. GENERIC FUNCTIONS: TYPE PARAMETER BOUNDS Sometimes it is useful to place restrictions on function type parameters. def lessThan[T <: Comparable[T]](first: T, second: T): Boolean = { first.compareTo(second) < 0 } lessThan("Ahoi", "Moin") <: is called upper bounds and means that T has to be a subtype of Comparable[T].
  • 18. GENERIC FUNCTIONS: TYPE PARAMETER BOUNDS (2) It is also possible to specify lower bounds. Expressed as >: declare a type to be a supertype of another type. case class Node[+T](h: T, t: Node[T]) { // work when Node is invariant // def prepend(elem: T): Node[T] = Node(elem, this) def prepend[U >: T](elem: U): Node[U] = Node(elem, this) } Typical usage is when type parameter of enclosing class is covariant.
  • 19. GENERIC FUNCTIONS: TYPE PARAMETER BOUNDS (3) It is possible to have both bounds for one type parameter. T <: Upper >: Lower But ... it is not possible to have multiple upper or lower bounds. It is still possible to require that type parameter implements multiple traits. T <: Comparable[T] with Serializable with Clonable
  • 20. GENERIC FUNCTIONS: IMPLICIT PARAMETERS Function can have parameter list marked as implicit. sealed trait Affix case class Prefix(value: String) extends Affix case class Sufix(value: String) extends Affix def show(value: String)(implicit prefix: Prefix, sufix: Sufix): String Function can still be called with explicit arguments... show("Moin")(Prefix("("), Sufix(")"))
  • 21. GENERIC FUNCTIONS: IMPLICIT PARAMETERS (2) But the compiler can look for default values to supply with the function call. object Affixes { implicit val prefix = Prefix("(") implicit def sufix = Sufix(")") } import Affixes._ // i.e. import of implicit values show("Moin") Default value has to be val or def declared as implicit. Usual implicits resolution mechanism is applied.
  • 22. GENERIC FUNCTIONS: CONTEXT BOUNDS For parameter list with 1 implicit parameter there is a syntactic sugar called context bound. // suppose that Prefix uses type parameter for value case class Prefix[T](value: T) extends Affix // generic definition of show will look like def show[T](value: T)(implicit prefix: Prefix[T]): String = { prefix.value // accessing implicit parameter, directly ... } // shorthand version defined via context bound def show[T : Prefix](value: T): String = { val prefix = implicitly[Prefix[T]] // retrieving implicit parameter prefix.value // accessing implicit parameter ... } Context bound is important concept by encoding type classes in scala.
  • 23. GENERIC FUNCTIONS: CONTEXT BOUNDS (2) You can define multiple contexts for one type parameter T. case class Prefix[T](value: T) extends Affix case class Sufix[T](value: T) extends Affix def show[T : Prefix : Sufix](value: T): String = ... def show[T <: Comparable[T] : Prefix : Sufix](value: T): String = ... If more than 1 type parameter is required, context bounds cannot be used. case class Infix[T1, T2](left: T1, right: T2) extends Affix // def show[T1, T2 : Infix] won't compile def show[T1, T2](left: T1, right: T2)(implicit infix: Infix[T1, T2]):
  • 24. GENERIC FUNCTIONS: TYPE CONSTRAINTS Scala Predef defines type constraints. Purpose is to contraint type parameters. // usage def show[T](value: T)(implicit ev: T =:= String): String = ... // call side show("Moin") show(1) <console>:17: error: Cannot prove that Int =:= String. show(1) A =:= B, which means A must be equal to B A <:< B, which meand A must be subtype of B
  • 26. FUNCTIONS AS VALUES: FUNCTIONS AS VALUES Functions are "first-class citizens" in Scala. You can: call a function store a function into the variable pass a function into another function as an argument
  • 27. FUNCTIONS AS VALUES: ANNONYMOUS FUNCTIONS Scala provides lightweight syntax for annonymous functions. (x: Int) => x + 1 It is called function literal. val addOne = (x: Int) => x + 1 // assignment to variable Just like numbers or strings have literals: 3 or "Moin", functions have too.
  • 28. FUNCTIONS AS VALUES: ANNONYMOUS FUNCTIONS (2) Behind the scenes, compiler will convert it into annonymous class definition. val addOne = new Function1[Int, Int] { def apply(x: Int): Int = x + 1 // special rule for apply } addOne(2) addOne.apply(2) Provided are traits from Function0 until Function22. // compiled into Function2[Int, String, String] (x: Int, y: String) => x + "-" + y // compiled into Function0[String] () => "Moin"
  • 29. FUNCTIONS AS VALUES: FUNCTIONS WITH FUNCTIONS PARAMETERS Functions can take other fuctions as parameters or return them as results. // function as parameter def fiftyPercent(fn: Double => Double): Double = fn(0.5) // function as result def multiplyBy(factor: Int) = (x: Int) => x * factor // supplying function as argument fiftyPercent( (x: Double) => x * x ) val twice = multiplyBy(2) // assignment to variable twice(2) // call Such functions are called high-order functions. Syntax Double => Double represents function type which can be used as parameter type or result type.
  • 30. FUNCTIONS AS VALUES: PARAMETER INFERENCE By passing annonymous function to another function, Scala deduces types when possible. def fiftyPercent(fn: Double => Double): Double = fn(0.5) fiftyPercent( (x: Double) => x * x ) fiftyPercent( (x) => x * x ) // type is inferred to be Double fiftyPercent( x => x * x ) // parens can be omitted For function with 1 parameter it is possible to omit ().
  • 31. FUNCTIONS AS VALUES: TYPE INFERENCE High-order functions can use type parameters too. def dropWhile[A](l: List[A], f: A => Boolean): List[A] = ... val numbers = List(1, 2, 3) dropWhile(numbers, (x: Int) => x < 2) // Int is required Type parameters are inferred from le to right across parameter lists. def dropWhile[A](l: List[A])(f: A => Boolean): List[A] = ... val numbers = List(1, 2, 3) dropWhile(numbers, x => x < 2) To help compiler use multiple parameter lists.
  • 33. CLOSURES Scala allows you to define function inside any scope: package, class, object or even in another function. In body of function it is possible to access any variables from an enclosing scope. def show(items: List[String], sufix: String): String = { // inner function, which accesses sufix from enclosing scope def loop(items: List[String], buffer: StringBuilder) = if (items.isEmpty) buffer else { buffer.append(head).append(sufix) loop(items.tail, buffer) } loop(items, StringBuilder.newBuilder).toString } Such function which access variables from enclosing scope is called closure.
  • 34. CLOSURES (2) Variables accesed from enclosing scope of closure are called free variables. def multiplyBy(factor: Int) = (x: Int) => x * factor val doubled = multiplyBy(2) val tripled = multiplyBy(3) def calc(n: Int) = doubled(n) + tripled(n) Free variables are bound lexically on call side.
  • 36. PARTIAL APPLICATION Scala allow you to apply the functions partially. That means applying some but not all the arguments of the function. // helper which applies A in any (A, B) => C function def partial[A, B, C](a: A, fn: (A, B) => C): B => C = (b: B) => fn(a, b) val multiply = (x: Int, y: Int) => x * y // partialy applied multiply, to always multiply by 2 val doubled = partial(2, multiply) doubled: Int => Int = $$Lambda$1197/1032689422@2fac80a8 The process is called partial application and result is partially applied function.
  • 37. PARTIAL APPLICATION (2) Partial application is so common, that Scala dedicated syntax for that. def divide(x: Int, y: Int): Int = x / y val oneByN = divide(1, _: Int) // applying 1st argument oneByN: Int => Int = $$Lambda$1336/1775639151@2696b687 val nBy100 = divide(_: Int, 100) // applying 2nd argument nBy100: Int => Int = $$Lambda$1337/1973093841@ea45a5b _: Type represents "hole", yet not applied argument.
  • 38. PARTIAL APPLICATION (3) Partial application also allows to obtain normally defined function as value. def divide(x: Int, y: Int): Int = x / y // Not applying any of the arguments val division = divide(_: Int, _: Int) val division = divide _ // shorter way Technically we are converting method into instance of Function object.
  • 39. CURRYING Function with more parameters can be expressed as chain of one-parameter functions and vice versa. // helper which transforms (A, B) => C into A => B => C def curry[A, B, C](fn : (A, B) => C): A => B => C = (a: A) => (b: B) => fn(a, b) // helper which transforms A => B => C into (A, B) => C def uncurry[A, B, C](fn: A => B => C): (A, B) => C = (a: A, b: B) => fn(a)(b) val multiply = (x: Int, y: Int) => x * y val multiplyChain = curry(multiply) // Int => Int => Int val againMultiply = uncurry(multiplyChain) multiplyChain(2)(3) val doubled = multiplyChain(2) // partially applied function
  • 40. CURRYING (2) It can be useful in relation to partial application. def divide(x: Int, y: Int): Int = x / y val multiply = (x: Int, y: Int) => x * y val oneByN = (divide _).curried(1) // divide(1, _: Int) oneByN: Int => Int = $$Lambda$1336/1775639151@2696b687 val twice = multiply.curried(2) // multiply(2, _: Int) twice: Int => Int = scala.Function2$$Lambda$1411/1255024717@236861da curried is provided by all Function* traits.
  • 41. COMPOSITION Another very useful operation over functions is function composition. // helper which composes two functions def compose[A, B, C](f: A => B, g: B => C): A => C = (a: A) => g(f(a)) val addOne = (x: Int) => x + 1 val multiplyBy100 = (x: Int) => x * 100 val plus1Muliplied100 = compose(addOne, multiplyBy100) It composes 2 functions A => B and B => C into A => B. Types of the functions must be in alignment.
  • 42. COMPOSITION (2) Function composition is such a useful thing that, Scala standard library provides methods for function composition. val addOne = (x: Int) => x + 1 val multiplyBy100 = (x: Int) => x * 100 val plus1Muliplied100 = addOne.andThen(multiplyBy100) val multiply100plus1 = addOne.compose(multiplyBy100) They are only defined in trait Function1, thus function with more parameters must be curried first.
  • 44. PARTIAL FUNCTIONS: CONCEPT Concept comes from mathematics, where we talk about total and partial functions. // total function, defined for each Int def addOne(i: Int) = i + 1 // partial function, undefined for 0 def divideOne(d: Int) = 1 / d
  • 45. PARTIAL FUNCTIONS: DEFINITION Set of case statements within { } is partial function. // another form of annonymous function val divideOne: PartialFunction[Int, Int] = { case d: Int if d != 0 => 42 / d } // it is translated into (more or less) val divideOne = new PartialFunction[Int, Int] { def apply(d: Int) = 1 / d def isDefinedAt(d: Int) = d != 0 } PartialFunction is trait which extends Function1
  • 46. PARTIAL FUNCTIONS: USAGE Usage and transformations. val plusMinus: PartialFunction[Char, Int] = { case '+' => 1 case '-' => -1 } // application like total function scala> plusMinus('+') res15: Int = 1 scala> plusMinus('o') // undefined scala.MatchError: o (of class java.lang.Character) at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254) // check if defined scala> plusMinus.isDefinedAt('0') res16: Boolean = false
  • 47. PARTIAL FUNCTIONS: USAGE (2) Usage (part 2) // substitute undefined values scala> plusMinus.applyOrElse('o', (_: Char) => 0) res21: Int = 0 // conversion to total functions scala> plusMinus.lift res22: Char => Option[Int] = <function1>
  • 48. PARTIAL FUNCTIONS: USAGE (3) True benefit. // supplying PartialFunction into call where Function1 is expected someMap.foreach { // ... destructuring for free case (k, v) => println(k + " -> " + v) } case class Greeting(greeting: String) List(Greeting("Moin"), Int).collect { case Greeting(greeting) => println(greeting) greeting } Pattern matching like casting-done-right, guards, and destructuring for free.
  • 50. SYNTACTIC SUGAR: CALL BY NAME PAREMETERS Sequence of statements can be modeled as function with no parameters. // code parameter has type `Function0` def runInThread(code: () => Unit): Thead = { ... code() ... } // you have to supply function () => Unit runInThread(() => println("Moin"))
  • 51. SYNTACTIC SUGAR: CALL BY NAME PAREMETERS (2) Usually parameters are called by value, i.e. value of the parameter is evaluated before it is given to function. // call by name parameter def runInThread(code: => Unit): Thread = ... // no need for () runInThread(println("Moin")) => before paremeter type says compiler that parameter is called by name. Its value is not evaluated before it is given to function. It is considered lazy on call side.
  • 52. SYNTACTIC SUGAR: CALL BY NAME PAREMETERS (3) Evaluation of call by name parameter happens everytime the parameter is accessed. def until(condition: => Boolean)(code: => Unit): Unit = { while(!condition) { // evaluated by aech access code // no parens necessary } } var x = 0 until(x == 10)({ x += 1; println(x) }) // loop is terminated
  • 53. SYNTACTIC SUGAR: CONTROL ABSTRACTIONS Caller can use { } instead of ( ) for any parameter list with just one parameter. def until(condition: => Boolean)(code: => Unit): Unit = { while(!condition) { // evaluated by aech access code // no parens necessary } } var x = 0 until (x == 10) { x += 1 println(x) } until { x == 20 } { x += 1; println(x) } This allows to write control abstractions, i. e. functions which looks like build in language keywords.
  • 54. SYNTACTIC SUGAR: CONTROL ABSTRACTIONS (2) Using return to return a value from an anonymous function. def indexOf(str: String, ch: Char): Int = { var i = 0 until (i == str.length) { // closure // will return from enclosing functions if (str(i) == ch) return i i += 1 } return -1 } indexOf("Moin", 'o') res8: Int = 1
  • 55. SYNTACTIC SUGAR: CONTROL ABSTRACTIONS (3) Use return judiciously. If it is used in a named function it has to provide result type. scala> def show(value: String, sufix: String = "") = { return value + sufix } <console>:11: error: method show has return statement; needs result type def show(value: String, sufix: String = "") = { return value + sufix } Very fragile construct. // return expression is captured and not evaluated def somewhereDeepInTheCodebase: () => Int = () => return () => 1 // passed thru a lot of code val x = somewhereDeepInTheCodebase // finally used x() scala.runtime.NonLocalReturnControl // !!! RESULT !!! // Btw. NonLocalReturnControl extends NoStackTrace // i.e. so you are given no clue about origin.
  • 56. CHANGES IN SCALA 2.12 Taken from official .release notes
  • 57. SCALA 2.12: FUNCTION LITERALS Type checker accepts a function literal as a valid expression for any Single Abstract Method (SAM) type scala> val r: Runnable = () => println("Run!") r: Runnable = $$Lambda$1073/754978432@7cf283e1 scala> r.run()
  • 58. SCALA 2.12: FUNCTION LITERALS (2) Only lambda expressions are converted to SAM type instances, not arbitrary expressions of FunctionN. scala> val f = () => println("Faster!") scala> val fasterRunnable: Runnable = f <console>:12: error: type mismatch; found : () => Unit required: Runnable
  • 59. SCALA 2.12: FUNCTION LITERALS (2) Scala's built-in FunctionN traits are compiled to SAM interfaces. scala> val addOne = (n: Int) => n + 1 addOne: Int => Int = $$Lambda$1342/671078904@642c6461 scala> val addTwo = (n: Int) => n + 3 addTwo: Int => Int = $$Lambda$1343/205988608@5f6494c0 scala> addOne andThen addTwo res14: Int => Int = scala.Function1$$Lambda$1335/1630903943@464aeb09
  • 60. SCALA 2.12: PARAMETER INFERENCE The parameter type in a lambda expression can be omitted even when the invoked method is overloaded. scala> trait MyFun { def apply(x: Int): String } scala> object T { | def m(f: Int => String) = 0 | def m(f: MyFun) = 1 | } scala> T.m(x => x.toString) res0: Int = 0 Note that though both methods are applicable, overloading resolution selects the one with the Function1 argument type.
  • 61. SCALA 2.12: BREAKING CHANGES Overloading resolution has been adapted to prefer methods with Function-typed arguments over methods with parameters of SAM types. scala> object T { | def m(f: () => Unit) = 0 | def m(r: Runnable) = 1 | } scala> val f = () => () scala> T.m(f) res0: Int = 0 In Scala 2.11, the first alternative was chosen because it is the only applicable. In Scala 2.12, both methods are applicable, but most specific alternative is picked.
  • 62. SCALA 2.12: BREAKING CHANGES SAM conversion precedes implicits. trait MySam { def i(): Int } implicit def convert(fun: () => Int): MySam = new MySam { def i() = 1 } val sam1: MySam = () => 2 // Uses SAM conversion, not the implicit sam1.i() // Returns 2 Note that SAM conversion only applies to lambda expressions, not to arbitrary expressions with Scala FunctionN types val fun = () => 2 // Type Function0[Int] val sam2: MySam = fun // Uses implicit conversion sam2.i() // Returns 1