SlideShare une entreprise Scribd logo
1  sur  91
Télécharger pour lire hors ligne
1
Julien Truffaut
Backend Scala developer for 10+ years
FP instructor at fp-tower.com
Co-founder of scalajobs.com
2
Implicit parameters
def newBlogPost(title: String)(implicit author: User): BlogPost
class UserService(db: Connection)(implicit ec: ExecutionContext) {}
3
Implicit parameters
def newBlogPost(title: String)(implicit author: User): BlogPost
class UserService(db: Connection)(implicit ec: ExecutionContext) {}
When should we define a parameter as implicit?
4
Parameters definition
Explicit
def fullName(firstName: String, lastName: String): String =
s"$firstName $lastName"
fullName("John", "Doe")
// res0: String = "John Doe"
5
Parameters definition
Explicit
def fullName(firstName: String, lastName: String): String =
s"$firstName $lastName"
fullName("John", "Doe")
// res0: String = "John Doe"
fullName(lastName = "Smith", firstName = "Bob")
// res1: String = "Bob Smith"
6
Austria
sealed abstract class AcademicTitle(val shortForm: String)
case object MasterOfScience extends AcademicTitle("MSc")
case object Magistrate extends AcademicTitle("Mag")
...
7
Austria
sealed abstract class AcademicTitle(val shortForm: String)
case object MasterOfScience extends AcademicTitle("MSc")
case object Magistrate extends AcademicTitle("Mag")
...
def fullName(firstName: String, lastName: String, title: Option[AcademicTitle]): String = {
val suffix = title.map(" " + _.shortForm).getOrElse("")
s"${firstName} ${lastName}${suffix}"
}
fullName("John", "Doe", None)
// res: String = "John Doe"
fullName("Bob", "Smith", Some(MasterOfScience))
// res: String = "Bob Smith MSc"
8
Parameters definition
Default value
def fullName(firstName: String, lastName: String, title: Option[AcademicTitle] = None): String = {
val suffix = title.map(" " + _.shortForm).getOrElse("")
s"${firstName} ${lastName}${suffix}"
}
fullName("John", "Doe")
// res: String = "John Doe"
fullName("Bob", "Smith", Some(MasterOfScience))
// res: String = "Bob Smith MSc"
9
Parameters definition
Default value
def kafkaListener(
topic : String,
bootstrapServers : String,
commitTimeout : FiniteDuration = 50.millis,
pollInterval : FiniteDuration = 15.millis,
autoOffsetReset : AutoOffsetReset = AutoOffsetReset.Latest,
)
10
Parameters definition
Default value
def kafkaListener(
topic : String,
bootstrapServers : String,
commitTimeout : FiniteDuration = 50.millis,
pollInterval : FiniteDuration = 15.millis,
autoOffsetReset : AutoOffsetReset = AutoOffsetReset.Latest,
)
Similar options: Overloads or Builder Pattern
11
Parameters definition
Implicit
case class BlogPost(
author : UserId,
title : String,
content : String,
)
case class UserId(value: String)
12
Parameters definition
Implicit
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = ""
)
13
Parameters definition
Implicit
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = ""
)
createEmptyBlogPost("Scala Implicits: The complete guide")(UserId("john_1234")) // Explicit call
// res: BlogPost = BlogPost(
// author = UserId("john_1234"),
// title = "Scala Implicits: The complete guide",
// content = "",
// )
14
Parameters definition
Implicit
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = ""
)
createEmptyBlogPost("Scala Implicits: The complete guide") // Implicit call
// res: BlogPost = BlogPost(
// author = UserId("john_1234"),
// title = "Scala Implicits: The complete guide",
// content = "",
// )
15
Implicit resolution
val ImplicitValues: Map[Type, Value] = // Maintained by the compiler
Map(
Int -> 5,
String -> "",
UserId -> UserId("john_1234"),
)
createEmptyBlogPost("Scala Implicits: The complete guide") // user code
16
Implicit resolution
val ImplicitValues: Map[Type, Value] = // Maintained by the compiler
Map(
Int -> 5,
String -> "",
UserId -> UserId("john_1234"),
)
createEmptyBlogPost("Scala Implicits: The complete guide") // user code
|
v
createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time
17
Implicit resolution
val ImplicitValues: Map[Type, Value] = // Maintained by the compiler
Map(
Int -> 5,
String -> "",
UserId -> UserId("john_1234"),
)
createEmptyBlogPost("Scala Implicits: The complete guide") // user code
|
v
createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time
18
Implicit resolution
val ImplicitValues: Map[Type, Value] = // Maintained by the compiler
Map(
Int -> 5,
String -> "",
UserId -> UserId("john_1234"),
)
createEmptyBlogPost("Scala Implicits: The complete guide") // user code
|
v
createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time
|
v
createEmptyBlogPost("Scala Implicits: The complete guide")(UserId("john_1234"))
19
Implicit resolution
val ImplicitValues: Map[Type, Value] = // Maintained by the compiler
Map(
Int -> 5,
String -> "",
// No UserId
)
createEmptyBlogPost("Scala Implicits: The complete guide") // user code
|
v
createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time
|
v
???
20
Implicit resolution
val ImplicitValues: Map[Type, Value] = // Maintained by the compiler
Map(
Int -> 5,
String -> "",
// No UserId
)
createEmptyBlogPost("Scala Implicits: The complete guide") // user code
|
v
createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time
|
v
error: could not find implicit value for parameter requesterId: UserId // compile-time error
21
Implicit Definition
implicit val requesterId: UserId = UserId("john_1234")
createEmptyBlogPost("Scala Implicits: The complete guide")
// res: BlogPost = BlogPost(
// author = UserId("john_1234"),
// title = "Scala Implicits: The complete guide",
// content = "",
// )
22
Implicit Scope
class BlogPostTest extends AnyFunSuite {
test("createEmptyBlogPost gets the author implicitly") {
implicit val requesterId: UserId = UserId("john_1234")
val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile
assert(result.author == requesterId)
}
test("createEmptyBlogPost has no content") {
val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ❌ could not find implicit value
assert(result.content.isEmpty)
}
}
23
Implicit Scope
class BlogPostTest extends AnyFunSuite {
test("createEmptyBlogPost gets the author implicitly") {
implicit val requesterId: UserId = UserId("john_1234")
val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile
assert(result.author == requesterId)
}
test("createEmptyBlogPost has no content") {
val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ❌ could not find implicit value
assert(result.content.isEmpty)
}
}
24
Implicit Scope
class BlogPostTest extends AnyFunSuite {
implicit val requesterId: UserId = UserId("john_1234")
test("createEmptyBlogPost gets the author implicitly") {
val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile
assert(result.author == requesterId)
}
test("createEmptyBlogPost has no content") {
val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile
assert(result.content.isEmpty)
}
}
25
Summary
1. The compiler keeps track of all the implicits available within a scope
2. At compile-time, the compiler injects all implicit parameters
3. If an implicit is missing, we get a compiled-time error
26
Summary
1. The compiler keeps track of all the implicits available within a scope
2. At compile-time, the compiler injects all implicit parameters
3. If an implicit is missing, we get a compiled-time error
4. If there are 2 or more implicit values of the same type in scope, we also
get a compiled-time error
27
Within a Scope, there must be Only One implicit value per Type
28
Environment Pattern
29
Environment Pattern
val httpService = {
case req @ POST -> Root / "blog" => // create a blog
case req @ PUT -> Root / "blog" / id => // update a blog
case req @ DELETE -> Root / "blog" / id => // delete a blog
}
30
Environment Pattern
case req @ POST -> Root / "blog" =>
implicit val requesterId: UserId = extractRequesterId(req)
for {
payload <- req.parseBodyAs[NewBlog]
_ <- blogAPI.create(payload.title)
} yield Ok()
31
Environment Pattern
case req @ POST -> Root / "blog" =>
implicit val requesterId: UserId = extractRequesterId(req)
for {
payload <- req.parseBodyAs[NewBlog]
_ <- blogAPI.create(payload.title)
} yield Ok()
32
Environment Pattern
case req @ POST -> Root / "blog" =>
implicit val requesterId: UserId = extractRequesterId(req)
for {
payload <- req.parseBodyAs[NewBlog]
_ <- blogAPI.create(payload.title)
} yield Ok()
class BlogAPI(db: DB) {
def create(title: String)(implicit requesterId: UserId): Future[Unit] = {
val newBlog = createEmptyBlogPost(title)
db.save(newBlog)
}
}
33
Environment Pattern
case req @ POST -> Root / "blog" =>
implicit val requesterId: UserId = extractRequesterId(req)
for {
payload <- req.parseBodyAs[NewBlog]
_ <- blogAPI.create(payload.title)
} yield Ok()
class BlogAPI(db: DB) {
def create(title: String)(implicit requesterId: UserId): Future[Unit] = {
val newBlog = createEmptyBlogPost(title)
db.save(newBlog)
}
}
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = "",
)
34
Environment Pattern
case req @ POST -> Root / "blog" =>
implicit val requesterId: UserId = extractRequesterId(req)
for {
payload <- req.parseBodyAs[NewBlog]
_ <- blogAPI.create(payload.title)
} yield Ok()
class BlogAPI(db: DB) {
def create(title: String)(implicit requesterId: UserId): Future[Unit] = {
val newBlog = createEmptyBlogPost(title)
db.save(newBlog)
}
}
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = "",
)
35
Environment Pattern
case class BlogPost(
author : UserId,
title : String,
content : String,
createAt: Instant,
)
36
Environment Pattern
case class BlogPost(
author : UserId,
title : String,
content : String,
createAt: Instant,
)
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = "",
createAt = Instant.now(),
)
37
Environment Pattern
test("create blog post") {
implicit val requesterId: UserId = UserId("john_1234")
val result = createEmptyBlogPost("Test")
assert(result == BlogPost(requesterId, "Test", "", ???))
}
38
Environment Pattern
trait Clock {
def now(): Instant
}
39
Environment Pattern
trait Clock {
def now(): Instant
}
object Clock {
val real: Clock = new Clock {
def now(): Instant = Instant.now()
}
def static(timestamp: Instant): Clock = new Clock {
def now(): Instant = timestamp
}
}
40
Environment Pattern
trait Clock {
def now(): Instant
}
object Clock {
val real: Clock = new Clock {
def now(): Instant = Instant.now()
}
def static(timestamp: Instant): Clock = new Clock {
def now(): Instant = timestamp
}
}
41
Environment Pattern
def createEmptyBlogPost(title: String)(implicit requesterId: UserId, clock: Clock): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = "",
createAt = clock.now(),
)
42
Environment Pattern
def createEmptyBlogPost(title: String)(implicit requesterId: UserId, clock: Clock): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = "",
createAt = clock.now(),
)
object Main extends App {
implicit val clock: Clock = Clock.real
...
}
class BlogPostTest extends AnyFunSuite {
implicit val clock: Clock = Clock.static(Instant.EPOCH)
...
}
43
Environment Pattern
object Main extends App {
implicit val ec: ExecutionContext = ExecutionContext.global
...
}
class BlogDatabaseTest extends AnyFunSuite {
implicit val ec: ExecutionContext = fixedSizeExecutionContext(1)
...
}
44
Environment parameters are Static in a given Context
45
Context: Per request
RequesterId
TraceId
Context: Prod / Test
Clock
ExecutionContext (for Future)
RandomGenerator
46
Advice
1. Use precise types
def createQueue[A](implicit size: Int): Queue[A] =
...
def connect(hostname: String)(implicit port: Int): Unit =
...
47
Advice
1. Use precise types
def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost =
BlogPost(
author = requesterId,
title = title,
content = "",
)
def shareBlog(blog: BlogPost, targetUser: UserId)(implicit requesterId: UserId): Future[Unit] =
...
48
Advice
1. Use precise types
case class RequesterId(userId: UserId)
def createEmptyBlogPost(title: String)(implicit requesterId: RequesterId): BlogPost =
BlogPost(
author = requesterId.userId,
title = title,
content = "",
)
49
Advice
2. Use clear and simple Context
50
The value of implicit parameters must be Obvious
51
Environment Pattern Alternatives
Reader
def createBlogPost(title: String) : Reader[(RequesterId, Clock), BlogPost] = ...
def createProject(projectName: String): Reader[(RequesterId, Clock), Project] = ...
for {
blog <- createBlogPost("Implicits for the noob")
project <- createProject("tutorial")
} yield ...
52
Environment Pattern Alternatives
Reader
def createBlogPost(title: String) : Reader[(RequesterId, Clock), BlogPost] = ...
def createProject(projectName: String): Reader[RequesterId , Project] = ...
for {
blog <- createBlogPost("Implicits for the noob")
project <- createProject("tutorial") ❌
} yield ...
53
Environment Pattern Alternatives
ZIO
trait ZIO[-R, +E, +A]
54
Typeclass Pattern
55
Typeclass Pattern
val user : User = ...
val userIds: List[UserId] = ...
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
56
Typeclass Pattern
val user : User = ...
val userIds: List[UserId] = ...
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
def Ok[A](value: A): HttpResponse =
HttpResponse(200, value.toJson)
57
Typeclass Pattern
val user : User = ...
val userIds: List[UserId] = ...
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
def Ok[A](value: A): HttpResponse =
HttpResponse(200, value.toJson)
58
Typeclass Pattern
val user : User = ...
val userIds: List[UserId] = ...
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
def Ok[A](value: A): HttpResponse =
HttpResponse(200, value.toJson)
Ok((x: Int) => x + 1) // ???
59
Typeclass Pattern
trait JsonEncoder[A] {
def encode(value: A): Json
}
60
Typeclass Pattern
trait JsonEncoder[A] {
def encode(value: A): Json
}
def Ok[A](value: A, encoder: JsonEncoder[A]): HttpResponse =
HttpResponse(200, encoder.encode(value))
61
Typeclass Pattern
trait JsonEncoder[A] {
def encode(value: A): Json
}
def Ok[A](value: A, encoder: JsonEncoder[A]): HttpResponse =
HttpResponse(200, encoder.encode(value))
val userEncoder : JsonEncoder[User] = ...
val listUserIdsEncoder: JsonEncoder[List[UserId]] = ...
Ok(user, userEncoder)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds, listUserIdsEncoder)
// res: HttpResponse(200, ["1234", "9464", "0582"])
62
Typeclass Pattern
trait JsonEncoder[A] {
def encode(value: A): Json
}
def Ok[A](value: A)(implicit encoder: JsonEncoder[A]): HttpResponse =
HttpResponse(200, encoder.encode(value))
implicit val userEncoder : JsonEncoder[User] = ...
implicit val listUserIdsEncoder: JsonEncoder[List[UserId]] = ...
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
63
Typeclass Pattern
object JsonSerializer {
implicit val userEncoder : JsonEncoder[User] = ...
implicit val listUserIdsEncoder: JsonEncoder[List[UserId]] = ...
}
import JsonSerializer._
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
64
Implicit Search
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Search for JsonEncoder[User] in User companion object
case class User(userId: UserId, email: String)
object User {
implicit val encoder: JsonEncoder[User] = ...
}
65
Implicit Search
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
Search for JsonEncoder[List[UserId]] in List companion object
sealed trait List[A]
object List {
// There is no JsonEncoder here
}
66
Implicit Search
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
Search for JsonEncoder[List[UserId]] in JsonEncoder companion object
object JsonEncoder {
implicit val string: JsonEncoder[String] = ...
implicit val int : JsonEncoder[Int] = ...
implicit val date : JsonEncoder[LocalDate] = ...
implicit val list : JsonEncoder[List[???]] = ...
}
67
Implicit Derivation
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
Search for JsonEncoder[List[UserId]] in JsonEncoder companion object
object JsonEncoder {
implicit val string: JsonEncoder[String] = ...
implicit val int : JsonEncoder[Int] = ...
implicit val date : JsonEncoder[LocalDate] = ...
implicit def list[A]: JsonEncoder[List[A]] = ...
}
68
Implicit Derivation
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
Search for JsonEncoder[List[UserId]] in JsonEncoder companion object
object JsonEncoder {
implicit val string: JsonEncoder[String] = ...
implicit val int : JsonEncoder[Int] = ...
implicit val date : JsonEncoder[LocalDate] = ...
implicit def list[A](implicit valueEncoder: A): JsonEncoder[List[A]] = ...
}
69
Implicit Search for JsonEncoder[List[UserId]]
1. Search current scope ❌
2. Search companion object of List ❌
3. Search companion object of JsonEncoder (Maybe)
4. Search companion object of UserId ✅
70
Typeclass Pattern
def Ok[A](value: A)(implicit encoder: JsonEncoder[A]): HttpResponse
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
Ok((x: Int) => x + 1) // ❌ compile-time error: could not find implicit value for parameter
71
Typeclass Pattern
def Ok[A: JsonEncoder](value: A): HttpResponse
Ok(user)
// res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"})
Ok(userIds)
// res: HttpResponse(200, ["1234", "9464", "0582"])
Ok((x: Int) => x + 1) // ❌ compile-time error: could not find implicit value for parameter
72
Typeclass Pattern
trait JsonEncoder[A] {
def encode(value: A): Json
}
73
Typeclass Pattern
For types we own, define instances in the companion object
object User {
implicit val encoder: JsonEncoder[User] = ...
}
object UserId {
implicit val encoder: JsonEncoder[UserId] = ...
}
For other types, define instances in the companion object of the typeclass
object JsonEncoder {
implicit val string: JsonEncoder[String] = ...
implicit val int : JsonEncoder[Int] = ...
implicit val date : JsonEncoder[LocalDate] = ...
}
74
Typeclass Pattern
Use typeclass derivation to automatically create instances
object JsonEncoder {
implicit def list[A](implicit valueEncoder: A): JsonEncoder[List[A]] = ...
}
75
Typeclass Pattern
Use typeclass derivation to automatically create instances
object JsonEncoder {
// shapeless, magnolia
implicit def caseClass[A: JsonEncoder, B: JsonEncoder]: JsonEncoder[CaseClass[A, B]] = ...
}
case class User(userId: UserId, email: String)
object User {
implicit val encoder: JsonEncoder[User] = JsonEncoder.caseClass
}
76
Typeclass Pattern (Scala 3)
Use typeclass derivation to automatically create instances
case class User(userId: UserId, email: String) derives JsonEncoder
77
Advice
Don't define instances in custom objects
object Client1Encoder {
implicit val userEncoder: JsonEncoder[User] = ...
}
object Client2Encoder {
implicit val userEncoder: JsonEncoder[User] = ...
}
import Client1Encoder._
// lots of code
Ok(user)
78
The value of implicit parameters must be Obvious
79
Ordering
trait Ordering[A] {
def compare(left: A, right: A): Int
}
80
Ordering
trait Ordering[A] {
def compare(left: A, right: A): Int
}
trait List[A] {
def sorted(implicit ordering: Ordering[A]): List[A] = ...
}
81
Ordering
trait Ordering[A] {
def compare(left: A, right: A): Int
}
trait List[A] {
def sorted(implicit ordering: Ordering[A]): List[A] = ...
}
List(8,1,9).sorted
// ???
82
Ordering
trait Ordering[A] {
def compare(left: A, right: A): Int
}
trait List[A] {
def sorted(implicit ordering: Ordering[A]): List[A] = ...
}
List(8,1,9).sorted
// res3: List[Int] = List(1, 8, 9)
83
Custom Ordering
implicit val descendingIntOrdering: Ordering[Int] = Ordering.Int.reverse
List(8,1,9).sorted
// res4: List[Int] = List(9, 8, 1)
84
Custom Ordering
implicit val descendingIntOrdering: Ordering[Int] = Ordering.Int.reverse
List(8,1,9).sorted
// res4: List[Int] = List(9, 8, 1)
List(8,1,9).sorted(Ordering.Int.reverse)
// res5: List[Int] = List(9, 8, 1)
85
Better Ordering
trait List[A] {
def sorted(ordering: Ordering[A]): List[A] = ...
}
List(8,1,9).sorted(Ordering.Int.ascending)
// res: List[Int] = List(1, 8, 9)
List(8,1,9).sorted(Ordering.Int.descending)
// res: List[Int] = List(9, 8, 1)
86
Review
Explicit
Simple
Great tooling
Default value
When one value is much more common than the others
Implicit
When some parameters value are static within a context
When writing generic functions
87
The value of implicit parameters must be Obvious
88
89
hello@scalajobs.com
90
91

