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

Scala Implicits - Not to be feared

  • 1.
    Implicits Scalain Derek Wyatt Twitter: @derekwyatt Email:derek@derekwyatt.org Friday, 11 October, 13
  • 2.
    Agenda Lies and DamnLies Use Cases Scope ExampleCode! Truths Rules of Thumb Friday, 11 October, 13
  • 3.
  • 4.
    Implicits are NEW Newthings can be cool! Friday, 11 October, 13
  • 5.
    Implicits are NEW Newthings 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 Newthings 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 Newthings 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 Newthings 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 Newthings 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
  • 10.
  • 11.
  • 12.
    Implicits Are Not Global variablesLIE! Friday, 11 October, 13
  • 13.
    Implicits Are Not Global variables DynamicallyApplied LIE! DAMN LIE! Friday, 11 October, 13
  • 14.
    Implicits Are Not Global variables DynamicallyApplied Dangerous (...much...) LIE! DAMN LIE! Fib Friday, 11 October, 13
  • 15.
    Implicits Are Not Global variables DynamicallyApplied 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 arethey used for? Friday, 11 October, 13
  • 17.
    Use Case: TypeClasses Friday, 11 October, 13
  • 18.
    Use Case: TypeClasses val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b Friday, 11 October, 13
  • 19.
    Use Case: TypeClasses val a = someInt() val b = someOtherInt() val lesser = if (lessThan(a, b)) a else b lessThan needsdefinition Friday, 11 October, 13
  • 20.
    Use Case: TypeClasses 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: TypeClasses 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: TypeClasses 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: TypeClasses 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: ClassExtension Friday, 11 October, 13
  • 25.
    Use Case: ClassExtension val hexVals = “implicit”.asHexSeq // Vector(0x69, 0x6D, 0x70, 0x6C, 0x69, 0x63, 0x69, 0x74) The “Pimp” Friday, 11 October, 13
  • 26.
    Use Case: ClassExtension 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: ClassExtension 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 valfuture1 = 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 valfuture1 = 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 valfuture1 = 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 valfuture1 = 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: InternalDSLs Create your own sub-language with ease Friday, 11 October, 13
  • 33.
    Use Case: InternalDSLs 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: InternalDSLs 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: Otherstuff... Friday, 11 October, 13
  • 36.
    Use Case: Otherstuff... Overriding defaults def func[A](a: A)(implicit tout: Duration = 3.seconds): Future[A] Friday, 11 October, 13
  • 37.
    Use Case: Otherstuff... 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: Otherstuff... 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: Otherstuff... 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
  • 40.
  • 41.
    Implicit Scope Rules!!!! There area Lot of Rules Friday, 11 October, 13
  • 42.
    Implicit Scope Rules!!!! There area Lot of Rules Read “Scala In Depth”* *Josh Suereth Friday, 11 October, 13
  • 43.
    Implicit Scope Rules!!!! There area Lot of Rules Read “Scala In Depth”* Implicits without the Import Tax* *Josh Suereth Friday, 11 October, 13
  • 44.
    Implicit Scope Rules!!!! There area 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.
  • 46.
    Creating a Protocol anImplicit Friday, 11 October, 13
  • 47.
    Creating a Protocol anImplicit We want: actor emit Message(“Hello”) Friday, 11 October, 13
  • 48.
    Creating a Protocol anImplicit 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 traitEnvelopingActor 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 traitEnvelopingActor 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 defderivedReceiveWrapper(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 defderivedReceiveWrapper(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 classMyActor extends EnvelopingActor { def derivedRecieve: Receive = { case Message(str) => someOtherActor emit Message(s”I got: $str”) } } Friday, 11 October, 13
  • 56.
    Using the Protocol classMyActor 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 classMyActor 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 classMyActor 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 classMyActor 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 classMyActor 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.
  • 62.
    All the Implicits PimpActorRef with Emit Friday, 11 October, 13
  • 63.
    All the Implicits PimpActorRef with Emit Convert Any to envelope Friday, 11 October, 13
  • 64.
    All the Implicits PimpActorRef with Emit Convert Any to envelope Simplify the API Friday, 11 October, 13
  • 65.
    All the Implicits PimpActorRef 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 PimpActorRef 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 UseCase Friday, 11 October, 13
  • 68.
    The Last UseCase Implicits help you put complexity where it belongs... In your libraries! &Away from your Users! Friday, 11 October, 13
  • 69.
  • 70.
    Pitfalls &Rules of Thumb Usevery specific types ComponentType(s: String) String()NOT Friday, 11 October, 13
  • 71.
    Pitfalls &Rules of Thumb Usevery 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 Usevery 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 Usevery 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: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