Correct way to approach splitting a trait - scala

I have 3 traits:
trait Worker
...
trait StringWorker extends Worker {
def workString(): Iterator[String]
}
...
trait IntWorker extends Worker {
def workInt(): Iterator[Int]
}
Some of my classes extend only StringWorker, while others extend both StringWorker and IntWorker
My code obtains the correct parser depending on some pattern matching like so:
def getCorrectWorkerProvider: () => Worker = {
case SomeCase => getStringWorkerProvider()
case _ => getIntWorkerProvider()
}
If I keep the traits the same as written above, then I'll pretty much always have to do something like this pseudocode:
if working with string, then getCorrectWorkerProvider().asInstanceOf[StringWorker].workString
if working with int, then getCorrectWorkerProvider().asInstanceOf[IntWorker].workInt
whereas if I changed the definition of the traits to something like this:
trait Worker {
def workString(): Iterator[String]
def workInt(): Iterator[Int]
}
trait StringWorker extends Worker
trait IntWorker extends Worker
then I would never have to use .asInstanceOf[SomeWorker] to invoke the correct method.
I believe the first way is more correct and intuitive as the methods are specific to a certain Worker, but the second way seems to be less of a headache.

What I believe you're you're looking for is called the typeclass pattern. Here's an article that explains the idea. Basically the way it works is you create a function that takes a value of type T and an implicit parameter which is the Worker[T], and then scala's implicit resolution mechanism finds the right Worker[T] for you.
Here's an example:
object Main {
def main(args: Array[String]): Unit = {
work("String")
work(3)
}
def work[T](value: T)(implicit worker: Worker[T]) = {
worker.work(value)
}
}
trait Worker[T]{
def work(t: T): Iterator[T]
}
object Worker {
implicit val stringWorker: Worker[String] = (t: String) => Iterator(t)
implicit val intWorker: Worker[Int] = (t: Int) => Iterator(t)
}

Related

Functional reposiotory - build get() based on find()/create() methods

I have algebra like this
object Algebra {
case class Product(id: String, description: String)
case class ShoppingCart(id: String, products: List[Product])
trait ShoppingCarts[F[_]] {
def create(id: String): F[Unit]
def get(id: String): F[ShoppingCart]
def find(id: String): F[Option[ShoppingCart]]
}
}
I came up with following implementation. But I wonder if it would be possible to implement it as generic method within the trait itself. I have tried to bound context to functor to gain access to map but this is not valid construct.
override def get(id: String): ScRepoState[ShoppingCart] =
find(id).flatMap {
case Some(sc) => sc.pure[ScRepoState]
case None => create(id) *> get(id)
}
Another problem is to implement addMany() metdhod. I got something like this
def addMany[F[_] : Monad](cartId: String, products: List[Product])(implicit shoppingCarts: ShoppingCarts[F]): F[ShoppingCart] = {
for {
cart <- shoppingCarts.get(cartId)
product <- products.pure[F]
newCart <- product.traverse(product => shoppingCarts.add(cart, product))
} yield newCart
}
I struggle how to mix differetnt wrappers within single for comprehension block
But I wonder if it would be possible to implement it as generic method within the trait itself.
Not quite. Scala 2 doesn't allow traits to have parameters, but you can use an abstract class instead. You can either not use trait entirely, or have a default class with all derivable implementations, e.g.:
abstract class DefaultShoppingCarts[F[_]: Monad] extends ShoppingCarts[F] {
override def get(id: String): F[ShoppingCart] =
find(id).flatMap {
case Some(sc) => sc.pure[F]
case None => create(id) >> get(id)
}
}
This is my preferred method, but there are other options for changing traits directly.
You can add a Monad parameter to a method:
trait ShoppingCarts[F[_]] {
def create(id: String): F[Unit]
def find(id: String): F[Option[ShoppingCart]]
def get(id: String)(implicit F: Monad[F]): F[ShoppingCart] =
find(id).flatMap {
case Some(sc) => sc.pure[F]
case None => create(id) >> get(id)
}
}
This is quite different from what we did in abstract class example, b/c the use site of ShoppingCarts will be forced to have a monad available instead of construction site, and the implementor, if they want to override the method, would have to replicate the signature exactly even if that Monad[F] is not used.
You can also emulate what trait parameters would do with abstract implicit defs:
trait ShoppingCarts[F[_]] {
implicit protected def F: Monad[F]
def create(id: String): F[Unit]
def get(id: String): F[ShoppingCart] =
find(id).flatMap {
case Some(sc) => sc.pure[F]
case None => create(id) >> get(id)
}
def find(id: String): F[Option[ShoppingCart]]
}
This works but you are more likely to run into technical issues with implicit scope when implementing the F member.
I struggle how to mix different wrappers within single for comprehension block
You don't. No mixing is allowed. Don't use for-comprehension for list, only use it for F. In some more complex cases you might want to nest for comprehensions, or use a monad transformer, but here you only need to work in F. I'm also not sure what's the return type of add, but assuming it's F[ShoppingCart]:
def addMany[F[_] : Monad](cartId: String, products: List[Product])(implicit shoppingCarts: ShoppingCarts[F]): F[ShoppingCart] = {
for {
cart <- shoppingCarts.get(cartId)
results <- products.traverse(product => shoppingCarts.add(cart, product))
// results is a list of intermediate carts, get the last one; fallback if list was empty
} yield results.lastOption.getOrElse(cart)
}
Also please ask second question separately next time.

