![Page 1: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/1.jpg)
An excuse to Try, Either, folding, and Future.
sequence or parsing command line options with
crappy-optional
@gerferra
![Page 2: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/2.jpg)
crappy-optional?
“Don’t worry be crappy” mantra
optional library from DRMacIverand paulp
![Page 3: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/3.jpg)
optional
optional is a command line option parser and library.
![Page 4: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/4.jpg)
optional
YOU WRITE:
object MyAwesomeCommandLineTool extends optional.Application {
// for instance...
def main(count: Option[Int], file: Option[java.io.File],
arg1: String) {
[...]
}
}
![Page 5: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/5.jpg)
optional
THEN YOU DO:
scala MyAwesomeCommandLineTool --count 5 quux
![Page 6: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/6.jpg)
optional
AND YOUR MAIN METHOD WILL BE INVOKED SUCH THAT:
count = Some(5)file = Nonearg1 = quux
![Page 7: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/7.jpg)
optional
AND YOUR MAIN METHOD WILL BE INVOKED SUCH THAT:
count = Some(5)file = Nonearg1 = quux
object MyAwesomeCommandLineTool extends optional.Application {
// for instance...
def main(count: Option[Int], file: Option[java.io.File],
arg1: String) {
[...]
}
}
scala MyAwesomeCommandLineTool --count 5 quux
Ref by name
![Page 8: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/8.jpg)
optional
AND YOUR MAIN METHOD WILL BE INVOKED SUCH THAT:
count = Some(5)file = Nonearg1 = quux
object MyAwesomeCommandLineTool extends optional.Application {
// for instance...
def main(count: Option[Int], file: Option[java.io.File],
arg1: String) {
[...]
}
}
scala MyAwesomeCommandLineTool --count 5 quux
Ref by name
Optional parameter
![Page 9: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/9.jpg)
optional
AND YOUR MAIN METHOD WILL BE INVOKED SUCH THAT:
count = Some(5)file = Nonearg1 = quux
object MyAwesomeCommandLineTool extends optional.Application {
// for instance...
def main(count: Option[Int], file: Option[java.io.File],
arg1: String) {
[...]
}
}
scala MyAwesomeCommandLineTool --count 5 quux
Ref by name
Optional parameter
Ref by position
![Page 10: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/10.jpg)
optional
HOW IT WORKS:
![Page 11: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/11.jpg)
optional
HOW IT WORKS:
Reflection, man.
![Page 12: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/12.jpg)
optional
HOW IT WORKS:
(Java) Reflection, man.
![Page 13: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/13.jpg)
optional
HOW IT WORKS:
(Java) Reflection, man.
doesn’t work OK with Scala since 2.9 (I guess) ...
used to work
![Page 14: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/14.jpg)
So...
… copy the idea, but use Scala reflection instead …
… and don’t worry and be crappy :) ...
![Page 15: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/15.jpg)
Show me the code!trait Application {
def main(args: Array[String]) {
runMain(this, args.toList)
}
private def runMain[T: ClassTag](
instance: T, args: List[String]) { // ... something happens here ...
}
}
![Page 16: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/16.jpg)
Show me the code!private def runMain[T: ClassTag](instance: T, args: List[String]) {
val instanceMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(instance)
val theType = instanceMirror.symbol.typeSignature
val methods = theType.members.collect {
case m if m.isMethod => m.asMethod
}
val mainMethods = methods.filter(m => m.name == ru.TermName("main") &&
m.fullName != classOf[Application].getName + ".main")
val methodOrError = mainMethods.headOption.toRight("No main method defined")
// Scala support multiple parameter lists, I care only about the first (if exists ...)
val = methodOrError.right.map(m => m.paramLists.headOption.getOrElse(Nil))
paramsOrError
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right // mysterious instantiation of things ...
} yield {
val refMethod = instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*) // here is the execution of the main method happening
}
invocationOrError.fold(println, identity /* nothing to do because it already executed as a side effect */)
}
![Page 17: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/17.jpg)
Step by step: method definition
Scala method:
private def runMain[T: ClassTag](
instance: T, args: List[String]) {
private, so it’s not inherited
with a type parameter T
with a context bound ClassTag
![Page 18: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/18.jpg)
Step by step: method definition
… with a context bound ClassTag?
private def runMain[T: ClassTag](
instance: T, args: List[String]) {
≡ private def runMain[T](
instance: T, args: List[String])(
implicit ev: ClassTag[T]) {
both expressions are analogous
![Page 19: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/19.jpg)
Step by step: method definition
we ask for an evidence that a ClassTag can be constructed for the type T ...
… so we can use runtime reflection on it ...
![Page 20: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/20.jpg)
Step by step: reflecting on instance
val instanceMirror =
ru
.runtimeMirror(getClass.getClassLoader)
.reflect(instance)
![Page 21: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/21.jpg)
Step by step: reflecting on instance
val instanceMirror =
ru
.runtimeMirror(getClass.getClassLoader)
.reflect(instance)
(mystic voice) …You need a mirror to access the reflection…
![Page 22: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/22.jpg)
Step by step: reflecting on instance
val instanceMirror =
ru
.runtimeMirror(getClass.getClassLoader)
.reflect(instance)
`ru` here is just an alias to packagescala.reflect.runtime.universe
import scala.reflect.runtime.{ universe => ru }
![Page 23: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/23.jpg)
Step by step: reflecting on instance
val instanceMirror =
ru
.runtimeMirror(getClass.getClassLoader)
.reflect(instance)
A ClassTag is needed here to overcome the erasure of the type at runtime T
![Page 24: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/24.jpg)
Step by step: obtaining the methodI want the methods ...
val theType =
instanceMirror.symbol.typeSignature
val methods = theType.members.collect {
case m if m.isMethod => m.asMethod
}
![Page 25: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/25.jpg)
Step by step: obtaining the method… to get the right main methods ...
val mainMethods =
methods.filter(m =>
m.name == ru.TermName("main") &&
m.fullName !=
classOf[Application].getName + ".main")
![Page 26: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/26.jpg)
Step by step: obtaining the method… to get the right main methods ...
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
Give me either the first of the methods, if there is one, or an error message
![Page 27: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/27.jpg)
Step by step: obtaining the method… to get the right main methods ...
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
Give me either the first of the methods, if there is one, or an error message
![Page 28: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/28.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
Give me either the first of the methods, if there is one, or an error message
![Page 29: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/29.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
headOption ~ List[A] => Option[A]
![Page 30: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/30.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
headOption ~ List[A] => Option[A]
Option[A] = Some(a: A) | None
![Page 31: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/31.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
headOption ~ List[A] => Option[A]
not scala (!)
Option[A] = Some(a: A) | None
![Page 32: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/32.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
headOption ~ List[A] => Option[A]
def headOption: Option[A] =
if (isEmpty) None else Some(head)
Option[A] = Some(a: A) | None
![Page 33: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/33.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
toRight[X] ~ Option[A] => (=> X) => Either[X,A]
![Page 34: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/34.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
toRight[X] ~ Option[A] => (=> X) => Either[X,A]
Either[A, B] = Left(a: A) | Right(b: B)
![Page 35: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/35.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
toRight[X] ~ Option[A] => (=> X) => Either[X,A]
def toRight[X](left: => X): Either[X,A] =
if (isEmpty) Left(left) else Right(this.get)
Either[A, B] = Left(a: A) | Right(b: B)
![Page 36: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/36.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
toRight[X] ~ Option[A] => (=> X) => Either[X,A]
def toRight[X](left: => X): Either[X,A] =
if (isEmpty) Left(left) else Right(this.get)
Either[A, B] = Left(a: A) | Right(b: B)
Either[String, ru.MethodSymbol]
![Page 37: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/37.jpg)
Step by step: obtaining the method… to get the right main methods …
val methodOrError =
mainMethods
.headOption
.toRight("No main method defined")
toRight[X] ~ Option[A] => (=> X) => Either[X,A]
def toRight[X](left: => X): Either[X,A] =
if (isEmpty) Left(left) else Right(this.get)
Either[A, B] = Left(a: A) | Right(b: B)
Either[String, ru.MethodSymbol]
![Page 38: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/38.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
Scala support multiple parameter lists. I care only about the first (if exists …)
![Page 39: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/39.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil)) Either[String, ru.MethodSymbol]
![Page 40: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/40.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil)) Either[String, ru.MethodSymbol]
only the right part please
![Page 41: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/41.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
map[X] ~ Either[A,B] => (B => X) => Either[A,X]
Either[String, ru.MethodSymbol]
only the right part please
![Page 42: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/42.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
map[X] ~ Either[A,B] => (B => X) => Either[A,X]
def map[X](f: B => X) = e match {
case Left(a) => Left(a)
case Right(b) => Right(f(b))
}
Either[String, ru.MethodSymbol]
only the right part please
![Page 43: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/43.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
List[List[ru.Symbol]]
![Page 44: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/44.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
Option[List[ru.Symbol]]
List[List[ru.Symbol]]
![Page 45: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/45.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
f: ru.MethodSymbol => List[ru.Symbol]
![Page 46: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/46.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
f: ru.MethodSymbol => List[ru.Symbol]paramsOrError: Either[String, List[ru.Symbol]]
![Page 47: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/47.jpg)
Step by step: obtaining the params
Ok. Now I need the parameters:
val paramsOrError =
methodOrError.right.map(m =>
m.paramLists
.headOption.getOrElse(Nil))
f: ru.MethodSymbol => List[ru.Symbol]paramsOrError: Either[String, List[ru.Symbol]]
paramsOrError have the parameters OR the original error "No main method defined"
![Page 48: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/48.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
![Page 49: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/49.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Same as before
![Page 50: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/50.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Same as before
The main method if all is right
![Page 51: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/51.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Same as before
The parameters if all is right
![Page 52: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/52.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Same as before
The values to use to invoke the method
![Page 53: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/53.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Same as before
The values to use to invoke the method if all is right :-)
![Page 54: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/54.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Will compute only if all OK
![Page 55: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/55.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Either[String, Any]
![Page 56: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/56.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Either[String, Any]
The first error that occurs (if any)
![Page 57: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/57.jpg)
Step by step: invocation
val invocationOrError =
for {
method <- methodOrError.right
params <- paramsOrError.right
values <- instantiate(params, args).right
} yield {
val refMethod =
instanceMirror.reflectMethod(method)
refMethod(values.unzip._2: _*)
}
Either[String, Any]
The first error that occurs (if any)
The value returned by the method (if all OK)
![Page 58: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/58.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
![Page 59: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/59.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
![Page 60: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/60.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
If you can convert the value at the left to X, and the value at the right to X, then you can convert an Either[A,B] to X
![Page 61: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/61.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
If you can convert the value at the left to X, and the value at the right to X, then you can convert an Either[A,B] to X
![Page 62: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/62.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
If you can convert the value at the left to X, and the value at the right to X, then you can convert an Either[A,B] to X
![Page 63: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/63.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
If you can convert the value at the left to X, and the value at the right to X, then you can convert an Either[A,B] to X
![Page 64: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/64.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
def fold[X](fa: A=>X, fb: B=>X) = this match {
case Left(a) => fa(a)
case Right(b) => fb(b)
}
![Page 65: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/65.jpg)
Step by step: handling ending cases
invocationOrError.fold(println, identity)
fold[X] ~
Either[A, B] => (A => X) => (B => X) => X
In this case, if there is an error (a Left value) it prints it to the console. If all went OK (a Right value) it does nothing, because the method was already executed as a side-effect
![Page 66: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/66.jpg)
instantiate?def instantiate(paramList: List[ru.Symbol], argList: List[String]): Either[Error, List[(Name, Any)]] = {
val params = paramList.map(p => p.name.encodedName.toString -> p.typeSignature)
val paramNames = params.unzip._1
val argsOptName = assignNames(argList)
val argsPartition = argsOptName.partition(_._1.isEmpty)
val unnamedArgs = argsPartition._1.unzip._2
val namedArgsTmp = argsPartition._2.collect { case (Some(n), value) => n -> value }
def sortFunc(s: String): Int = { val i = paramNames.indexOf(s); if (i == -1) Int.MaxValue else i }
val namedArgs = namedArgsTmp.sortBy(p => sortFunc(p._1))
val argsNames = namedArgs.unzip._1
val (unreferencedParams, referencedParams) = params.partition(p => !argsNames.contains(p._1))
val unreferenced = instantiateUnreferencedParams(unreferencedParams, unnamedArgs)
val referenced = instantiateParams(referencedParams, namedArgs)
for {
unref <- unreferenced.right
ref <- referenced.right
} yield {
(unref ++ ref).sortBy(p => sortFunc(p._1))
}
}
![Page 67: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/67.jpg)
More ...
assignNames
instantiateUnreferencedParams
instantiateParams
coerce
![Page 68: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/68.jpg)
Example:
Suppose we want to query user information, but it is scattered in multiple servers (ldap and database).
Most of the time we will be searching by name, but sometimes we will want to search by uid or by the user login.
And we want it now! :)
![Page 69: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/69.jpg)
Example: usr
So we create a command `usr` with the following arguments:
name: Option[String]
limit: Option[Int]
uid: Option[String]
login: Option[String]
debug: Option[Boolean]
![Page 70: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/70.jpg)
Example: usr
So we create a command `usr` with the following arguments:
name: Option[String]
limit: Option[Int]
uid: Option[String]
login: Option[String]
debug: Option[Boolean]
limit the number of results
![Page 71: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/71.jpg)
Example: usr
So we create a command `usr` with the following arguments:
name: Option[String]
limit: Option[Int]
uid: Option[String]
login: Option[String]
debug: Option[Boolean] extra debug info?
![Page 72: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/72.jpg)
Example: usr
So we create a command `usr` with the following arguments:
name: Option[String]
limit: Option[Int]
uid: Option[String]
login: Option[String]
debug: Option[Boolean]
First so they can be used without name
![Page 73: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/73.jpg)
Example: usr
So we create a command `usr` with the following arguments:
name: Option[String]
limit: Option[Int]
uid: Option[String]
login: Option[String]
debug: Option[Boolean]
Any individual argument is optional
![Page 74: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/74.jpg)
Example: usr
So we create a command `usr` with the following arguments:
name: Option[String]
limit: Option[Int]
uid: Option[String]
login: Option[String]
debug: Option[Boolean]
String, Int, Boolean ...
![Page 75: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/75.jpg)
Example: usr
Some usage examples:
usr "juan perez"
usr "juan perez" 10
usr --uid jperez
usr --login jperez --limit 10 --debug
![Page 76: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/76.jpg)
Example: usr
object usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String], login: Option[String], debug: Option[Boolean]) {
// THE LOGIC ...
}}
![Page 77: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/77.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
![Page 78: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/78.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
One of them must be specified
![Page 79: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/79.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
No debug by default
![Page 80: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/80.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
Query the three sources in parallel
![Page 81: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/81.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
After completion, print the result as a side effect
![Page 82: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/82.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
Wait until the three queries finish
![Page 83: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/83.jpg)
Example: usrobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
Has a bug!
![Page 84: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/84.jpg)
Example: completing futures
futRes.onComplete(printResult)
def onComplete[U](f: Try[T] => U): Unit
Try[T] = Success(t: T) | Failure(e: Throwable)
![Page 85: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/85.jpg)
futRes.onComplete(printResult)
def onComplete[U](f: Try[T] => U): Unit
Example: completing futures
Either[Throwable, T]~~
Try[T] = Success(t: T) | Failure(e: Throwable)
![Page 86: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/86.jpg)
futRes.onComplete(printResult)
def onComplete[U](f: Try[T] => U): Unit
When this Future finishes, either correctly (Success) or with an exception (Failure), apply the function f which knows how to handle both cases to compute some side effect
Example: completing futures
Either[Throwable, T]Try[T] = Success(t: T) | Failure(e: Throwable)
~~
![Page 87: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/87.jpg)
futRes.onComplete(printResult)
def onComplete[U](f: Try[T] => U): Unit
In this case the side effect is just printing the result to the console.
Example: completing futures
Either[Throwable, T]~~
Try[T] = Success(t: T) | Failure(e: Throwable)
![Page 88: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/88.jpg)
Future.sequence(
Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB))
def sequence[A, M[_]](
in: M[Future[A]]): Future[M[A]]
Example: sequencing futures
![Page 89: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/89.jpg)
Future.sequence(
Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB))
def sequence[A, M[_]](
in: M[Future[A]]): Future[M[A]]
Convert some container M of Future[A] in a Future M[A].
Example: sequencing futures
![Page 90: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/90.jpg)
Future.sequence(
Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB))
def sequence[A, M[_]](
in: M[Future[A]]): Future[M[A]]
Convert some container M of Future[A] in a Future M[A].
Example: sequencing futuresM[X] <: TraversableOnce[X]
![Page 91: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/91.jpg)
Future.sequence(
Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB))
def sequence[A, M[_]](
in: M[Future[A]]): Future[M[A]]
Convert some container M of Future[A] in a Future M[A].Useful to reduce many Futures into a single Future.
Example: sequencing futures
![Page 92: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/92.jpg)
Future.sequence(
Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB))
def sequence[A, M[_]](
in: M[Future[A]]): Future[M[A]]
Convert some container M of Future[A] in a Future M[A].Useful to reduce many Futures into a single Future.In this case we reduce three independent future results to a single future result with a Seq of the individual results.
Example: sequencing futures
![Page 93: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/93.jpg)
implicit class TryHarder[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] = t match { case Success(s) => Right(s) case Failure(f) => Left(f) }
def fold[U](success: T => U, failure: Throwable => U): U = toEither.fold(failure, success)}
Example: folding on Try
![Page 94: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/94.jpg)
implicit class TryHarder[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] = t match { case Success(s) => Right(s) case Failure(f) => Left(f) }
def fold[U](success: T => U, failure: Throwable => U): U = toEither.fold(failure, success)}
Example: folding on Try
Try is pretty much a specialized Either
![Page 95: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/95.jpg)
implicit class TryHarder[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] = t match { case Success(s) => Right(s) case Failure(f) => Left(f) }
def fold[U](success: T => U, failure: Throwable => U): U = toEither.fold(failure, success)}
Example: folding on Try
Try is pretty much a specialized Either
![Page 96: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/96.jpg)
Example: fixing the bugobject usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
futUsrLDAPA.onComplete(printResult("--- LDAP A ---", debug = effDebug))
futUsrLDAPB.onComplete(printResult("--- LDAP B ---", debug = effDebug))
futUsrDB.onComplete(printResult("--- Data Base ---", debug = effDebug))
val res = Await.ready(
Future.sequence(Seq(futUsrLDAPA, futUsrLDAPB, futUsrDB)), Duration.Inf)
}
}
The problem is that onComplete executes after the Future is completed. Await only awaits to the completion, not the execution of onComplete and the program can terminate “too soon”.
![Page 97: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/97.jpg)
implicit class FutureOps[T](val f: Future[T])
extends AnyVal {
def continue[S]( cont: Try[T] => S): Future[S] = {
val p = Promise[S]() f.onComplete { tt => p.complete(Try(cont(tt))) } p.future
}}
Example: fixing the bug
![Page 98: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/98.jpg)
implicit class FutureOps[T](val f: Future[T])
extends AnyVal {
def continue[S]( cont: Try[T] => S): Future[S] = {
val p = Promise[S]() f.onComplete { tt => p.complete(Try(cont(tt))) } p.future
}}
Example: fixing the bug
Like onComplete but returning another Future
![Page 99: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/99.jpg)
Example: now works :)object usr extends optional.Application {
def main(name: Option[String], limit: Option[Int], uid: Option[String],
login: Option[String], debug: Option[Boolean]) {
if (Seq(name, uid, login).flatten.isEmpty) {
println("You must specify at least one search criteria")
System.exit(1)
}
val effDebug = debug.getOrElse(false)
val futUsrLDAPA = Future { ldapA.findUsr(name, limit, uid, login) }
val futUsrLDAPB = Future { ldapB.findUsr(name, limit, uid, login) }
val futUsrDB = Future { dbase.findUsr(name, limit, uid, login) }
val endLDAPA = futUsrLDAPA.continue(printResult("--- LDAP A ---"))
val endLDAPB = futUsrLDAPB.continue(printResult("--- LDAP B ---"))
val endDB = futUsrDB.continue(printResult("--- Data Base ---"))
val res = Await.ready(
Future.sequence(Seq(endLDAPA, endLDAPB, endDB)), Duration.Inf)
}
}
![Page 100: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/100.jpg)
github.com/gerferra/crappy-optional
FIN
sub
![Page 101: An excuse to Try, Either, folding, and Future. sequence](https://reader033.vdocuments.mx/reader033/viewer/2022052900/5560e87ad8b42a3d768b5063/html5/thumbnails/101.jpg)
mini-demo?
FIN