SlideShare a Scribd company logo
Implicits
Scalain
Derek Wyatt
Twitter: @derekwyatt
Email: derek@derekwyatt.org
Friday, 11 October, 13
Agenda
Lies and Damn Lies
Use Cases
Scope
ExampleCode!
Truths
Rules of Thumb
Friday, 11 October, 13
Implicits are NEW
Friday, 11 October, 13
Implicits are NEW
New things can be cool!
Friday, 11 October, 13
Implicits are NEW
New things can be cool!
New things can also be scary!
❉
Scala 2.10’s new set of
warnings don’t help the
situation.
❉
Friday, 11 October, 13
Implicits are NEW
New things can be cool!
New things can also be scary!
❉
Scala 2.10’s new set of
warnings don’t help the
situation.
❉
Especially when they’re complicated!
Friday, 11 October, 13
Implicits are NEW
New things can be cool!
Newness + Complexness = Fearsometimes
New things can also be scary!
❉
Scala 2.10’s new set of
warnings don’t help the
situation.
❉
Especially when they’re complicated!
Friday, 11 October, 13
Implicits are NEW
New things can be cool!
Newness + Complexness = Fearsometimes
Fear Avoidance
New things can also be scary!
❉
Scala 2.10’s new set of
warnings don’t help the
situation.
❉
Especially when they’re complicated!
Friday, 11 October, 13
Implicits are NEW
New things can be cool!
Newness + Complexness = Fearsometimes
Fear Avoidance
Avoidance :(
New things can also be scary!
❉
Scala 2.10’s new set of
warnings don’t help the
situation.
❉
Especially when they’re complicated!
Friday, 11 October, 13
Implicits
Friday, 11 October, 13
Implicits
Are Not
Friday, 11 October, 13
Implicits
Are Not
Global variables LIE!
Friday, 11 October, 13
Implicits
Are Not
Global variables
Dynamically Applied
LIE!
DAMN
LIE!
Friday, 11 October, 13
Implicits
Are Not
Global variables
Dynamically Applied
Dangerous (...much...)
LIE!
DAMN
LIE!
Fib
Friday, 11 October, 13
Implicits
Are Not
Global variables
Dynamically Applied
Dangerous (...much...)
Implicits are like scissors.
Use them. Don’t run with them.
LIE!
DAMN
LIE!
Fib
Friday, 11 October, 13
Use Cases
What are they used for?
Friday, 11 October, 13
Use Case: Type Classes
Friday, 11 October, 13
Use Case: Type Classes
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)) a else b
Friday, 11 October, 13
Use Case: Type Classes
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)) a else b
lessThan needsdefinition
Friday, 11 October, 13
Use Case: Type Classes
def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean =
o.lt(a, b)
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)) a else b
lessThan needsdefinition
Friday, 11 October, 13
Use Case: Type Classes
def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean =
o.lt(a, b)
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)) a else b
Ordering[Int]’s gottacome from somewhere
lessThan needsdefinition
Friday, 11 October, 13
Use Case: Type Classes
def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean =
o.lt(a, b)
implicit object intOrdering extends Ordering[Int] {
def compare(a: Int, b: Int): Int = a - b
}
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)) a else b
Ordering[Int]’s gottacome from somewhere
lessThan needsdefinition
Friday, 11 October, 13
Use Case: Type Classes
def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean =
o.lt(a, b)
implicit object intOrdering extends Ordering[Int] {
def compare(a: Int, b: Int): Int = a - b
}
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)) a else b
Ordering[Int]’s gottacome from somewhere
val a = someInt()
val b = someOtherInt()
val lesser = if (lessThan(a, b)(intOrdering)) a else b
lessThan needsdefinition
Friday, 11 October, 13
Use Case: Class Extension
Friday, 11 October, 13
Use Case: Class Extension
val hexVals = “implicit”.asHexSeq
// Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74)
The “Pimp”
Friday, 11 October, 13
Use Case: Class Extension
val hexVals = “implicit”.asHexSeq
// Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74)
The “Pimp”
implicit class HexableString(s: String) {
def asHexSeq: Seq[String] = s map { c =>
f”0x$c%02X”
}
}
The implicit class definition provides the
extension method
Friday, 11 October, 13
Use Case: Class Extension
val hexVals = “implicit”.asHexSeq
// Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74)
The “Pimp”
implicit class HexableString(s: String) {
def asHexSeq: Seq[String] = s map { c =>
f”0x$c%02X”
}
}
The implicit class definition provides the
extension method
Bonus: If you extend implicit classes from AnyVal,
no temporary object construction will occur.
Friday, 11 October, 13
Use Case: Decluttering
val future1 = someCall(“a parameter”, 5.seconds)
val future2 = someCall(345, 5.seconds)
val future3 = someCall(235.9352, 5.seconds)
Friday, 11 October, 13
Use Case: Decluttering
val future1 = someCall(“a parameter”, 5.seconds)
val future2 = someCall(345, 5.seconds)
val future3 = someCall(235.9352, 5.seconds)
Blurgh
Friday, 11 October, 13
Use Case: Decluttering
val future1 = someCall(“a parameter”, 5.seconds)
val future2 = someCall(345, 5.seconds)
val future3 = someCall(235.9352, 5.seconds)
Blurgh
def someCall[A](a: A)(implicit timeout: Duration): Future[A] = ???
But, if we define someCall this way...
Friday, 11 October, 13
Use Case: Decluttering
val future1 = someCall(“a parameter”, 5.seconds)
val future2 = someCall(345, 5.seconds)
val future3 = someCall(235.9352, 5.seconds)
Blurgh
def someCall[A](a: A)(implicit timeout: Duration): Future[A] = ???
But, if we define someCall this way...
implicit val myTimeoutValue = 5.seconds
val future1 = someCall(“a parameter”)
val future2 = someCall(345)
val future3 = someCall(235.9352)
And define an
implicit value, we can
simplify the calls...
Friday, 11 October, 13
Use Case: Internal DSLs
Create your own sub-language with ease
Friday, 11 October, 13
Use Case: Internal DSLs
Create your own sub-language with ease
implicit class Recoverable[A](f: => A) {
def recover(g: Throwable => A): A =
try {
f
} catch {
case t: Throwable =>
g(t)
}
}
Friday, 11 October, 13
Use Case: Internal DSLs
Create your own sub-language with ease
implicit class Recoverable[A](f: => A) {
def recover(g: Throwable => A): A =
try {
f
} catch {
case t: Throwable =>
g(t)
}
}
def thisThrows(): Int = throw new Exception(“Argh!”)
val stable = thisThrows() recover { t =>
if (t.getMessage == “Argh!”)
10
else
5
} // stable == 10
Friday, 11 October, 13
Use Case: Other stuff...
Friday, 11 October, 13
Use Case: Other stuff...
Overriding defaults
def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A]
Friday, 11 October, 13
Use Case: Other stuff...
Overriding defaults
def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A]
Decoupled Dependency Injection
class Database(ec: ExecutionContext) {
def create(row: Row): Future[Result] = ???
def delete(id: RowId): Future[Result] = ???
// etc...
}
Friday, 11 October, 13
Use Case: Other stuff...
Overriding defaults
def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A]
Decoupled Dependency Injection
class Database(ec: ExecutionContext) {
def create(row: Row): Future[Result] = ???
def delete(id: RowId): Future[Result] = ???
// etc...
}
NO!
Friday, 11 October, 13
Use Case: Other stuff...
Overriding defaults
def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A]
Decoupled Dependency Injection
class Database {
def create(row: Row)(implicit ec: ExecutionContext): Future[Result]
def delete(id: RowId)(implicit ec: ExecutionContext): Future[Result]
// etc...
}
We can now vary the ExecutionContext at any
point by supplying the right implicit value
Friday, 11 October, 13
Implicit Scope
Rules!!!!
Friday, 11 October, 13
Implicit Scope
Rules!!!!
There are a Lot of Rules
Friday, 11 October, 13
Implicit Scope
Rules!!!!
There are a Lot of Rules
Read “Scala In Depth”*
*Josh Suereth
Friday, 11 October, 13
Implicit Scope
Rules!!!!
There are a Lot of Rules
Read “Scala In Depth”*
Implicits without the Import Tax*
*Josh Suereth
Friday, 11 October, 13
Implicit Scope
Rules!!!!
There are a Lot of Rules
Read “Scala In Depth”*
Implicits without the Import Tax*
*Josh Suereth
I don’t know them super well, and I haven’t cut my
arm off yet...
Friday, 11 October, 13
Creating a Protocol
Friday, 11 October, 13
Creating a Protocol
an Implicit
Friday, 11 October, 13
Creating a Protocol
an Implicit
We want:
actor emit Message(“Hello”)
Friday, 11 October, 13
Creating a Protocol
an Implicit
We want:
actor emit Message(“Hello”)
To Produce:
actor ! Envelope(ComponentType(“Client”),
ComponentType(“DBActor”),
ComponentId(“/user/supervisor/DB”),
WorkId(“764efa883dd7671c4a3bbd9e”),
MsgType(“org.my.Message”),
MsgNum(1),
Message(“Hello”))
Friday, 11 October, 13
An Actor Derivation
trait EnvelopingActor extends Actor
with EnvelopeImplicits
with ActorRefImplicits {
implicit val myCompType = ComponentType(getClass.getSimpleName)
implicit val myCompId = ComponentId(self.path)
private var currentWorkId = unknownWorkId
implicit def workId: WorkId = currentWorkId
private var currentMsgNum = MsgNum(-1)
implicit def msgNum: MsgNum = currentMsgNum
def derivedReceive: Receive
def derivedReceiveWrapper(wrapped: Receive): Receive = ???
final def receive = derivedReceiveWrapper(derivedReceive)
}
Friday, 11 October, 13
An Actor Derivation
trait EnvelopingActor extends Actor
with EnvelopeImplicits
with ActorRefImplicits {
implicit val myCompType = ComponentType(getClass.getSimpleName)
implicit val myCompId = ComponentId(self.path)
private var currentWorkId = unknownWorkId
implicit def workId: WorkId = currentWorkId
private var currentMsgNum = MsgNum(-1)
implicit def msgNum: MsgNum = currentMsgNum
def derivedReceive: Receive
def derivedReceiveWrapper(wrapped: Receive): Receive = ???
final def receive = derivedReceiveWrapper(derivedReceive)
}
Sets up the
implicits in a
high priority
scope
Friday, 11 October, 13
The Receive Wrapper
def derivedReceiveWrapper(wrapped: Receive): Receive = {
case Envelope(_, _, _, workId, _, messageNum, message) =>
currentWorkIdVar = workId
currentMessageNumVar = messageNum
wrapped(message)
case message =>
currentWorkIdVar = createWorkId()
currentMessageNumVar = MessageNum(-1)
wrapped(message)
}
Friday, 11 October, 13
The Receive Wrapper
def derivedReceiveWrapper(wrapped: Receive): Receive = {
case Envelope(_, _, _, workId, _, messageNum, message) =>
currentWorkIdVar = workId
currentMessageNumVar = messageNum
wrapped(message)
case message =>
currentWorkIdVar = createWorkId()
currentMessageNumVar = MessageNum(-1)
wrapped(message)
}
Ensures that the values that vary (workId and msgNum)
are updated in the implicit scope.
Friday, 11 October, 13
Envelope Implicits
trait EnvelopeImplicits {
import scala.language.implicitConversions
implicit def any2Envelope(a: Any)
(implicit fromCompType: ComponentType,
fromCompId: ComponentId,
workId: WorkId,
msgNum: MsgNum) =
Envelope(fromCompType, fromCompId, unknownCompId,
MsgType(a.getClass.getSimpleName),
workId, msgNum, a)
}
Allows us to substitute a concrete Envelope value where
an Any has been supplied. The implicit parameters make
this possible.
Friday, 11 October, 13
ActorRef Implicits
trait ActorRefImplicits {
implicit class PimpedActorRef(ref: ActorRef) {
def emit(envelope: Envelope)
(implicit sender: ActorRef = Actor.noSender): Unit = {
ref.tell(envelope.copy(
toComponentId = ComponentId(ref.path),
msgNum = envelope.msgNum.increment
), sender)
}
}
}
The emit method demands an Envelope. When you call
emit, that starts the implicit conversion! any2Envelope
creates it, and we update it here with better values.
Friday, 11 October, 13
Using the Protocol
class MyActor extends EnvelopingActor {
def derivedRecieve: Receive = {
case Message(str) =>
someOtherActor emit Message(s”I got: $str”)
}
}
Friday, 11 October, 13
Using the Protocol
class MyActor extends EnvelopingActor {
def derivedRecieve: Receive = {
case Message(str) =>
someOtherActor emit Message(s”I got: $str”)
}
}
Envelope(
ComponentType(“SomeActor”),
ComponentType(“MyActor”),
ComponentId(“/user/myactor”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(0),
Message(“SomeActor sent”))
Incoming
Friday, 11 October, 13
Using the Protocol
class MyActor extends EnvelopingActor {
def derivedRecieve: Receive = {
case Message(str) =>
someOtherActor emit Message(s”I got: $str”)
}
}
Envelope(
ComponentType(“SomeActor”),
ComponentType(“MyActor”),
ComponentId(“/user/myactor”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(0),
Message(“SomeActor sent”))
Incoming
Envelope(
ComponentType(“MyActor”),
ComponentType(“SomeOtherActor”),
ComponentId(“/user/someother”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(1),
Message(“I got: SomeActor sent”))
Outgoing
Friday, 11 October, 13
Using the Protocol
class MyActor extends EnvelopingActor {
def derivedRecieve: Receive = {
case Message(str) =>
someOtherActor emit Message(s”I got: $str”)
}
}
Envelope(
ComponentType(“SomeActor”),
ComponentType(“MyActor”),
ComponentId(“/user/myactor”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(0),
Message(“SomeActor sent”))
Incoming
Envelope(
ComponentType(“MyActor”),
ComponentType(“SomeOtherActor”),
ComponentId(“/user/someother”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(1),
Message(“I got: SomeActor sent”))
Outgoing
Chained
Friday, 11 October, 13
Using the Protocol
class MyActor extends EnvelopingActor {
def derivedRecieve: Receive = {
case Message(str) =>
someOtherActor emit Message(s”I got: $str”)
}
}
Envelope(
ComponentType(“SomeActor”),
ComponentType(“MyActor”),
ComponentId(“/user/myactor”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(0),
Message(“SomeActor sent”))
Incoming
Envelope(
ComponentType(“MyActor”),
ComponentType(“SomeOtherActor”),
ComponentId(“/user/someother”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(1),
Message(“I got: SomeActor sent”))
Outgoing
Maintained
Friday, 11 October, 13
Using the Protocol
class MyActor extends EnvelopingActor {
def derivedRecieve: Receive = {
case Message(str) =>
someOtherActor emit Message(s”I got: $str”)
}
}
Envelope(
ComponentType(“SomeActor”),
ComponentType(“MyActor”),
ComponentId(“/user/myactor”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(0),
Message(“SomeActor sent”))
Incoming
Envelope(
ComponentType(“MyActor”),
ComponentType(“SomeOtherActor”),
ComponentId(“/user/someother”),
WorkId(“ad7e877e41ff32a2”),
MsgType(“org.my.Message”),
MsgNum(1),
Message(“I got: SomeActor sent”))
Outgoing
Incremented
Friday, 11 October, 13
All the Implicits
Friday, 11 October, 13
All the Implicits
Pimp ActorRef with Emit
Friday, 11 October, 13
All the Implicits
Pimp ActorRef with Emit
Convert Any to envelope
Friday, 11 October, 13
All the Implicits
Pimp ActorRef with Emit
Convert Any to envelope
Simplify the API
Friday, 11 October, 13
All the Implicits
Pimp ActorRef with Emit
Convert Any to envelope
Simplify the API
actor emit Message(”Here’s a message”)
Just in case you forgot...
Friday, 11 October, 13
All the Implicits
Pimp ActorRef with Emit
Convert Any to envelope
Simplify the API
actor emit Message(”Here’s a message”)
Just in case you forgot...
SIMPLE
Friday, 11 October, 13
The Last Use Case
Friday, 11 October, 13
The Last Use Case
Implicits help you put complexity
where it belongs...
In your libraries!
&Away from your
Users!
Friday, 11 October, 13
Pitfalls
&Rules of Thumb
Friday, 11 October, 13
Pitfalls
&Rules of Thumb
Use very specific types
ComponentType(s: String) String()NOT
Friday, 11 October, 13
Pitfalls
&Rules of Thumb
Use very specific types
ComponentType(s: String) String()NOT
Enable by import, not compiler switches
Keeps libraries self-contained and avoids surprises
Friday, 11 October, 13
Pitfalls
&Rules of Thumb
Use very specific types
ComponentType(s: String) String()NOT
Enable by import, not compiler switches
Keeps libraries self-contained and avoids surprises
Push parameters to methods if you can
This keeps implicit resolution more flexible
Friday, 11 October, 13
Pitfalls
&Rules of Thumb
Use very specific types
ComponentType(s: String) String()NOT
Enable by import, not compiler switches
Keeps libraries self-contained and avoids surprises
Push parameters to methods if you can
This keeps implicit resolution more flexible
Use the right tool for the right job!!
Friday, 11 October, 13
Implicits
Scalain
Derek Wyatt
Twitter: @derekwyatt
Email: derek@derekwyatt.org
Thanks to @heathermiller for the presentation style
Source code is available at:
https://github.com/primal-github/implicit-messaging
Friday, 11 October, 13

More Related Content

Viewers also liked (20)

PDF
Effective Scala (SoftShake 2013)
mircodotta
 
PPTX
Scala’s implicits
Pablo Francisco Pérez Hidalgo
 
PDF
Real-World Scala Design Patterns
NLJUG
 
PDF
Demystifying Scala Type System
David Galichet
 
PDF
Advanced Non-Relational Schemas For Big Data
Victor Smirnov
 
PDF
Baking Delicious Modularity in Scala
Derek Wyatt
 
PDF
Implicit Explicit Scala
Kota Mizushima
 
PDF
Functor, Apply, Applicative And Monad
Oliver Daff
 
PPTX
Scala Back to Basics: Type Classes
Tomer Gabel
 
PPTX
Refactoring Design Patterns the Functional Way (in Scala)
Kfir Bloch
 
PDF
Android my Scala @ JFokus 2013
Konrad Malawski
 
PDF
Effective Scala (JavaDay Riga 2013)
mircodotta
 
PDF
[Tokyo Scala User Group] Akka Streams & Reactive Streams (0.7)
Konrad Malawski
 
ODP
Type Parameterization
Knoldus Inc.
 
PPTX
Effective Programming In Scala
Harsh Sharma
 
PDF
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Konrad Malawski
 
PPTX
Functional Programming and Concurrency Patterns in Scala
kellogh
 
PDF
Scala collections
Inphina Technologies
 
PDF
Effective Scala: Programming Patterns
Vasil Remeniuk
 
KEY
Simple Scala DSLs
linxbetter
 
Effective Scala (SoftShake 2013)
mircodotta
 
Scala’s implicits
Pablo Francisco Pérez Hidalgo
 
Real-World Scala Design Patterns
NLJUG
 
Demystifying Scala Type System
David Galichet
 
Advanced Non-Relational Schemas For Big Data
Victor Smirnov
 
Baking Delicious Modularity in Scala
Derek Wyatt
 
Implicit Explicit Scala
Kota Mizushima
 
Functor, Apply, Applicative And Monad
Oliver Daff
 
Scala Back to Basics: Type Classes
Tomer Gabel
 
Refactoring Design Patterns the Functional Way (in Scala)
Kfir Bloch
 
Android my Scala @ JFokus 2013
Konrad Malawski
 
Effective Scala (JavaDay Riga 2013)
mircodotta
 
[Tokyo Scala User Group] Akka Streams & Reactive Streams (0.7)
Konrad Malawski
 
Type Parameterization
Knoldus Inc.
 
Effective Programming In Scala
Harsh Sharma
 
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Konrad Malawski
 
Functional Programming and Concurrency Patterns in Scala
kellogh
 
Scala collections
Inphina Technologies
 
Effective Scala: Programming Patterns
Vasil Remeniuk
 
Simple Scala DSLs
linxbetter
 

Similar to Scala Implicits - Not to be feared (20)

PDF
Deconstructing Functional Programming
C4Media
 
PDF
Clojure night
Aria Haghighi
 
PDF
Introduction to ansible
Javier Arturo Rodríguez
 
KEY
groovy & grails - lecture 3
Alexandre Masselot
 
PDF
Rcos presentation
mskmoorthy
 
PDF
Macruby - RubyConf Presentation 2010
Matt Aimonetti
 
PDF
Beginners guide-concurrency
Michael Barker
 
PDF
Crystal Rocks
Brian Cardiff
 
PDF
Intro to pattern matching in scala
Jan Krag
 
PDF
De vuelta al pasado con SQL y stored procedures
Norman Clarke
 
PDF
JavaOne 2013 - Clojure for Java Developers
Jan Kronquist
 
PDF
실시간 웹 협업도구 만들기 V0.3
NAVER D2
 
PDF
Immutability
Yung-Luen Lan
 
PDF
Threequals - Case Equality in Ruby
Louis Scoras
 
PPTX
First Ride on Rust
David Evans
 
PDF
Celluloid - Beyond Sidekiq
Marcelo Pinheiro
 
PDF
Akka and the Zen of Reactive System Design
Lightbend
 
PDF
Scala in Practice
Francesco Usai
 
KEY
JavaScript Neednt Hurt - JavaBin talk
Thomas Kjeldahl Nilsson
 
PPTX
Shoulders of giants: Languages Kotlin learned from
Andrey Breslav
 
Deconstructing Functional Programming
C4Media
 
Clojure night
Aria Haghighi
 
Introduction to ansible
Javier Arturo Rodríguez
 
groovy & grails - lecture 3
Alexandre Masselot
 
Rcos presentation
mskmoorthy
 
Macruby - RubyConf Presentation 2010
Matt Aimonetti
 
Beginners guide-concurrency
Michael Barker
 
Crystal Rocks
Brian Cardiff
 
Intro to pattern matching in scala
Jan Krag
 
De vuelta al pasado con SQL y stored procedures
Norman Clarke
 
JavaOne 2013 - Clojure for Java Developers
Jan Kronquist
 
실시간 웹 협업도구 만들기 V0.3
NAVER D2
 
Immutability
Yung-Luen Lan
 
Threequals - Case Equality in Ruby
Louis Scoras
 
First Ride on Rust
David Evans
 
Celluloid - Beyond Sidekiq
Marcelo Pinheiro
 
Akka and the Zen of Reactive System Design
Lightbend
 
Scala in Practice
Francesco Usai
 
JavaScript Neednt Hurt - JavaBin talk
Thomas Kjeldahl Nilsson
 
Shoulders of giants: Languages Kotlin learned from
Andrey Breslav
 
Ad

Recently uploaded (20)

PPT
M&A5 Q1 1 differentiate evolving early Philippine conventional and contempora...
ErlizaRosete
 
PPTX
Aerobic and Anaerobic respiration and CPR.pptx
Olivier Rochester
 
DOCX
MUSIC AND ARTS 5 DLL MATATAG LESSON EXEMPLAR QUARTER 1_Q1_W1.docx
DianaValiente5
 
PDF
VCE Literature Section A Exam Response Guide
jpinnuck
 
PPTX
Comparing Translational and Rotational Motion.pptx
AngeliqueTolentinoDe
 
PPTX
How to Add New Item in CogMenu in Odoo 18
Celine George
 
PDF
Rapid Mathematics Assessment Score sheet for all Grade levels
DessaCletSantos
 
PPTX
How to use grouped() method in Odoo 18 - Odoo Slides
Celine George
 
PDF
The Power of Compound Interest (Stanford Initiative for Financial Decision-Ma...
Stanford IFDM
 
PPTX
F-BLOCK ELEMENTS POWER POINT PRESENTATIONS
mprpgcwa2024
 
PDF
Nanotechnology and Functional Foods Effective Delivery of Bioactive Ingredien...
rmswlwcxai8321
 
PDF
Learning Styles Inventory for Senior High School Students
Thelma Villaflores
 
PPTX
Peer Teaching Observations During School Internship
AjayaMohanty7
 
PPT
M&A5 Q1 1 differentiate evolving early Philippine conventional and contempora...
ErlizaRosete
 
PPTX
How to use _name_search() method in Odoo 18
Celine George
 
PDF
Lesson 1 : Science and the Art of Geography Ecosystem
marvinnbustamante1
 
PPTX
How Physics Enhances Our Quality of Life.pptx
AngeliqueTolentinoDe
 
DOCX
ANNOTATION on objective 10 on pmes 2022-2025
joviejanesegundo1
 
PDF
Andreas Schleicher_Teaching Compass_Education 2040.pdf
EduSkills OECD
 
PDF
Romanticism in Love and Sacrifice An Analysis of Oscar Wilde’s The Nightingal...
KaryanaTantri21
 
M&A5 Q1 1 differentiate evolving early Philippine conventional and contempora...
ErlizaRosete
 
Aerobic and Anaerobic respiration and CPR.pptx
Olivier Rochester
 
MUSIC AND ARTS 5 DLL MATATAG LESSON EXEMPLAR QUARTER 1_Q1_W1.docx
DianaValiente5
 
VCE Literature Section A Exam Response Guide
jpinnuck
 
Comparing Translational and Rotational Motion.pptx
AngeliqueTolentinoDe
 
How to Add New Item in CogMenu in Odoo 18
Celine George
 
Rapid Mathematics Assessment Score sheet for all Grade levels
DessaCletSantos
 
How to use grouped() method in Odoo 18 - Odoo Slides
Celine George
 
The Power of Compound Interest (Stanford Initiative for Financial Decision-Ma...
Stanford IFDM
 
F-BLOCK ELEMENTS POWER POINT PRESENTATIONS
mprpgcwa2024
 
Nanotechnology and Functional Foods Effective Delivery of Bioactive Ingredien...
rmswlwcxai8321
 
Learning Styles Inventory for Senior High School Students
Thelma Villaflores
 
Peer Teaching Observations During School Internship
AjayaMohanty7
 
M&A5 Q1 1 differentiate evolving early Philippine conventional and contempora...
ErlizaRosete
 
How to use _name_search() method in Odoo 18
Celine George
 
Lesson 1 : Science and the Art of Geography Ecosystem
marvinnbustamante1
 
How Physics Enhances Our Quality of Life.pptx
AngeliqueTolentinoDe
 
ANNOTATION on objective 10 on pmes 2022-2025
joviejanesegundo1
 
Andreas Schleicher_Teaching Compass_Education 2040.pdf
EduSkills OECD
 
Romanticism in Love and Sacrifice An Analysis of Oscar Wilde’s The Nightingal...
KaryanaTantri21
 
Ad

Scala Implicits - Not to be feared

  • 2. Agenda Lies and Damn Lies Use Cases Scope ExampleCode! Truths Rules of Thumb Friday, 11 October, 13
  • 3. Implicits are NEW Friday, 11 October, 13
  • 4. Implicits are NEW New things can be cool! Friday, 11 October, 13
  • 5. Implicits are NEW New things can be cool! New things can also be scary! ❉ Scala 2.10’s new set of warnings don’t help the situation. ❉ Friday, 11 October, 13
  • 6. Implicits are NEW New things can be cool! New things can also be scary! ❉ Scala 2.10’s new set of warnings don’t help the situation. ❉ Especially when they’re complicated! Friday, 11 October, 13
  • 7. Implicits are NEW New things can be cool! Newness + Complexness = Fearsometimes New things can also be scary! ❉ Scala 2.10’s new set of warnings don’t help the situation. ❉ Especially when they’re complicated! Friday, 11 October, 13
  • 8. Implicits are NEW New things can be cool! Newness + Complexness = Fearsometimes Fear Avoidance New things can also be scary! ❉ Scala 2.10’s new set of warnings don’t help the situation. ❉ Especially when they’re complicated! Friday, 11 October, 13
  • 9. Implicits are NEW New things can be cool! Newness + Complexness = Fearsometimes Fear Avoidance Avoidance :( New things can also be scary! ❉ Scala 2.10’s new set of warnings don’t help the situation. ❉ Especially when they’re complicated! Friday, 11 October, 13
  • 12. Implicits Are Not Global variables LIE! Friday, 11 October, 13
  • 13. Implicits Are Not Global variables Dynamically Applied LIE! DAMN LIE! Friday, 11 October, 13
  • 14. Implicits Are Not Global variables Dynamically Applied Dangerous (...much...) LIE! DAMN LIE! Fib Friday, 11 October, 13
  • 15. Implicits Are Not Global variables Dynamically Applied Dangerous (...much...) Implicits are like scissors. Use them. Don’t run with them. LIE! DAMN LIE! Fib Friday, 11 October, 13
  • 16. Use Cases What are they used for? Friday, 11 October, 13
  • 17. Use Case: Type Classes Friday, 11 October, 13
  • 18. Use Case: Type Classes val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b Friday, 11 October, 13
  • 19. Use Case: Type Classes val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b lessThan needsdefinition Friday, 11 October, 13
  • 20. Use Case: Type Classes def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean = o.lt(a, b) val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b lessThan needsdefinition Friday, 11 October, 13
  • 21. Use Case: Type Classes def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean = o.lt(a, b) val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b Ordering[Int]’s gottacome from somewhere lessThan needsdefinition Friday, 11 October, 13
  • 22. Use Case: Type Classes def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean = o.lt(a, b) implicit object intOrdering extends Ordering[Int] { def compare(a: Int, b: Int): Int = a - b } val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b Ordering[Int]’s gottacome from somewhere lessThan needsdefinition Friday, 11 October, 13
  • 23. Use Case: Type Classes def lessThan[A](a: A, b: A)(implicit o: Ordering[A]): Boolean = o.lt(a, b) implicit object intOrdering extends Ordering[Int] { def compare(a: Int, b: Int): Int = a - b } val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b Ordering[Int]’s gottacome from somewhere val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)(intOrdering)) a else b lessThan needsdefinition Friday, 11 October, 13
  • 24. Use Case: Class Extension Friday, 11 October, 13
  • 25. Use Case: Class Extension val hexVals = “implicit”.asHexSeq // Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74) The “Pimp” Friday, 11 October, 13
  • 26. Use Case: Class Extension val hexVals = “implicit”.asHexSeq // Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74) The “Pimp” implicit class HexableString(s: String) { def asHexSeq: Seq[String] = s map { c => f”0x$c%02X” } } The implicit class definition provides the extension method Friday, 11 October, 13
  • 27. Use Case: Class Extension val hexVals = “implicit”.asHexSeq // Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74) The “Pimp” implicit class HexableString(s: String) { def asHexSeq: Seq[String] = s map { c => f”0x$c%02X” } } The implicit class definition provides the extension method Bonus: If you extend implicit classes from AnyVal, no temporary object construction will occur. Friday, 11 October, 13
  • 28. Use Case: Decluttering val future1 = someCall(“a parameter”, 5.seconds) val future2 = someCall(345, 5.seconds) val future3 = someCall(235.9352, 5.seconds) Friday, 11 October, 13
  • 29. Use Case: Decluttering val future1 = someCall(“a parameter”, 5.seconds) val future2 = someCall(345, 5.seconds) val future3 = someCall(235.9352, 5.seconds) Blurgh Friday, 11 October, 13
  • 30. Use Case: Decluttering val future1 = someCall(“a parameter”, 5.seconds) val future2 = someCall(345, 5.seconds) val future3 = someCall(235.9352, 5.seconds) Blurgh def someCall[A](a: A)(implicit timeout: Duration): Future[A] = ??? But, if we define someCall this way... Friday, 11 October, 13
  • 31. Use Case: Decluttering val future1 = someCall(“a parameter”, 5.seconds) val future2 = someCall(345, 5.seconds) val future3 = someCall(235.9352, 5.seconds) Blurgh def someCall[A](a: A)(implicit timeout: Duration): Future[A] = ??? But, if we define someCall this way... implicit val myTimeoutValue = 5.seconds val future1 = someCall(“a parameter”) val future2 = someCall(345) val future3 = someCall(235.9352) And define an implicit value, we can simplify the calls... Friday, 11 October, 13
  • 32. Use Case: Internal DSLs Create your own sub-language with ease Friday, 11 October, 13
  • 33. Use Case: Internal DSLs Create your own sub-language with ease implicit class Recoverable[A](f: => A) { def recover(g: Throwable => A): A = try { f } catch { case t: Throwable => g(t) } } Friday, 11 October, 13
  • 34. Use Case: Internal DSLs Create your own sub-language with ease implicit class Recoverable[A](f: => A) { def recover(g: Throwable => A): A = try { f } catch { case t: Throwable => g(t) } } def thisThrows(): Int = throw new Exception(“Argh!”) val stable = thisThrows() recover { t => if (t.getMessage == “Argh!”) 10 else 5 } // stable == 10 Friday, 11 October, 13
  • 35. Use Case: Other stuff... Friday, 11 October, 13
  • 36. Use Case: Other stuff... Overriding defaults def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A] Friday, 11 October, 13
  • 37. Use Case: Other stuff... Overriding defaults def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A] Decoupled Dependency Injection class Database(ec: ExecutionContext) { def create(row: Row): Future[Result] = ??? def delete(id: RowId): Future[Result] = ??? // etc... } Friday, 11 October, 13
  • 38. Use Case: Other stuff... Overriding defaults def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A] Decoupled Dependency Injection class Database(ec: ExecutionContext) { def create(row: Row): Future[Result] = ??? def delete(id: RowId): Future[Result] = ??? // etc... } NO! Friday, 11 October, 13
  • 39. Use Case: Other stuff... Overriding defaults def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A] Decoupled Dependency Injection class Database { def create(row: Row)(implicit ec: ExecutionContext): Future[Result] def delete(id: RowId)(implicit ec: ExecutionContext): Future[Result] // etc... } We can now vary the ExecutionContext at any point by supplying the right implicit value Friday, 11 October, 13
  • 41. Implicit Scope Rules!!!! There are a Lot of Rules Friday, 11 October, 13
  • 42. Implicit Scope Rules!!!! There are a Lot of Rules Read “Scala In Depth”* *Josh Suereth Friday, 11 October, 13
  • 43. Implicit Scope Rules!!!! There are a Lot of Rules Read “Scala In Depth”* Implicits without the Import Tax* *Josh Suereth Friday, 11 October, 13
  • 44. Implicit Scope Rules!!!! There are a Lot of Rules Read “Scala In Depth”* Implicits without the Import Tax* *Josh Suereth I don’t know them super well, and I haven’t cut my arm off yet... Friday, 11 October, 13
  • 45. Creating a Protocol Friday, 11 October, 13
  • 46. Creating a Protocol an Implicit Friday, 11 October, 13
  • 47. Creating a Protocol an Implicit We want: actor emit Message(“Hello”) Friday, 11 October, 13
  • 48. Creating a Protocol an Implicit We want: actor emit Message(“Hello”) To Produce: actor ! Envelope(ComponentType(“Client”), ComponentType(“DBActor”), ComponentId(“/user/supervisor/DB”), WorkId(“764efa883dd7671c4a3bbd9e”), MsgType(“org.my.Message”), MsgNum(1), Message(“Hello”)) Friday, 11 October, 13
  • 49. An Actor Derivation trait EnvelopingActor extends Actor with EnvelopeImplicits with ActorRefImplicits { implicit val myCompType = ComponentType(getClass.getSimpleName) implicit val myCompId = ComponentId(self.path) private var currentWorkId = unknownWorkId implicit def workId: WorkId = currentWorkId private var currentMsgNum = MsgNum(-1) implicit def msgNum: MsgNum = currentMsgNum def derivedReceive: Receive def derivedReceiveWrapper(wrapped: Receive): Receive = ??? final def receive = derivedReceiveWrapper(derivedReceive) } Friday, 11 October, 13
  • 50. An Actor Derivation trait EnvelopingActor extends Actor with EnvelopeImplicits with ActorRefImplicits { implicit val myCompType = ComponentType(getClass.getSimpleName) implicit val myCompId = ComponentId(self.path) private var currentWorkId = unknownWorkId implicit def workId: WorkId = currentWorkId private var currentMsgNum = MsgNum(-1) implicit def msgNum: MsgNum = currentMsgNum def derivedReceive: Receive def derivedReceiveWrapper(wrapped: Receive): Receive = ??? final def receive = derivedReceiveWrapper(derivedReceive) } Sets up the implicits in a high priority scope Friday, 11 October, 13
  • 51. The Receive Wrapper def derivedReceiveWrapper(wrapped: Receive): Receive = { case Envelope(_, _, _, workId, _, messageNum, message) => currentWorkIdVar = workId currentMessageNumVar = messageNum wrapped(message) case message => currentWorkIdVar = createWorkId() currentMessageNumVar = MessageNum(-1) wrapped(message) } Friday, 11 October, 13
  • 52. The Receive Wrapper def derivedReceiveWrapper(wrapped: Receive): Receive = { case Envelope(_, _, _, workId, _, messageNum, message) => currentWorkIdVar = workId currentMessageNumVar = messageNum wrapped(message) case message => currentWorkIdVar = createWorkId() currentMessageNumVar = MessageNum(-1) wrapped(message) } Ensures that the values that vary (workId and msgNum) are updated in the implicit scope. Friday, 11 October, 13
  • 53. Envelope Implicits trait EnvelopeImplicits { import scala.language.implicitConversions implicit def any2Envelope(a: Any) (implicit fromCompType: ComponentType, fromCompId: ComponentId, workId: WorkId, msgNum: MsgNum) = Envelope(fromCompType, fromCompId, unknownCompId, MsgType(a.getClass.getSimpleName), workId, msgNum, a) } Allows us to substitute a concrete Envelope value where an Any has been supplied. The implicit parameters make this possible. Friday, 11 October, 13
  • 54. ActorRef Implicits trait ActorRefImplicits { implicit class PimpedActorRef(ref: ActorRef) { def emit(envelope: Envelope) (implicit sender: ActorRef = Actor.noSender): Unit = { ref.tell(envelope.copy( toComponentId = ComponentId(ref.path), msgNum = envelope.msgNum.increment ), sender) } } } The emit method demands an Envelope. When you call emit, that starts the implicit conversion! any2Envelope creates it, and we update it here with better values. Friday, 11 October, 13
  • 55. Using the Protocol class MyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Friday, 11 October, 13
  • 56. Using the Protocol class MyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Envelope( ComponentType(“SomeActor”), ComponentType(“MyActor”), ComponentId(“/user/myactor”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(0), Message(“SomeActor sent”)) Incoming Friday, 11 October, 13
  • 57. Using the Protocol class MyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Envelope( ComponentType(“SomeActor”), ComponentType(“MyActor”), ComponentId(“/user/myactor”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(0), Message(“SomeActor sent”)) Incoming Envelope( ComponentType(“MyActor”), ComponentType(“SomeOtherActor”), ComponentId(“/user/someother”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(1), Message(“I got: SomeActor sent”)) Outgoing Friday, 11 October, 13
  • 58. Using the Protocol class MyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Envelope( ComponentType(“SomeActor”), ComponentType(“MyActor”), ComponentId(“/user/myactor”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(0), Message(“SomeActor sent”)) Incoming Envelope( ComponentType(“MyActor”), ComponentType(“SomeOtherActor”), ComponentId(“/user/someother”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(1), Message(“I got: SomeActor sent”)) Outgoing Chained Friday, 11 October, 13
  • 59. Using the Protocol class MyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Envelope( ComponentType(“SomeActor”), ComponentType(“MyActor”), ComponentId(“/user/myactor”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(0), Message(“SomeActor sent”)) Incoming Envelope( ComponentType(“MyActor”), ComponentType(“SomeOtherActor”), ComponentId(“/user/someother”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(1), Message(“I got: SomeActor sent”)) Outgoing Maintained Friday, 11 October, 13
  • 60. Using the Protocol class MyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Envelope( ComponentType(“SomeActor”), ComponentType(“MyActor”), ComponentId(“/user/myactor”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(0), Message(“SomeActor sent”)) Incoming Envelope( ComponentType(“MyActor”), ComponentType(“SomeOtherActor”), ComponentId(“/user/someother”), WorkId(“ad7e877e41ff32a2”), MsgType(“org.my.Message”), MsgNum(1), Message(“I got: SomeActor sent”)) Outgoing Incremented Friday, 11 October, 13
  • 61. All the Implicits Friday, 11 October, 13
  • 62. All the Implicits Pimp ActorRef with Emit Friday, 11 October, 13
  • 63. All the Implicits Pimp ActorRef with Emit Convert Any to envelope Friday, 11 October, 13
  • 64. All the Implicits Pimp ActorRef with Emit Convert Any to envelope Simplify the API Friday, 11 October, 13
  • 65. All the Implicits Pimp ActorRef with Emit Convert Any to envelope Simplify the API actor emit Message(”Here’s a message”) Just in case you forgot... Friday, 11 October, 13
  • 66. All the Implicits Pimp ActorRef with Emit Convert Any to envelope Simplify the API actor emit Message(”Here’s a message”) Just in case you forgot... SIMPLE Friday, 11 October, 13
  • 67. The Last Use Case Friday, 11 October, 13
  • 68. The Last Use Case Implicits help you put complexity where it belongs... In your libraries! &Away from your Users! Friday, 11 October, 13
  • 70. Pitfalls &Rules of Thumb Use very specific types ComponentType(s: String) String()NOT Friday, 11 October, 13
  • 71. Pitfalls &Rules of Thumb Use very specific types ComponentType(s: String) String()NOT Enable by import, not compiler switches Keeps libraries self-contained and avoids surprises Friday, 11 October, 13
  • 72. Pitfalls &Rules of Thumb Use very specific types ComponentType(s: String) String()NOT Enable by import, not compiler switches Keeps libraries self-contained and avoids surprises Push parameters to methods if you can This keeps implicit resolution more flexible Friday, 11 October, 13
  • 73. Pitfalls &Rules of Thumb Use very specific types ComponentType(s: String) String()NOT Enable by import, not compiler switches Keeps libraries self-contained and avoids surprises Push parameters to methods if you can This keeps implicit resolution more flexible Use the right tool for the right job!! Friday, 11 October, 13
  • 74. Implicits Scalain Derek Wyatt Twitter: @derekwyatt Email: [email protected] Thanks to @heathermiller for the presentation style Source code is available at: https://github.com/primal-github/implicit-messaging Friday, 11 October, 13