Summoning Scala implicits for subclasses of sealed abstract trait

I'm using two Scala libraries that both rely on implicit parameters to supply codecs/marshallers for case classes (the libraries in question are msgpack4s and op-rabbit). A simplified example follows:
sealed abstract trait Event
case class SomeEvent(msg: String) extends Event
case class OtherEvent(code: String) extends Event
// Assume library1 needs Show and library2 needs Printer
trait Show[A] { def show(a: A): String }
trait Printer[A] { def printIt(a: A): Unit }
object ShowInstances {
implicit val showSomeEvent = new Show[SomeEvent] {
override def show(a: SomeEvent) =
s"SomeEvent: ${a.msg}"
}
implicit val showOtherEvent = new Show[OtherEvent] {
override def show(a: OtherEvent) =
s"OtherEvent: ${a.code}"
}
}
The Printer for the one library can be generic provided there's an implicit Show for the other library available:
object PrinterInstances {
implicit def somePrinter[A: Show]: Printer[A] = new Printer[A] {
override def printIt(a: A): Unit =
println(implicitly[Show[A]].show(a))
}
}
I want to provide an API that abstracts over the details of the underlying libraries - callers should only need to pass the case class, internally to the API implementation the relevant implicits should be summoned.
object EventHandler {
private def printEvent[A <: Event](a: A)(implicit printer: Printer[A]): Unit = {
print("Handling event: ")
printer.printIt(a)
}
def handle(a: Event): Unit = {
import ShowInstances._
import PrinterInstances._
// I'd like to do this:
//EventHandler.printEvent(a)
// but I have to do this
a match {
case s: SomeEvent => EventHandler.printEvent(s)
case o: OtherEvent => EventHandler.printEvent(o)
}
}
}
The comments in EventHandler.handle() method indicate my issue - is there a way to have the compiler select the right implicits for me?.
I suspect the answer is no because at compile time the compiler doesn't know which subclass of Event handle() will receive, but I wanted to see if there's another way. In my actual code, I control & can change the PrinterInstances code, but I can't change the signature of the printEvent method (that's provided by one of the libraries)
*EDIT: I think this is the same as Provide implicits for all subtypes of sealed type. The answer there is nearly 2 years old, I'm wondering if it's still the best approach?
You have to do the pattern matching somewhere. Do it in the Show instance:
implicit val showEvent = new Show[Event] {
def show(a: Event) = a match {
case SomeEvent(msg) => s"SomeEvent: $msg"
case OtherEvent(code) => s"OtherEvent: $code"
}
}
If you absolutely need individual instances for SomeEvent and OtherEvent, you can provide them in a different object so they can be imported separately.
If Show is defined to be contravariant (i.e. as trait Show[-A] { ... }, with a minus on the generic type) then everything works out of the box and a Show[Event] is usable as a Show[SomeEvent] (and as a Show[OtherEvent] for that matter).
If Show is unfortunately not written to be contravariant, then we might have to do a little bit more juggling on our end than we'd like. One thing we can do is declare all of our SomeEvent values as simply Events, vis a vis val fooEvent: Event = SomeEvent("foo"). Then fooEvent will be showable.
In a more extreme version of the above trick, we can actually hide our inheritance hierarchy:
sealed trait Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X
}
object Event {
private case class SomeEvent(msg: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withSomeEvent(msg)
}
private case class OtherEvent(code: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withOtherEvent(code)
}
def someEvent(msg: String): Event = SomeEvent(msg)
def otherEvent(code: String): Event = OtherEvent(code)
}
Event.someEvent and Event.otherEvent allow us to construct values, and fold allows us to pattern match.