Contenu connexe

Tendances

Parboiled explained
Parboiled explainedParboiled explained
Parboiled explainedPaul Popoff
 
Class & Object - User Defined Method
Class & Object - User Defined MethodClass & Object - User Defined Method
Class & Object - User Defined MethodPRN USM
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaJorge Vásquez
 
Collections - Array List
Collections - Array List Collections - Array List
Collections - Array List Hitesh-Java
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...Philip Schwarz
 
Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...
Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...
Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...Edureka!
 
Functional Error Handling with Cats
Functional Error Handling with CatsFunctional Error Handling with Cats
Functional Error Handling with CatsMark Canlas
 
JavaScript - An Introduction
JavaScript - An IntroductionJavaScript - An Introduction
JavaScript - An IntroductionManvendra Singh
 
Java Code for Sample Projects Inheritance
Java Code for Sample Projects InheritanceJava Code for Sample Projects Inheritance
Java Code for Sample Projects Inheritancejwjablonski
 
Kotlin for Android Development
Kotlin for Android DevelopmentKotlin for Android Development
Kotlin for Android DevelopmentSpeck&Tech
 
Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Jorge Vásquez
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
OOP in C++
OOP in C++OOP in C++
OOP in C++ppd1961
 
This keyword and final keyword
This keyword and final  keywordThis keyword and final  keyword
This keyword and final keywordkinjalbirare
 
