Understanding IO and .mapError in SCALA - scala

Can anyone pls expain the IO.effect(a)
.mapError(SecretsError.exception) in the below effect method. Thanks
import org.json.JSONObject
import zio.IO
object Secrets {
sealed trait SecretsError
object SecretsError {
final case class ExceptionEncountered(message: String) extends SecretsError
def exception(e: Throwable): SecretsError =
ExceptionEncountered(s"Exception: ${Apps.stackTrace(e)}")
}
private def effect[A](a: => A): IO[SecretsError, A] =
IO.effect(a)
.mapError(SecretsError.exception)```

Related

Can Scala Companion Object Traits call a constructor of the class?

I'm trying to solve a problem that may not be possible in Scala.
I want to have a Trait to solve default constructors
trait Builder[T <: Buildable] {
def build(code: String): T = new T(code)
def build: T = new T("bar")
}
So extending the Trait on the companion object automatically has access to functions that creates the class with specific constructors and parameters
class A(code: String) extends Buildable
object A extends Builder[A]
Extending the Trait, the companion object has the constructors
A.build("foo")
A.build
Is this possible in Scala?
Also tried abstract classes, but hadn't had any success
trait Builder[T <: BuildableClass] {
def build(code: String): T = new T(code)
def build: T = new T("bar")
}
abstract class BuildableClass(code: String)
class A(code: String) extends BuildableClass(code)
object A extends Builder[A]
Thanks in advance
Edit: currently locked on Scala 2.12
Because of the type erasure, in ordinary code new T is allowed only for class type T, not an abstract type/type parameter.
In Scala, is it possible to instantiate an object of generic type T?
How to create an instance of type T at runtime with TypeTags
Class type required but T found
An alternative to runtime reflection (see #StanislavKovalenko's answer) is macros. new T is possible there because during macro expansion T is not erased yet.
import scala.language.experimental.macros
import scala.reflect.macros.blackbox // libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
abstract class BuildableClass(code: String)
trait Builder[T <: BuildableClass] {
def build(code: String): T = macro BuilderMacros.buildImpl[T]
def build: T = macro BuilderMacros.buildDefaultImpl[T]
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
def buildImpl[T: WeakTypeTag](code: Tree): Tree = q"new ${weakTypeOf[T]}($code)"
def buildDefaultImpl[T: WeakTypeTag]: Tree = q"""new ${weakTypeOf[T]}("bar")"""
}
// in a different subproject
class A(code:String) extends BuildableClass(code)
object A extends Builder[A]
A.build("foo") // scalac: new A("foo")
A.build // scalac: new A("bar")
Alternative implementations:
trait Builder[T <: BuildableClass] {
def build(code: String): T = macro BuilderMacros.buildImpl
def build: T = macro BuilderMacros.buildDefaultImpl
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = c.prefix.tree.tpe.baseType(symbolOf[Builder[_]]).typeArgs.head
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val symb = c.prefix.tree.symbol.companion
def buildImpl(code: Tree): Tree = q"new $symb($code)"
def buildDefaultImpl: Tree = q"""new $symb("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = c.prefix.tree.tpe.companion
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = symbolOf[Builder[_]].typeParams.head.asType.toType
.asSeenFrom(c.prefix.tree.tpe, symbolOf[Builder[_]])
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
One of the potential solution that uses a reflection looks a bit ugly, but it works.
import scala.reflect._
trait Builder[T <: Buildable] {
def build(code: String)(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getConstructors()(0).newInstance(code).asInstanceOf[T]
def build(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getConstructors()(0).newInstance("bar").asInstanceOf[T]
}
trait Buildable
class A(code: String) extends Buildable {
def getCode = code
}
object A extends Builder[A]
val a: A = A.build
println(a.getCode)
The problem is that your Builder trait doesn't know anything about how to construct your instances. You can get this info from runtime with reflection or from compile time with macros.
Found a much cleaner solution to this problem without using macros / reflection / implicits
trait Buildable
trait Builder[T <: Buildable] {
self =>
def apply(code: String): T
def build: T = self.apply("foo")
def build(code: String): T = self.apply(code)
}
case class A(code: String) extends Buildable {
def getCode: String = code
}
object A extends Builder[A]
A.build("bar").getCode
A.build.getCode

How to determine if a class is a subclass of a parent class or trait?

In Scala, how can we determine if a class is a subclass of a parent class or a trait? For example:
trait MyTrait
class MyParentClass()
class MyOtherParentClass()
case class MySubClass() extends MyParentClass with MyTrait
case class MyOtherSubClass() extends MyOtherParentClass
Is it possible to identify if class such as MySubClass extends from MyParentClass or MyTrait without instantiating an object and through reflection APIs? Given an unknown generic type T, I am interested in having it match a case if T extends a particular parent class or a trait:
def example[T](): Unit = {
T match {
case if T extends MyParentClass => ...
case if T extends MyOtherParentClass => ...
case if T extends MyOtherTrait => ...
case _ => default case ...
}
If you write
case class MySubClass() extends MyParentClass with MyTrait
then obviously MySubClass extends MyParentClass and MyTrait so you can check that for a generic type T with
def test[T](implicit ev: T <:< MyParentClass, ev1: T <:< MyTrait) = ???
test[MySubClass] // compiles
at compile time.
If the thing is you want to check that with OR instead of AND, then you can use shapeless.OrElse or implicitbox.Priority
Scala method that needs either one of two implicit parameters
I updated the question with an example of the desired usage
It seems you want a type class
trait Example[T] {
def example(): Unit
}
object Example {
implicit def subtypeOfMyParentClass[T <: MyParentClass] = new Example[T] {
override def example(): Unit = ???
}
implicit def subtypeOfMyOtherParentClass[T <: MyOtherParentClass] = new Example[T] {
override def example(): Unit = ???
}
implicit def subtypeOfMyOtherTrait[T <: MyOtherTrait] = new Example[T] {
override def example(): Unit = ???
}
implicit def default[T] = new Example[T] {
override def example(): Unit = ???
}
}
def example[T]()(implicit e: Example[T]): Unit = e.example()
A type class is a compile-time (i.e. type-level) replacement for pattern matching.
If there is ambiguity among implicits you can prioritize them.
Just curious, do you know if there is a way to do this in a simple one line conditional such as if (T extends from MyParentClass) then ... through reflection APIs (is it possible through classOf[] or typeOf[]?)
You can do that at runtime
import scala.reflect.runtime.universe._
def example[T: TypeTag](): Unit =
if (typeOf[T] <:< typeOf[MyParentClass]) ???
else if (typeOf[T] <:< typeOf[MyOtherParentClass]) ???
else if (typeOf[T] <:< typeOf[MyOtherTrait]) ???
else ???
or
import scala.reflect.ClassTag
def example[T: ClassTag](): Unit =
if (classOf[MyParentClass] isAssignableFrom classOf[T]) ???
else if (classOf[MyOtherParentClass] isAssignableFrom classOf[T]) ???
else if (classOf[MyOtherTrait] isAssignableFrom classOf[T]) ???
else ???
or at compile time
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def example[T](): Unit = macro exampleImpl[T]
def exampleImpl[T: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
import c.universe._
if (weakTypeOf[T] <:< typeOf[MyParentClass]) ???
else if (weakTypeOf[T] <:< typeOf[MyOtherParentClass]) ???
else if (weakTypeOf[T] <:< typeOf[MyOtherTrait]) ???
else ???
}
But implicits and types is a preferable way rather than (compile-time or especially runtime) reflection. It's not clear why you need reflection at all.
https://users.scala-lang.org/t/how-to-access-the-method/6281

Is it possible to override an implicit object contained within a trait that is being extended?

I have a wrapper trait that extends BasicFormats from spray json https://github.com/spray/spray-json/blob/release/1.3.x/src/main/scala/spray/json/BasicFormats.scala
but I would like to override the behavior of implicit object BigDecimalJsonFormat extends JsonFormat[BigDecimal] to add rounding logic. Example being
import spray.json._
import scala.math.BigDecimal.RoundingMode
case class Foo(i: BigDecimal)
object Foo extends DefaultJsonProtocol {
implicit val roundedBigDecimalProtocol: JsonFormat[BigDecimal] =
new JsonFormat[BigDecimal] {
def write(f: BigDecimal) = JsNumber(f.setScale(2, RoundingMode.HALF_UP))
def read(json: JsValue): BigDecimal =
DefaultJsonProtocol.BigDecimalJsonFormat.read(json)
}
implicit val fooFormatter = jsonFormat1(this.apply)
}
scastie snippet:
https://scastie.scala-lang.org/9RNhajzGRDGMX5QsuAohVA
Great question, I wasn't even aware this may cause so many problems. The solution I am about to propose is probably not the cleanest, but it does the job... First of all, you don't have to extend DefaultJsonProtocol, you might also import it's members:
object Foo {
import DefaultJsonProtocol._
implicit val roundedBigDecimalProtocol: JsonFormat[BigDecimal] = ...
implicit val fooFormatter = jsonFormat1(this.apply)
}
This doesn't solve the problem but that way you can exclude some of the members so that they are not imported. Here's the syntax for that
import DefaultJsonProtocol.{BigDecimalJsonFormat => _, _}
It basically says: don't import BigDecimalJsonFormat but import the rest.
And the following code sums it up.
import spray.json._
import scala.math.BigDecimal.RoundingMode
case class Foo(i: BigDecimal)
object Foo {
import DefaultJsonProtocol.{BigDecimalJsonFormat => _, _}
implicit val roundedBigDecimalProtocol: JsonFormat[BigDecimal] =
new JsonFormat[BigDecimal] {
def write(f: BigDecimal) = JsNumber(f.setScale(2, RoundingMode.HALF_UP))
def read(json: JsValue): BigDecimal =
DefaultJsonProtocol.BigDecimalJsonFormat.read(json)
}
implicit val fooFormatter = jsonFormat1(this.apply)
}

How to define partially parameterize generic implicit class?

Is it possible to define partially parameterize generic implicit class ? For instance assume I have following class
implicit class IoExt[L, R](val io: IO[R]) {
def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] = ???
}
How can I defined something like
type IoExtLocal[R] = IoExt[String, R]
And have IoExtLocal[R] be available as implicit class ?
The motivation is to free client code from specifying type parameter every time wrapped[](..) is called. It gets very verbose.
Just create another implicit class and import necessary one
object ioExt {
implicit class IoExt[L, R](val io: IO[R]) extends AnyVal {
def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] = ???
}
}
object ioExtLocal {
implicit class IoExtLocal[R](val io: IO[R]) extends AnyVal {
def wrapped(errorCode: String): IO[Either[ProcessingResult[String], R]] =
(io: ioExt.IoExt[String, R]).wrapped(errorCode)
}
}
import ioExtLocal._
trait SomeR
val x: IO[SomeR] = ???
x.wrapped(???)
After trying multiple solutions I've found that following works without instantiating helper class on every call to wrapped
trait IoExtTrait[L, R] extends Any {
protected def io: IO[R]
def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] =
io.attempt.map(_.leftMap(ex ⇒ FailureMsg[L](errorCode, Some(ex))))
def wrappedT(errorCode: String): EitherT[IO, ProcessingResult[L], R] =
EitherT(wrapped(errorCode))
}
implicit class IoExtLocalString[R](protected val io: IO[R]) extends AnyVal with IoExtTrait[String, R] {
override def wrapped(errorCode: String) = super.wrapped(errorCode)
}
on the other hand following instantiates helper class on every call
implicit class IoExtLocalString[R](protected val io: IO[R]) extends AnyVal with IoExtTrait[String, R] {}
If anyone know why it happens please let me know. I'm on Scala 2.12.8 (same behavior with 2.13-RC1).
Further conversation at https://github.com/scala/bug/issues/11526 confirmed that allocation happens on both cases. Too bad.

Implicit JsonWriter for trait not working

I have class as below
trait RiskCheckStatusCode {
def code: String
def isSuccess: Boolean
}
object RiskCheckStatusCode {
val SUCCESS = SuccessRiskCheckStatusCode("1.1.1")
val FAIL = FailRiskCheckStatusCode("2.2.2")
case class SuccessRiskCheckStatusCode(code: String) extends RiskCheckStatusCode {
override def isSuccess = true
}
object SuccessRiskCheckStatusCode {
import spray.json.DefaultJsonProtocol._
implicit val formatter = jsonFormat1(SuccessRiskCheckStatusCode.apply)
}
case class FailRiskCheckStatusCode(code: String) extends RiskCheckStatusCode {
override def isSuccess = false
}
object FailRiskCheckStatusCode {
import spray.json.DefaultJsonProtocol._
implicit val formatter = jsonFormat1(FailRiskCheckStatusCode.apply)
}
}
and now I would like to convert the list of RiskCheckStatusCode to json
object Main extends App{
import spray.json._
import spray.json.DefaultJsonProtocol._
val l = List(RiskCheckStatusCode.SUCCESS, RiskCheckStatusCode.FAIL)
implicit object RiskCheckStatusCodeJsonFormat extends JsonWriter[RiskCheckStatusCode] {
override def write(obj: RiskCheckStatusCode): JsValue = obj match {
case obj: SuccessRiskCheckStatusCode => obj.toJson
case obj: FailRiskCheckStatusCode => obj.toJson
}
}
def json[T](list: T)(implicit formatter: JsonWriter[T]) = {
print(list.toJson)
}
json(l)
}
but the json method can not find jsonWriter[RiskCheckStatusCode].
Can you explain why? Maybe should I do it differently for trait type?
Edit:
It works for
val l: RiskCheckStatusCode = RiskCheckStatusCode.SUCCESS
so the problem is with List[RiskCheckStatusCode] because I have a formatter for RiskCheckStatusCode, not for List[RiskCheckStatusCode]. I tried import DefaultJsonProtocol but it still does not work.
import spray.json.DefaultJsonProtocol._
I have to change the definitions? From
implicit object RiskCheckStatusCodeJsonFormat extends JsonWriter[RiskCheckStatusCode]
to
implicit object RiskCheckStatusCodeJsonFormat extends JsonWriter[List[RiskCheckStatusCode]]
error:
Error:(28, 7) Cannot find JsonWriter or JsonFormat type class for List[com.example.status.RiskCheckStatusCode]
json(l)
Error:(28, 7) not enough arguments for method json: (implicit formatter: spray.json.JsonWriter[List[com.example.status.RiskCheckStatusCode]])Unit.
Unspecified value parameter formatter.
json(l)
Your code is fine you are just not having toJson in your scope (it is located in the package object of spray.json).
Add it and your code should compile:
object Main extends App with DefaultJsonProtocol {
import spray.json._
// ...
}
Furthermore spray has some issues to lift JsonWriter through derived formats (see this for details).
You can switch to JsonFormat instead:
implicit object RiskCheckStatusCodeJsonFormat extends JsonFormat[RiskCheckStatusCode] {
override def write(obj: RiskCheckStatusCode): JsValue = obj match {
case obj: SuccessRiskCheckStatusCode => obj.toJson
case obj: FailRiskCheckStatusCode => obj.toJson
}
override def read(json: JsValue): RiskCheckStatusCode = ???
}
In addition, to cleanup the type of your List change the definition of RiskCheckStatusCode to (this explains more details):
sealed trait RiskCheckStatusCode extends Serializable with Product