I will try to be as clear as possible.
I have this class that combines two other classes HBaseCREvent and HBaseCR:
class HBaseCREvent(val rowKey : scala.Predef.String, val actualEnd : scala.Predef.String, val actualImpact : scala.Predef.String, val actualStart : scala.Predef.String)
class combinedType[T]
object combinedType {
implicit object HBaseCREventWitness extends combinedType[HBaseCREvent]
implicit object HBaseCRWitness extends combinedType[HBaseCR]
}
and I have a method to implement like this
def convertHBaseObj[T:combinedType](event: T) : CRInput = {
event match {
case t # (_: HBaseCREvent | _: HBaseCR) => {
this.setActualEnd(t.actualEnd)
this.setActualImpact(t.actualImpact)
this.setActualStart(t.actualStart)
}
}
}
I am trying to avoid repeating the same set of statements when the input is of type HBaseCREvent or HBaseCR.
However, this approach does not work. My IDE cannot resolve the attributes (t.actualEnd, t.actualImpact, etc).
I have also tried this:
def convertHBaseObj[T:combinedType](event: T) : CRInput = {
event match {
case t: HBaseCREvent|HBaseCR => {
this.setActualEnd(t.actualEnd)
this.setActualImpact(t.actualImpact)
this.setActualStart(t.actualStart)
}
}
}
but I got an error:
illegal variable in pattern alternative
Any help on this?
Thanks
If you have control of HBaseCREvent, HBaseCR then extract your methods into a trait and implement that.
trait MyTrait {
def actualEnd = ???
def actualImpact = ???
def actualEnd = ???
}
def convertHBaseObj(t: MyTrait) = {
setActualEnd(t.actualEnd)
setActualImpact(t.actualImpact)
setActualStart(t.actualStart)
}
If you don't have control then you could do something like the following. I am re-using CombinedEvent here because your version doesn't do anything.
trait CombinedType[T] {
def actualEnd = ???
def actualImpact = ???
def actualEnd = ???
}
implicit def HBaseCREvent2CombinedType(t: HBaseCREvent) = new CombinedType[HBaseCREvent] {
def actualEnd = t.actualEnd
def actualImpact = t.actualImpact
def actualEnd = t.actualEnd
}
implicit def HBaseCR2CombinedType(t: HBaseCR) = new CombinedType[HBaseCR] {
def actualEnd = t.actualEnd
def actualImpact = t.actualImpact
def actualEnd = t.actualEnd
}
def convertHBaseObj[T](event: T)(implicit combinedEvent: CombinedEvent[T]) = {
setActualEnd(combinedEvent.actualEnd)
setActualImpact(combinedEvent.actualImpact)
setActualStart(combinedEvent.actualStart)
}
Either solution is better than your pattern matching implementation because they will fail at compile time rather than at runtime if the wrong type is passed to convertHBaseObj
Related
I want to bind a check method to the Test in such a way that the implementation does not contain an argument (look at the last line). It is necessary to use type classes here, but I'm new in Scala, so I have problems.
Object Checker is my attempts to solve the problem. Perhaps it is enough to make changes to it...
trait Test[+T] extends Iterable[T]
class TestIterable[+T](iterable: Iterable[T]) extends Test[T] {
override def iterator: Iterator[T] = iterable.iterator
}
object Test {
def apply[T](iterable: Iterable[T]): Test[T] = new TestIterable[T](iterable)
}
trait Check[M] {
def check(m: M): M
}
object Checker {
def apply[M](implicit instance: Check[M]): Check[M] = instance
implicit def checkSyntax[M: Check](m: M): CheckOps[M] = new CheckOps[M](m)
private implicit def test[T](m: Test[T]) : Check[Test[T]] = {
new Check[Test[T]] {
override def check(m: Test[T]) = m
}
}
final class CheckOps[M: Check](m: M) {
def x2: M = Checker[M].check(m)
}
}
import Checker._
val test123 = Test(Seq(1, 2, 3))
Test(test123).check
I have
trait OptionTransaction {
def data: Data
}
BuyOptionTransaction extends OptionTransaction
SellOptionTransaction extends OptionTransaction
I use these with a Formatter type class to create string representations of various transactions
trait Formatter[T] {
def format(ot:T):String
}
object Formatter {
def apply[T](implicit screen: Formatter[T]) = screen
implicit val buyOT = new Formatter[BuyOptionTransaction] {
def format(ot: BuyOptionTransaction):String = ot.x.toString
}
implicit val sellOT = new Formatter[SellOptionTransaction] {
def format(ot: SellOptionTransaction):String = ot.y.toString
}
}
This is the entry point:
import Formatter._
val closeTransactions: List[OptionTransaction] = ...
closeTransactions.map(startFormat)
The problem is that closeTransactions has type List[OptionTransaction] and the type class needs OptionTransaction downcast to BuyOptionTransaction or SellOptionTransaction otherwise it won't find the implicit formatter.
How can I achieve this downcast automatically?
If you want to deal with the polymorphism runtime, you need to implement some kind of dynamic (runtime) dispatch instead of Type classes, which are static one (compile time). It could look like this:
type Data = String
trait OptionTransaction {
def data: Data = ""
}
class BuyOptionTransaction extends OptionTransaction {
def x: String = "X"
}
class SellOptionTransaction extends OptionTransaction {
def y: String = "Y"
}
trait Formatter[T] {
def format(ot:T):String
}
object Formatter {
def apply[T](implicit screen: Formatter[T]) = screen
def selectFormatter[T](obj: T)(implicit formatter: Formatter[T]) = formatter
implicit val buyOT = new Formatter[BuyOptionTransaction] {
def format(ot: BuyOptionTransaction):String = ot.x.toString
}
implicit val sellOT = new Formatter[SellOptionTransaction] {
def format(ot: SellOptionTransaction):String = ot.y.toString
}
implicit val ot = new Formatter[OptionTransaction] {
def format(ot: OptionTransaction):String = ot match {
case ot: BuyOptionTransaction =>
selectFormatter(ot).format(ot)
case ot: SellOptionTransaction =>
selectFormatter(ot).format(ot)
}
}
}
def startFormat[T](ot: T)(implicit ev: Formatter[T]) = {
ev.format(ot)
}
import Formatter._
val closeTransactions: List[OptionTransaction] = List(new BuyOptionTransaction, new SellOptionTransaction)
closeTransactions.map(startFormat(_))
You can collect the appropriate types:
val closeTransactions: List[OptionTransaction] = ???
val buys = closeTransactions.collect { case b: BuyOptionTransaction => b}
val sells = closeTransactions.collect { case s: SellOptionTransaction => s}
Now you can apply the proper typeclasses.
It would be probably better to add the action/transformation you want to the OptionTransaction trait and use that for dynamic binding. If you want to keep working only for one of them, please take a look at this answer.
I have a requirement to intercept toString of DateTime, LocalDate and Option in the runTime.
#implicitNotFound("No member of type class ReportString in scope for ${T}")
trait ReportStringTransformer[T] {
def toReportString(e: T): String
}
object ReportStringTransformer {
implicit object ReportStringTransformerDateTime
extends ReportStringTransformer[DateTime] {
override def toReportString(e: DateTime): String =
ISODateTimeFormat.dateTime().print(e)
}
implicit object ReportStringTransformerDate
extends ReportStringTransformer[LocalDate] {
override def toReportString(e: LocalDate): String =
ISODateTimeFormat.date().print(e)
}
implicit def ReportStringTransformerOpt[T]: ReportStringTransformer[Option[T]] =
new ReportStringTransformer[Option[T]] {
override def toReportString(e: Option[T]): String = e match {
case Some(obj) => ReportStringTransform.transform(obj)
case None => ""
}
}
}
object ReportStringTransform {
def transform[T](obj: T)(implicit t: ReportStringTransformer[T]): String =
t.toReportString(obj)
}
I could add a default transformer for Any class at the end which could only
be picked up after these, but is there any other cleaner way to do?
Your implementation could be simplified as follows:
#implicitNotFound("No member of type class Show in scope for ${T}")
case class Show[T](f: T => String) extends AnyVal
object Show {
implicit val showDateTime = Show[DateTime](ISODateTimeFormat.dateTime() print _)
implicit val showDate = Show[LocalDate](ISODateTimeFormat.date() print _)
implicit def showOpt[T](implicit s: Show[T]) = Show[Option[T]](_.fold("")(s.f))
}
To have a fallback for anything that is not a DateTime, a LocalDate or an Option of either the these, you could the following trait as a paraent of object Show
trait LowPriorityShow {
implicit def showAnything[T] = Show[T](_.toString)
}
object Show extends LowPriorityShow { ... }
Probably late to the party, but your issue on your gist here, is that the implicit resolution picks up the type Some[String] for the second case you put. other than that, the solution given by OlivierBlanvillain is great and it should solve your needs.
You can verify that this is your case by casting to Option[String]
println(MyShow.show(Some("abc"): Option[String])) // this will work as you expected
playing with variance/covariance you can make it work as expected link.
import org.joda.time.{DateTime, DateTimeZone}
import org.joda.time.format.ISODateTimeFormat
trait Show[-T] {
def show: T => String
}
trait LowPriorityShow {
implicit def showAnything[T] = new Show[T] {
def show: T => String = _.toString
}
}
object Show extends LowPriorityShow {
implicit val showString: Show[String] = new Show[String] {
def show: String => String = identity
}
implicit val showDateTime: Show[DateTime] =
new Show[DateTime] {
def show: DateTime => String =
ISODateTimeFormat.dateTime().withZone(DateTimeZone.forID("America/New_York")).print
}
implicit def showOpt[T : Show]: Show[Option[T]] =
new Show[Option[T]] {
def show: Option[T] => String = _.fold("")(implicitly[Show[T]].show)
}
def show[T : Show](v: T): String = implicitly[Show[T]].show(v)
}
println(Show.show(DateTime.now()))
println(Show.show(Some("abc")))
println(Show.show(12))
I am trying to implement a cake pattern like code, but I get:
Error:(47, 36) illegal inheritance;
self-type app.server.im.Im_Api_Service_Impl.type does not conform to app.server.im.Persistence[app.server.im.State.State]'s selftype app.server.im.Persistence[app.server.im.State.State] with app.server.im.Persistable[app.server.im.State.State]
object Im_Api_Service_Impl extends Persistence[State.State]
with the code below.
What might be the problem ?
I looked at this SOF question, but it seems to describe a different scenerio (or maybe I am just not seeing the similarity).
import app.shared.IndexChange
import app.shared.apiAndModel.im.{CanCreateEntity, Im_Api_Interface, LineShared, LineSharedPayload, UUID}
import upickle.default._
object State {
type State = Seq[LineShared]
}
trait Im_Api_Service extends Im_Api_Interface with Persistable[State.State] {
implicit object CanCreate extends CanCreateEntity
import State.State
val init = List("egy", "ketto", "harom", "negy", "ot", "hat", "het", "nyolc").map(LineSharedPayload(_)).map(LineShared(_))
val fileNameForPersistence="state"
var state: State = init
def setState(s:State)={state=s}
override def getLines(): Seq[LineShared] = state
def moveLine(ls: State, from: Int, to: Int): Seq[LineShared] = {
val r=IndexChange(from, to).updatedList[LineShared](ls.toList)
r
}
override def moveLine(from: Int, to: Int): Seq[LineShared] = {state=moveLine(state, from, to);state;}
override def newLine(pl: LineSharedPayload): Seq[LineShared] = {
setState(state :+ LineShared(pl))
state
}
def getLine(ls:State, id: UUID): Option[LineShared] = ls.find(_.id == id)
override def getLine(id: UUID): Option[LineShared] = getLine(state,id)
override def updateLine(l: LineShared): State = {
setState(state.map(ll => if (ll~l) l else ll ))
state
}
}
object Im_Api_Service_Impl extends Persistence[State.State]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
illegal inheritance problem HERE
trait Persistable[State]
{
val fileNameForPersistence:String
var state :State
}
trait Persistence[State] { this:Persistable[State] =>
def serializeState(s: State): String = write(s)
// TODO add timestamp to filename
def saveState(): Unit = writeToFile(serializeState(state), fileNameForPersistence)
def loadState(): Unit = {
try {
state = deserializeState(readFromFile(fileNameForPersistence))
}
catch {
case e: Exception => println(e)
}
}
def writeToFile(s: String, fn: String): Unit = {
import java.io._
val pw = new PrintWriter(new File(fn))
pw.write(s)
pw.close
}
def readFromFile(fn: String): String = {
val source = scala.io.Source.fromFile(fn)
val lines: String = try source.mkString finally source.close()
lines
}
def deserializeState(s: String): State = read[State](s)
}
You have promised that trait Persistence would only be mixed into a class that extends Persistable: trait Persistence[State] { this:Persistable[State].
Instead, your object extends Persistence[State.State]. Is that the same thing?
I have written automatic type class derivation in order to automatically generate elasticsearch Json mapping for case classes.
For that I am using the TypeClass type class in shapeless.
The problem I have is that many fields in the case classes we use are Scala enumerations.
For example
object ConnectionState extends Enumeration {
type ConnectionState = Value
val ordering, requested, pending, available, down, deleting, deleted, rejected = Value
}
Or
object ProductCodeType extends Enumeration {
type ProductCodeType = Value
val devpay, marketplace = Value
}
It seems I have to define a specific implicit instance for every Enumeration that is defined in order that the automatic derivation will pick it up (e.g. for both ConnectionState and ProductCodeType).
I cannot have one implicit def for Enumeration such as
implicit def enumerationMapping: MappingEncoder[Enumeration] = new MappingEncoder[Enumeration] {
def toMapping = jSingleObject("type", jString("text"))
}
that will work for all enumeration types.
I tried making the type class covariant, and a bunch of other things but nothing helped.
Any ideas?
Here is the derivation code:
object Mapping {
trait MappingEncoder[T] {
def toMapping: Json
}
object MappingEncoder extends LabelledProductTypeClassCompanion[MappingEncoder] {
implicit val stringMapping: MappingEncoder[String] = new MappingEncoder[String] {
def toMapping = jSingleObject("type", jString("text"))
}
implicit val intMapping: MappingEncoder[Int] = new MappingEncoder[Int] {
def toMapping = jSingleObject("type", jString("integer"))
}
implicit def seqMapping[T: MappingEncoder]: MappingEncoder[Seq[T]] = new MappingEncoder[Seq[T]] {
def toMapping = implicitly[MappingEncoder[T]].toMapping
}
implicit def optionMapping[T: MappingEncoder]: MappingEncoder[Option[T]] = new MappingEncoder[Option[T]] {
def toMapping = implicitly[MappingEncoder[T]].toMapping
}
object typeClass extends LabelledProductTypeClass[MappingEncoder] {
def emptyProduct = new MappingEncoder[HNil] {
def toMapping = jEmptyObject
}
def product[F, T <: HList](name: String, sh: MappingEncoder[F], st: MappingEncoder[T]) = new MappingEncoder[F :: T] {
def toMapping = {
val head = sh.toMapping
val tail = st.toMapping
(name := head) ->: tail
}
}
def project[F, G](instance: => MappingEncoder[G], to: F => G, from: G => F) = new MappingEncoder[F] {
def toMapping = jSingleObject("properties", instance.toMapping)
}
}
}
}
I was able to fix the problem by adding additional implicit defs to scope:
implicit def enumerationMapping[T <: Enumeration#Value]: MappingEncoder[T] = new MappingEncoder[T] {
def toMapping = jSingleObject("type", jString("text"))
}
implicit def enumerationSeqMapping[T <: Enumeration#Value]: MappingEncoder[Seq[T]] = new MappingEncoder[Seq[T]] {
def toMapping = jSingleObject("type", jString("text"))
}
The second implicit was needed as some of the case classes had members of type Seq[T] where T is some enumeration type.