Strings in Java
Strings in Java Strings in Java
Strings in Java Hitesh-Java
 
Java Basics
Java BasicsJava Basics
Java BasicsSunil OS
 
Introduction to Java 8
Introduction to Java 8Introduction to Java 8
Introduction to Java 8Knoldus Inc.
 

Tendances (20)

Parboiled explained
Parboiled explainedParboiled explained
Parboiled explained
 
Class & Object - User Defined Method
Class & Object - User Defined MethodClass & Object - User Defined Method
Class & Object - User Defined Method
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
 
Collections - Array List
Collections - Array List Collections - Array List
Collections - Array List
 
The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...The aggregate function - from sequential and parallel folds to parallel aggre...
The aggregate function - from sequential and parallel folds to parallel aggre...
 
Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...
Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...
Java Strings Tutorial | String Manipulation in Java | Java Tutorial For Begin...
 
Functional Error Handling with Cats
Functional Error Handling with CatsFunctional Error Handling with Cats
Functional Error Handling with Cats
 
JavaScript - An Introduction
JavaScript - An IntroductionJavaScript - An Introduction
JavaScript - An Introduction
 
Java Code for Sample Projects Inheritance
Java Code for Sample Projects InheritanceJava Code for Sample Projects Inheritance
Java Code for Sample Projects Inheritance
 