Scala: overloading methods based on provided type

Consider a simple object that serves as a storage for some cohesive data discriminated by type. I want it to have an API which is:
consistent and concise;
compile-time safe.
I can easily provide such API for saving objects by using overloading:
object CatsAndDogsStorage {
def save(key: String, cat: Cat): Future[Unit] = { /* write cat to db */ }
def save(key: String, dog: Dog): Future[Unit] = { /* save dog to Map */ }
/* other methods */
}
But I cannot find a good way to declare such methods for loading objects. Ideally, I would want something like this:
// Futures of two unrelated objects
val catFuture: Future[Cat] = CatsAndDogsStorage.load[Cat]("Lucky")
val dogFuture = CatsAndDogsStorage.load[Dog]("Lucky")
I'm fairly new to Scala, but I know that I have these options (sorted from the least preferred):
1. Different method names
def loadCat(key: String): Future[Cat] = { /* ... */ }
def loadDog(key: String): Future[Dog] = { /* ... */ }
Not the most concise method. I dislike how if I decide to rename Cat to something else, I would have to rename the method too.
2. Runtime check for provided class
def load[T: ClassTag](key: String): Future[T] = classTag[T] match {
case t if t == classOf[Dog] => /* ... */
case c if c == classOf[Cat] => /* ... */
}
This one gives the desired syntax, but it fails in runtime, not compile time.
3. Dummy implicits
def load[T <: Cat](key: String): Future[Cat] = /* ... */
def load[T <: Dog](key: String)(implicit i1: DummyImplicit): Future[Dog]
This code becomes nightmare when you have a handful of types you need to support. It also makes it quite inconvenient to remove those types
4. Sealed trait + runtime check
sealed trait Loadable
case class Cat() extends Loadable
case class Dog() extends Loadable
def load[T <: Loadable: ClassTag](key: String): Future[T] = classTag[T] match {
case t if t == classOf[Dog] => /* ... */
case c if c == classOf[Cat] => /* ... */
}
This has the advantage of 2) while preventing user from asking anything besides Dog or Cat. Still, I would rather not change the object hierarchy. I can use union types to make the code shorter.
So, the last solution is okay, but it still feels hack-ish, and maybe there is another known way which I just cannot figure out.
Having functions with sligthly different name doing similar work but for differents type doesn't seem bad for me.
If you really want to have a facade API dispatching according the type you can use typeclasses.
trait SaveFn[T] extends (T => Future[Unit]) {}
object SaveFn {
implicit object SaveDog extends SaveFn[Dog] { def apply(dog: Dog): Future[Unit] = ??? }
implicit object SaveCat extends SaveFn[Dog] { def apply(cat: Cat): Future[Unit] = ??? }
}
object Storage {
def save[T : SaveFn](in: T): Future[Unit] = implicitly[SaveFn[T]](in)
}
For the .load case:
trait LoadFn[T] extends (String => Future[T]) {}
object LoadFn {
implicit object LoadDog extends LoadFn[Dog] { def apply(key: String): Future[Dog] = ??? }
implicit object LoadCat extends LoadFn[Cat] { def apply(key: String): Future[Cat] = ??? }
}
object Storage {
def load[T : LoadFn](key: String): Future[T] = implicitly[LoadFn[T]](key)
}
As for .load the inference cannot be found according the arguments as for .save, that's less nice to use: Storage.load[Dog]("dogKey")