Kotlin for Android Development
Kotlin for Android DevelopmentKotlin for Android Development
Kotlin for Android Development
 
Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!Be Smart, Constrain Your Types to Free Your Brain!
Be Smart, Constrain Your Types to Free Your Brain!
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
OOP in C++
OOP in C++OOP in C++
OOP in C++
 
This keyword and final keyword
This keyword and final  keywordThis keyword and final  keyword
This keyword and final keyword
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Strings in Java
Strings in Java Strings in Java
Strings in Java
 
Java Basics
Java BasicsJava Basics
Java Basics
 
JQuery selectors
JQuery selectors JQuery selectors
JQuery selectors
 
Python programming : Abstract classes interfaces
Python programming : Abstract classes interfacesPython programming : Abstract classes interfaces
Python programming : Abstract classes interfaces
 
Introduction to Java 8
Introduction to Java 8Introduction to Java 8
Introduction to Java 8
 

Similaire à Implicit parameters, when to use them (or not)!

SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfSummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfARORACOCKERY2111
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologyDaniel Knell
 
Why Spring <3 Kotlin
Why Spring <3 KotlinWhy Spring <3 Kotlin
Why Spring <3 KotlinVMware Tanzu
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stackPaul Bearne
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Enhancing Productivity and Insight A Tour of JDK Tools Progress Beyond Java 17
Enhancing Productivity and Insight  A Tour of JDK Tools Progress Beyond Java 17Enhancing Productivity and Insight  A Tour of JDK Tools Progress Beyond Java 17
Enhancing Productivity and Insight A Tour of JDK Tools Progress Beyond Java 17Ana-Maria Mihalceanu
 
How to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainHow to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainCodemotion Tel Aviv
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmersAlexander Varwijk
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)James Titcumb
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说Ting Lv
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Tsuyoshi Yamamoto
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...go_oh
 
¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?jaespinmora
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPDan Jesus
 

Similaire à Implicit parameters, when to use them (or not)! (20)

SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdfSummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
SummaryHW6 Account ManagementIn HW4, you kept track of multiple.pdf
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Why Spring <3 Kotlin
Why Spring <3 KotlinWhy Spring <3 Kotlin
Why Spring <3 Kotlin
 
Using WordPress as your application stack
Using WordPress as your application stackUsing WordPress as your application stack
Using WordPress as your application stack
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Enhancing Productivity and Insight A Tour of JDK Tools Progress Beyond Java 17
Enhancing Productivity and Insight  A Tour of JDK Tools Progress Beyond Java 17Enhancing Productivity and Insight  A Tour of JDK Tools Progress Beyond Java 17
Enhancing Productivity and Insight A Tour of JDK Tools Progress Beyond Java 17
 
How to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrainHow to actually use promises - Jakob Mattsson, FishBrain
How to actually use promises - Jakob Mattsson, FishBrain
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmers
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
 
前端MVC 豆瓣说
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
 
¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?¿Cómo de sexy puede hacer Backbone mi código?
¿Cómo de sexy puede hacer Backbone mi código?
 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
 

Dernier

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024Lorenzo Miniero
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)Samir Dash
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringWSO2
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch TuesdayIvanti
 
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)Paige Cruz
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc
 
UiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewUiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewDianaGray10
 
How to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfHow to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfdanishmna97
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMKumar Satyam
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingScyllaDB
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe中 央社
 
Quantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingQuantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingWSO2
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityVictorSzoltysek
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data SciencePaolo Missier
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseWSO2
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 

Dernier (20)

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software Engineering
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch Tuesday
 
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
 
UiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overviewUiPath manufacturing technology benefits and AI overview
UiPath manufacturing technology benefits and AI overview
 
How to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cfHow to Check CNIC Information Online with Pakdata cf
How to Check CNIC Information Online with Pakdata cf
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream Processing
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
Quantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingQuantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation Computing
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps Productivity
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data Science
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern Enterprise
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 