Extend "pimp my Iterable" to Options

Recently I have found in my code several places where I was first gathering some solutions, and then continued processing them only if the solution was unique (solution collection contained only one element). Following code is an attempt to solve this in a more functional manner.
implicit class GetOnlyOne[A](val coll: Iterable[A]) {
def getonlyone = {
if (coll.isEmpty) None
else if (coll.tail.isEmpty) coll.headOption
else None
}
}
The function can be used like:
Seq(1).getonlyone
Seq(1,2).getonlyone
Set(1).getonlyone
What currently does not work is:
Some(1).getonlyone
Could the function be improved to accept Option as well, besides of Iterables, perhaps with view bounds?
You might be able to bodge something for Option with view bounds, but the general solution is to define a typeclass: you define an interface and provide an implicit instance of that interface for each type you want to support:
trait CanGetOnlyOne[F[_]] {
def getOnlyOne[A](fa: F[A]): Option[A]
}
object CanGetOnlyOne {
implicit object CanGetOnlyOneIterable extends CanGetOnlyOne[Iterable]{
def getOnlyOne[A](fa: Iterable[A]) = ...
}
implicit object CanGetOnlyOneOption extends CanGetOnlyOne[Option] {
def getOnlyOne[A](fa: Option[A]) = fa
}
}
implicit class GetOnlyOne[F[_], A](fa: F[A])(implicit cgoo: CanGetOnlyOne[F]) {
def getonlyone = cgoo.getOnlyOne(fa)
}
Option can be implicitly converted to an Iterable, so the following works:
implicit class GetOnlyOne[A, Coll](coll: Coll)
(implicit view: Coll => Iterable[A]) {
def getonlyone = {
val it: Iterable[A] = coll
if (it.isEmpty) None
else if (it.tail.isEmpty) it.headOption
else None
}
}
However for Option is this very inefficient, because your getonlyone is essentially the identity function. Therefore, I would just introduce a second method extension just for options:
implicit class GetOnlyOneOption[A](private val opt: Option[A]) extends AnyVal {
def getonlyone = opt
}

Could not find implicit value for parameter x

Just when I thought I understood the basics of Scala's type system... :/
I'm trying to implement a class that reads the contents of a file and outputs a set of records. A record might be a single line, but it could also be a block of bytes, or anything. So what I'm after is a structure that allows the type of Reader to imply the type of the Record, which in turn will imply the correct Parser to use.
This structure works as long as MainApp.records(f) only returns one type of Reader. As soon as it can return more, I get this error:
could not find implicit value for parameter parser
I think the problem lies with the typed trait definitions at the top, but I cannot figure out how to fix the issue...
// Core traits
trait Record[T]
trait Reader[T] extends Iterable[Record[T]]
trait Parser[T] {
def parse(r: Record[T]): Option[Int]
}
// Concrete implementations
class LineRecord[T] extends Record[T]
class FileReader[T](f:File) extends Reader[T] {
val lines = Source.fromFile(f).getLines()
def iterator: Iterator[LineRecord[T]] =
new Iterator[LineRecord[T]] {
def next() = new LineRecord[T]
def hasNext = lines.hasNext
}
}
trait TypeA
object TypeA {
implicit object TypeAParser extends Parser[TypeA] {
def parse(r: Record[TypeA]): Option[Int] = ???
}
}
trait TypeB
object TypeB {
implicit object TypeBParser extends Parser[TypeB] {
def parse(r: Record[TypeB]): Option[Int] = ???
}
}
// The "app"
object MainApp {
def process(f: File) =
records(f) foreach { r => parse(r) }
def records(f: File) = {
if(true)
new FileReader[TypeA](f)
else
new FileReader[TypeB](f)
}
def parse[T](r: Record[T])(implicit parser: Parser[T]): Option[Int] =
parser.parse(r)
}
First off you must import the implicit object in order to use them:
import TypeA._
import TypeB._
That's not enough though. It seems like you're trying to apply implicits dynamically. That's not possible; they have to be found compile time.
If you import the objects as above and change the records so that the compiler finds the correct generic it will run fine:
def records(f: File) = new FileReader[TypeA](f)
But then it may not be what you were looking for ;)
The problem is that the return type of your records method is basically FileReader[_] (since it can return either FileReader[TypeA] or FileReader[TypeB]), and you don't provide an implicit argument of type Parser[Any]. If you remove the if-expression the return type is inferred to FileReader[TypeA], which works fine. I'm not sure what you're trying to do, but obviously the compiler can't select implicit argument based upon a type that is only known at runtime.
1) Using type with implicit inside as type parameter - doesn't bind this implicit to the host type, to do this change objects to the traits and mix them instead of generalizing (type-parametrizing):
def records(f: File) = {
if(true)
new FileReader(f) with TypeA
else
new FileReader(f) with TypeB
}
2) The parser should be in scope of function that calls parse. So you may try smthg like that:
def process(f: File) = {
val reader = records(f);
import reader._
reader foreach { r => parse(r) }
}
PlanB) Simpler alternative is to define type-parameter specific implicit methods inside the AppMain (or some trait mixed in), but it will work only if TypeA/TypeB is known on compile time, so records method can return concrete type:
implicit class TypeAParser(r: Record[TypeA]) {
def parse: Option[Int] = ???
}
implicit class TypeBParser(r: Record[TypeB]) {
def parse: Option[Int] = ???
}
def process[T <: TypeAorB](f: File) =
records[T](f).foreach(_.parse)
def recordsA[T <: TypeAorB](f: File) = new FileReader[T](f)
Here is, I think, the full set of modifications you need to do to get where I think you want to go.
import scala.io.Source
import java.io.File
import reflect.runtime.universe._
// Core traits
trait Record[+T]
trait Reader[+T] extends Iterable[Record[T]]
trait Parser[-T] {
def parse(r: Record[T]): Option[Int]
}
// Concrete implementations [unmodified]
class LineRecord[T] extends Record[T]
class FileReader[T](f:File) extends Reader[T] {
val lines = Source.fromFile(f).getLines()
def iterator: Iterator[LineRecord[T]] =
new Iterator[LineRecord[T]] {
def next() = new LineRecord[T]
def hasNext = lines.hasNext
}
}
sealed trait Alternatives
case class TypeA() extends Alternatives
object TypeA {
implicit object TypeAParser extends Parser[TypeA] {
def parse(r: Record[TypeA]): Option[Int] = ???
}
}
case class TypeB() extends Alternatives
object TypeB {
implicit object TypeBParser extends Parser[TypeB] {
def parse(r: Record[TypeB]): Option[Int] = ???
}
}
class ParseAlternator(parserA: Parser[TypeA], parserB: Parser[TypeB]) extends Parser[Alternatives] {
def parse(r: Record[Alternatives]): Option[Int] = r match {
case x: Record[TypeA #unchecked] if typeOf[Alternatives] =:= typeOf[TypeA] => parserA.parse(x)
case x: Record[TypeB #unchecked] if typeOf[Alternatives] =:= typeOf[TypeB] => parserB.parse(x)
}
}
object ParseAlternator {
implicit def parseAlternator(implicit parserA: Parser[TypeA], parserB: Parser[TypeB]): Parser[Alternatives] = new ParseAlternator(parserA, parserB)
}
// The "app"
object MainApp {
import ParseAlternator._
def process(f: File) =
records(f) foreach { r => parse(r) }
def records(f: File): Reader[Alternatives] = {
if(true)
new FileReader[TypeA](f)
else
new FileReader[TypeB](f)
}
def parse[T](r: Record[T])(implicit parser: Parser[T]): Option[Int] =
parser.parse(r)
}
The gist of it is: all of this would be completely classsical if only your parse instance did not have to pattern-match on a generic type but dealt directly with an Alternative instead.
It's this limitation (inherited from the JVM) that scala can't properly pattern-match on an object of a parametric type that requires the reflection & typeOf usage. Without it, you would just have type alternatives for your content (TypeA, TypeB), which you would add to a sealed trait, and which you would dispatch on, in an implicit that produces a Parser for their supertype.
Of course this isn't the only solution, it's just what I think is the meeting point of what's closest to what you're trying to do, with what's most idiomatic.