Implicit parameters, when to use them (or not)!

  • 1. 1
  • 2. Julien Truffaut Backend Scala developer for 10+ years FP instructor at fp-tower.com Co-founder of scalajobs.com 2
  • 3. Implicit parameters def newBlogPost(title: String)(implicit author: User): BlogPost class UserService(db: Connection)(implicit ec: ExecutionContext) {} 3
  • 4. Implicit parameters def newBlogPost(title: String)(implicit author: User): BlogPost class UserService(db: Connection)(implicit ec: ExecutionContext) {} When should we define a parameter as implicit? 4
  • 5. Parameters definition Explicit def fullName(firstName: String, lastName: String): String = s"$firstName $lastName" fullName("John", "Doe") // res0: String = "John Doe" 5
  • 6. Parameters definition Explicit def fullName(firstName: String, lastName: String): String = s"$firstName $lastName" fullName("John", "Doe") // res0: String = "John Doe" fullName(lastName = "Smith", firstName = "Bob") // res1: String = "Bob Smith" 6
  • 7. Austria sealed abstract class AcademicTitle(val shortForm: String) case object MasterOfScience extends AcademicTitle("MSc") case object Magistrate extends AcademicTitle("Mag") ... 7
  • 8. Austria sealed abstract class AcademicTitle(val shortForm: String) case object MasterOfScience extends AcademicTitle("MSc") case object Magistrate extends AcademicTitle("Mag") ... def fullName(firstName: String, lastName: String, title: Option[AcademicTitle]): String = { val suffix = title.map(" " + _.shortForm).getOrElse("") s"${firstName} ${lastName}${suffix}" } fullName("John", "Doe", None) // res: String = "John Doe" fullName("Bob", "Smith", Some(MasterOfScience)) // res: String = "Bob Smith MSc" 8
  • 9. Parameters definition Default value def fullName(firstName: String, lastName: String, title: Option[AcademicTitle] = None): String = { val suffix = title.map(" " + _.shortForm).getOrElse("") s"${firstName} ${lastName}${suffix}" } fullName("John", "Doe") // res: String = "John Doe" fullName("Bob", "Smith", Some(MasterOfScience)) // res: String = "Bob Smith MSc" 9
  • 10. Parameters definition Default value def kafkaListener( topic : String, bootstrapServers : String, commitTimeout : FiniteDuration = 50.millis, pollInterval : FiniteDuration = 15.millis, autoOffsetReset : AutoOffsetReset = AutoOffsetReset.Latest, ) 10
  • 11. Parameters definition Default value def kafkaListener( topic : String, bootstrapServers : String, commitTimeout : FiniteDuration = 50.millis, pollInterval : FiniteDuration = 15.millis, autoOffsetReset : AutoOffsetReset = AutoOffsetReset.Latest, ) Similar options: Overloads or Builder Pattern 11
  • 12. Parameters definition Implicit case class BlogPost( author : UserId, title : String, content : String, ) case class UserId(value: String) 12
  • 13. Parameters definition Implicit def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "" ) 13
  • 14. Parameters definition Implicit def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "" ) createEmptyBlogPost("Scala Implicits: The complete guide")(UserId("john_1234")) // Explicit call // res: BlogPost = BlogPost( // author = UserId("john_1234"), // title = "Scala Implicits: The complete guide", // content = "", // ) 14
  • 15. Parameters definition Implicit def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "" ) createEmptyBlogPost("Scala Implicits: The complete guide") // Implicit call // res: BlogPost = BlogPost( // author = UserId("john_1234"), // title = "Scala Implicits: The complete guide", // content = "", // ) 15
  • 16. Implicit resolution val ImplicitValues: Map[Type, Value] = // Maintained by the compiler Map( Int -> 5, String -> "", UserId -> UserId("john_1234"), ) createEmptyBlogPost("Scala Implicits: The complete guide") // user code 16
  • 17. Implicit resolution val ImplicitValues: Map[Type, Value] = // Maintained by the compiler Map( Int -> 5, String -> "", UserId -> UserId("john_1234"), ) createEmptyBlogPost("Scala Implicits: The complete guide") // user code | v createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time 17
  • 18. Implicit resolution val ImplicitValues: Map[Type, Value] = // Maintained by the compiler Map( Int -> 5, String -> "", UserId -> UserId("john_1234"), ) createEmptyBlogPost("Scala Implicits: The complete guide") // user code | v createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time 18
  • 19. Implicit resolution val ImplicitValues: Map[Type, Value] = // Maintained by the compiler Map( Int -> 5, String -> "", UserId -> UserId("john_1234"), ) createEmptyBlogPost("Scala Implicits: The complete guide") // user code | v createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time | v createEmptyBlogPost("Scala Implicits: The complete guide")(UserId("john_1234")) 19
  • 20. Implicit resolution val ImplicitValues: Map[Type, Value] = // Maintained by the compiler Map( Int -> 5, String -> "", // No UserId ) createEmptyBlogPost("Scala Implicits: The complete guide") // user code | v createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time | v ??? 20
  • 21. Implicit resolution val ImplicitValues: Map[Type, Value] = // Maintained by the compiler Map( Int -> 5, String -> "", // No UserId ) createEmptyBlogPost("Scala Implicits: The complete guide") // user code | v createEmptyBlogPost("Scala Implicits: The complete guide")(ImplicitValues(UserId)) // lookup at compile-time | v error: could not find implicit value for parameter requesterId: UserId // compile-time error 21
  • 22. Implicit Definition implicit val requesterId: UserId = UserId("john_1234") createEmptyBlogPost("Scala Implicits: The complete guide") // res: BlogPost = BlogPost( // author = UserId("john_1234"), // title = "Scala Implicits: The complete guide", // content = "", // ) 22
  • 23. Implicit Scope class BlogPostTest extends AnyFunSuite { test("createEmptyBlogPost gets the author implicitly") { implicit val requesterId: UserId = UserId("john_1234") val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile assert(result.author == requesterId) } test("createEmptyBlogPost has no content") { val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ❌ could not find implicit value assert(result.content.isEmpty) } } 23
  • 24. Implicit Scope class BlogPostTest extends AnyFunSuite { test("createEmptyBlogPost gets the author implicitly") { implicit val requesterId: UserId = UserId("john_1234") val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile assert(result.author == requesterId) } test("createEmptyBlogPost has no content") { val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ❌ could not find implicit value assert(result.content.isEmpty) } } 24
  • 25. Implicit Scope class BlogPostTest extends AnyFunSuite { implicit val requesterId: UserId = UserId("john_1234") test("createEmptyBlogPost gets the author implicitly") { val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile assert(result.author == requesterId) } test("createEmptyBlogPost has no content") { val result = createEmptyBlogPost("Scala Implicits: The complete guide") // ✅ Compile assert(result.content.isEmpty) } } 25
  • 26. Summary 1. The compiler keeps track of all the implicits available within a scope 2. At compile-time, the compiler injects all implicit parameters 3. If an implicit is missing, we get a compiled-time error 26
  • 27. Summary 1. The compiler keeps track of all the implicits available within a scope 2. At compile-time, the compiler injects all implicit parameters 3. If an implicit is missing, we get a compiled-time error 4. If there are 2 or more implicit values of the same type in scope, we also get a compiled-time error 27
  • 28. Within a Scope, there must be Only One implicit value per Type 28
  • 30. Environment Pattern val httpService = { case req @ POST -> Root / "blog" => // create a blog case req @ PUT -> Root / "blog" / id => // update a blog case req @ DELETE -> Root / "blog" / id => // delete a blog } 30
  • 31. Environment Pattern case req @ POST -> Root / "blog" => implicit val requesterId: UserId = extractRequesterId(req) for { payload <- req.parseBodyAs[NewBlog] _ <- blogAPI.create(payload.title) } yield Ok() 31
  • 32. Environment Pattern case req @ POST -> Root / "blog" => implicit val requesterId: UserId = extractRequesterId(req) for { payload <- req.parseBodyAs[NewBlog] _ <- blogAPI.create(payload.title) } yield Ok() 32
  • 33. Environment Pattern case req @ POST -> Root / "blog" => implicit val requesterId: UserId = extractRequesterId(req) for { payload <- req.parseBodyAs[NewBlog] _ <- blogAPI.create(payload.title) } yield Ok() class BlogAPI(db: DB) { def create(title: String)(implicit requesterId: UserId): Future[Unit] = { val newBlog = createEmptyBlogPost(title) db.save(newBlog) } } 33
  • 34. Environment Pattern case req @ POST -> Root / "blog" => implicit val requesterId: UserId = extractRequesterId(req) for { payload <- req.parseBodyAs[NewBlog] _ <- blogAPI.create(payload.title) } yield Ok() class BlogAPI(db: DB) { def create(title: String)(implicit requesterId: UserId): Future[Unit] = { val newBlog = createEmptyBlogPost(title) db.save(newBlog) } } def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "", ) 34
  • 35. Environment Pattern case req @ POST -> Root / "blog" => implicit val requesterId: UserId = extractRequesterId(req) for { payload <- req.parseBodyAs[NewBlog] _ <- blogAPI.create(payload.title) } yield Ok() class BlogAPI(db: DB) { def create(title: String)(implicit requesterId: UserId): Future[Unit] = { val newBlog = createEmptyBlogPost(title) db.save(newBlog) } } def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "", ) 35
  • 36. Environment Pattern case class BlogPost( author : UserId, title : String, content : String, createAt: Instant, ) 36
  • 37. Environment Pattern case class BlogPost( author : UserId, title : String, content : String, createAt: Instant, ) def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "", createAt = Instant.now(), ) 37
  • 38. Environment Pattern test("create blog post") { implicit val requesterId: UserId = UserId("john_1234") val result = createEmptyBlogPost("Test") assert(result == BlogPost(requesterId, "Test", "", ???)) } 38
  • 39. Environment Pattern trait Clock { def now(): Instant } 39
  • 40. Environment Pattern trait Clock { def now(): Instant } object Clock { val real: Clock = new Clock { def now(): Instant = Instant.now() } def static(timestamp: Instant): Clock = new Clock { def now(): Instant = timestamp } } 40
  • 41. Environment Pattern trait Clock { def now(): Instant } object Clock { val real: Clock = new Clock { def now(): Instant = Instant.now() } def static(timestamp: Instant): Clock = new Clock { def now(): Instant = timestamp } } 41
  • 42. Environment Pattern def createEmptyBlogPost(title: String)(implicit requesterId: UserId, clock: Clock): BlogPost = BlogPost( author = requesterId, title = title, content = "", createAt = clock.now(), ) 42
  • 43. Environment Pattern def createEmptyBlogPost(title: String)(implicit requesterId: UserId, clock: Clock): BlogPost = BlogPost( author = requesterId, title = title, content = "", createAt = clock.now(), ) object Main extends App { implicit val clock: Clock = Clock.real ... } class BlogPostTest extends AnyFunSuite { implicit val clock: Clock = Clock.static(Instant.EPOCH) ... } 43
  • 44. Environment Pattern object Main extends App { implicit val ec: ExecutionContext = ExecutionContext.global ... } class BlogDatabaseTest extends AnyFunSuite { implicit val ec: ExecutionContext = fixedSizeExecutionContext(1) ... } 44
  • 45. Environment parameters are Static in a given Context 45
  • 46. Context: Per request RequesterId TraceId Context: Prod / Test Clock ExecutionContext (for Future) RandomGenerator 46
  • 47. Advice 1. Use precise types def createQueue[A](implicit size: Int): Queue[A] = ... def connect(hostname: String)(implicit port: Int): Unit = ... 47
  • 48. Advice 1. Use precise types def createEmptyBlogPost(title: String)(implicit requesterId: UserId): BlogPost = BlogPost( author = requesterId, title = title, content = "", ) def shareBlog(blog: BlogPost, targetUser: UserId)(implicit requesterId: UserId): Future[Unit] = ... 48
  • 49. Advice 1. Use precise types case class RequesterId(userId: UserId) def createEmptyBlogPost(title: String)(implicit requesterId: RequesterId): BlogPost = BlogPost( author = requesterId.userId, title = title, content = "", ) 49
  • 50. Advice 2. Use clear and simple Context 50
  • 51. The value of implicit parameters must be Obvious 51
  • 52. Environment Pattern Alternatives Reader def createBlogPost(title: String) : Reader[(RequesterId, Clock), BlogPost] = ... def createProject(projectName: String): Reader[(RequesterId, Clock), Project] = ... for { blog <- createBlogPost("Implicits for the noob") project <- createProject("tutorial") } yield ... 52
  • 53. Environment Pattern Alternatives Reader def createBlogPost(title: String) : Reader[(RequesterId, Clock), BlogPost] = ... def createProject(projectName: String): Reader[RequesterId , Project] = ... for { blog <- createBlogPost("Implicits for the noob") project <- createProject("tutorial") ❌ } yield ... 53
  • 56. Typeclass Pattern val user : User = ... val userIds: List[UserId] = ... Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) 56
  • 57. Typeclass Pattern val user : User = ... val userIds: List[UserId] = ... Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) def Ok[A](value: A): HttpResponse = HttpResponse(200, value.toJson) 57
  • 58. Typeclass Pattern val user : User = ... val userIds: List[UserId] = ... Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) def Ok[A](value: A): HttpResponse = HttpResponse(200, value.toJson) 58
  • 59. Typeclass Pattern val user : User = ... val userIds: List[UserId] = ... Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) def Ok[A](value: A): HttpResponse = HttpResponse(200, value.toJson) Ok((x: Int) => x + 1) // ??? 59
  • 60. Typeclass Pattern trait JsonEncoder[A] { def encode(value: A): Json } 60
  • 61. Typeclass Pattern trait JsonEncoder[A] { def encode(value: A): Json } def Ok[A](value: A, encoder: JsonEncoder[A]): HttpResponse = HttpResponse(200, encoder.encode(value)) 61
  • 62. Typeclass Pattern trait JsonEncoder[A] { def encode(value: A): Json } def Ok[A](value: A, encoder: JsonEncoder[A]): HttpResponse = HttpResponse(200, encoder.encode(value)) val userEncoder : JsonEncoder[User] = ... val listUserIdsEncoder: JsonEncoder[List[UserId]] = ... Ok(user, userEncoder) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds, listUserIdsEncoder) // res: HttpResponse(200, ["1234", "9464", "0582"]) 62
  • 63. Typeclass Pattern trait JsonEncoder[A] { def encode(value: A): Json } def Ok[A](value: A)(implicit encoder: JsonEncoder[A]): HttpResponse = HttpResponse(200, encoder.encode(value)) implicit val userEncoder : JsonEncoder[User] = ... implicit val listUserIdsEncoder: JsonEncoder[List[UserId]] = ... Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) 63
  • 64. Typeclass Pattern object JsonSerializer { implicit val userEncoder : JsonEncoder[User] = ... implicit val listUserIdsEncoder: JsonEncoder[List[UserId]] = ... } import JsonSerializer._ Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) 64
  • 65. Implicit Search Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Search for JsonEncoder[User] in User companion object case class User(userId: UserId, email: String) object User { implicit val encoder: JsonEncoder[User] = ... } 65
  • 66. Implicit Search Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) Search for JsonEncoder[List[UserId]] in List companion object sealed trait List[A] object List { // There is no JsonEncoder here } 66
  • 67. Implicit Search Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) Search for JsonEncoder[List[UserId]] in JsonEncoder companion object object JsonEncoder { implicit val string: JsonEncoder[String] = ... implicit val int : JsonEncoder[Int] = ... implicit val date : JsonEncoder[LocalDate] = ... implicit val list : JsonEncoder[List[???]] = ... } 67
  • 68. Implicit Derivation Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) Search for JsonEncoder[List[UserId]] in JsonEncoder companion object object JsonEncoder { implicit val string: JsonEncoder[String] = ... implicit val int : JsonEncoder[Int] = ... implicit val date : JsonEncoder[LocalDate] = ... implicit def list[A]: JsonEncoder[List[A]] = ... } 68
  • 69. Implicit Derivation Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) Search for JsonEncoder[List[UserId]] in JsonEncoder companion object object JsonEncoder { implicit val string: JsonEncoder[String] = ... implicit val int : JsonEncoder[Int] = ... implicit val date : JsonEncoder[LocalDate] = ... implicit def list[A](implicit valueEncoder: A): JsonEncoder[List[A]] = ... } 69
  • 70. Implicit Search for JsonEncoder[List[UserId]] 1. Search current scope ❌ 2. Search companion object of List ❌ 3. Search companion object of JsonEncoder (Maybe) 4. Search companion object of UserId ✅ 70
  • 71. Typeclass Pattern def Ok[A](value: A)(implicit encoder: JsonEncoder[A]): HttpResponse Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) Ok((x: Int) => x + 1) // ❌ compile-time error: could not find implicit value for parameter 71
  • 72. Typeclass Pattern def Ok[A: JsonEncoder](value: A): HttpResponse Ok(user) // res: HttpResponse(200, {"userId" : "1234", "name" : "John Doe"}) Ok(userIds) // res: HttpResponse(200, ["1234", "9464", "0582"]) Ok((x: Int) => x + 1) // ❌ compile-time error: could not find implicit value for parameter 72
  • 73. Typeclass Pattern trait JsonEncoder[A] { def encode(value: A): Json } 73
  • 74. Typeclass Pattern For types we own, define instances in the companion object object User { implicit val encoder: JsonEncoder[User] = ... } object UserId { implicit val encoder: JsonEncoder[UserId] = ... } For other types, define instances in the companion object of the typeclass object JsonEncoder { implicit val string: JsonEncoder[String] = ... implicit val int : JsonEncoder[Int] = ... implicit val date : JsonEncoder[LocalDate] = ... } 74
  • 75. Typeclass Pattern Use typeclass derivation to automatically create instances object JsonEncoder { implicit def list[A](implicit valueEncoder: A): JsonEncoder[List[A]] = ... } 75
  • 76. Typeclass Pattern Use typeclass derivation to automatically create instances object JsonEncoder { // shapeless, magnolia implicit def caseClass[A: JsonEncoder, B: JsonEncoder]: JsonEncoder[CaseClass[A, B]] = ... } case class User(userId: UserId, email: String) object User { implicit val encoder: JsonEncoder[User] = JsonEncoder.caseClass } 76
  • 77. Typeclass Pattern (Scala 3) Use typeclass derivation to automatically create instances case class User(userId: UserId, email: String) derives JsonEncoder 77
  • 78. Advice Don't define instances in custom objects object Client1Encoder { implicit val userEncoder: JsonEncoder[User] = ... } object Client2Encoder { implicit val userEncoder: JsonEncoder[User] = ... } import Client1Encoder._ // lots of code Ok(user) 78
  • 79. The value of implicit parameters must be Obvious 79
  • 80. Ordering trait Ordering[A] { def compare(left: A, right: A): Int } 80
  • 81. Ordering trait Ordering[A] { def compare(left: A, right: A): Int } trait List[A] { def sorted(implicit ordering: Ordering[A]): List[A] = ... } 81
  • 82. Ordering trait Ordering[A] { def compare(left: A, right: A): Int } trait List[A] { def sorted(implicit ordering: Ordering[A]): List[A] = ... } List(8,1,9).sorted // ??? 82
  • 83. Ordering trait Ordering[A] { def compare(left: A, right: A): Int } trait List[A] { def sorted(implicit ordering: Ordering[A]): List[A] = ... } List(8,1,9).sorted // res3: List[Int] = List(1, 8, 9) 83
  • 84. Custom Ordering implicit val descendingIntOrdering: Ordering[Int] = Ordering.Int.reverse List(8,1,9).sorted // res4: List[Int] = List(9, 8, 1) 84
  • 85. Custom Ordering implicit val descendingIntOrdering: Ordering[Int] = Ordering.Int.reverse List(8,1,9).sorted // res4: List[Int] = List(9, 8, 1) List(8,1,9).sorted(Ordering.Int.reverse) // res5: List[Int] = List(9, 8, 1) 85
  • 86. Better Ordering trait List[A] { def sorted(ordering: Ordering[A]): List[A] = ... } List(8,1,9).sorted(Ordering.Int.ascending) // res: List[Int] = List(1, 8, 9) List(8,1,9).sorted(Ordering.Int.descending) // res: List[Int] = List(9, 8, 1) 86
  • 87. Review Explicit Simple Great tooling Default value When one value is much more common than the others Implicit When some parameters value are static within a context When writing generic functions 87
  • 88. The value of implicit parameters must be Obvious 88
  • 89. 89
  • 91. 91