Accompanying object for trait in Scala - scala

I try to write general apply method to serve as a factory method for child classes. What I came up with is following:
trait A
object A {
def apply[T <: A](someParam: String): T {
new T()
}
}
class B private extends A
class C private extends A
So one can create new B or C instance:
def main(args: Array[String]): Unit = {
A[B]("test")
}
Is it acceptable that trait has an accompanying object?Is there a better way to implement this?

You could:
trait A
object A {
def apply[T <: A ](someParam: String) (implicit ev: ClassTag[T]): T ={
ev.runtimeClass.newInstance().asInstanceOf[T]
}
}
But its not very useful with varying constructor's for each sub class
sealed trait A
object A {
def apply[T <: A](someParam: String)(implicit ev: T): T = {
ev
}
}
class B(n: Int) extends A
class C(n: String) extends A
object B {
implicit def defaultCons: B = new B(1)
}
object C {
implicit def defaultCons: C = new C("hi")
}
Or you could also go via combination of ClassTag approach with pattern match based on the class instead of using reflection for instantiation.

Related

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 evidence from a type within a trait

Let's say we have the following:
object MyValue {
case class MyBoolean(record: Boolean) extends MyValue
case class MyDouble(record: Double) extends MyValue
}
trait MyValue
and a sealed trait:
object MyValueGrabber {
trait MyBooleanGrabber[T] extends MyValueGrabber[T] {
override def apply(record: T): Option[MyValue.MyBoolean]
}
trait MyDoubleGrabber[T] extends MyValueGrabber[T] {
override def apply(record: T): Option[MyValue.MyDouble]
}
}
sealed trait MyValueGrabber[T] {
def apply(record: T): Option[MyValue]
}
as well as a mapping between the MyValue type and a different type with which it is associated:
object Mapper {
implicit val myBooleanMapper = new Mapper[MyValueGrabber.MyBooleanGrabber[_], String] {
override def getValue: String = "found a bool"
}
implicit val myDoubleMapper = new Mapper[MyValueGrabber.MyDoubleGrabber[_], Long] {
override def getValue: Long = 100L
}
}
trait Mapper[A, B] {
def getValue: B
}
and then we have:
trait HolyGrail[T] {
def name: String
def myValueGrabber: MyValueGrabber[T]
def getValue[U] = ???
}
The question is how do we use the Mapper implicitly to return the correct type U. Ideally, it would be something like:
def getValue[U](implicit ev: Mapper[myValueGrabber.type, U]) = ev.getValue // doesn't work
You should use it like this:
def getValue[U](implicit ev: Mapper[MyValueGrabber[T], U]) = ev.getValue
As methods do not have .type. (Their converted function have, but I think that is not what you want.)
Based on the clarifications in the comments, I think you want something like Shapeless' HMap.
You will probably need to adjust your ValueGrabber trait a bit:
sealed trait MyValueGrabber[T, -R <: MyValue] {
def apply(record: T): Option[R]
}
or
sealed trait MyValueGrabber[T] {
type R <: MyValue
def apply(record: T): Option[R]
}
probably the latter is harder to use in your getValue:
def getValue[U, O](implicit ev: Mapper[MyValueGrabber[T] {type R = O}, U]): U = ev.getValue
the former would look like this (but as I understand not what you want):
trait HolyGrail[T, R] {
def name: String
def myValueGrabber: MyValueGrabber[T, R]
def getValue[U](implicit ev: Mapper[MyValueGrabber[T, R], U]): U = ev.getValue
}
I do not know how to do the thing you want (path dependent type with trait) without shapeless.

Ensure instance of typeclass

if I have an ADT and a type class, is there a way for me to ensure at compile time that there is an instance of the type class for every subtype of the ADT?
Just to give an example - I'd really like this to not compile as there isn't an instance of A for Baz
sealed trait Foo
final case class Bar(s: String) extends Foo
final case class Baz(i: Int) extends Foo
trait A[T <: Foo] {
type O
def f(t: T): O
}
implicit val barA = new A[Bar] {
type O = String
def f(t: Bar): O = t.s
}
This is all my own code, so I'm happy to change the encoding of Foo if required (maybe a shapeless coproduct can help me out here?)
EDIT
Sorry, should have mentioned - I have a function a bit like this I'd like to implement (lets assume my instances are in an object I've imported and they are the only implementations in scope)
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From the comments below, it looks like I should also have said that the thing that calls g can do so with a List of any subclass of Foo (I have no control over that part other than to change g I guess). Here, I'm trying to ensure that if someone changes Foo later on, then there will be a compiler error letting the user know that they need to implement an appropriate A
You can use F-bounded polymorphism (aka Curiously Recurrent Template Pattern):
sealed abstract class Foo[Self <: Foo](implicit val hasA: A[Self])
final case class Bar(s: String) extends Foo[Bar]
final case class Baz(i: Int) extends Foo[Baz]
abstract class is used instead of trait so the implicit is picked up automatically.
However, for this specific A and g, you may not really need a type class:
sealed trait Foo[O] {
def f(): O
}
final case class Bar(s: String) extends Foo[String] {
def f() = s
}
def g(fs: List[Foo[O]]): List[O] = fs.map(_.f())
trait Foo[T] {
this: ImplementThis[T] =>
}
case class Bar() extends Foo[String] with ImplementThis[String] {
override def f(t: String): String = {
t
}
}
case class Baz() extends Foo[Int] with ImplementThis[Int] {
override def f(t: Int): Int = {
t
}
}
trait ImplementThis[T] {
type O
def f(t: T): O
}
Try something like this. This will enforce implementation of def f(t: T):O for any subclass of Foo that's defined.
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From this, I assume you want all the child classes of your Foo to have a def f so that they dont fail at runtime. I think my above suggestion will enforce that def f implementation and solve this problem.

Scala factory for generic types using the apply method?

Suppose that I have the following trait that defines an interface and takes a couple of type parameters...
trait Foo[A, B] {
// implementation details not important
}
I want to use the companion object as a factory for concrete implementations of the trait. I also want to force users to use the Foo interface instead of sub-classing So I hide the concrete implementations in the companion object like so:
object Foo {
def apply[A, B](thing: Thing): Foo[A, B] = {
???
}
private case class FooImpl[A1, B1](thing: Thing) extends Foo[A1, B1]
private case class AnotherFooImpl[A2, B1](thing: Thing) extends Foo[A2, B1]
}
I want to be able to use the factory as follows:
val foo = Foo[A1, B1](thing) // should be an instance of FooImpl
val anotherFoo = Foo[A2, B1](thing) // should be an instance of AnotherFooImpl
How do I implement the apply method to make this happen? This SO post seems close to the mark.
How about:
trait Foo[A, B]
trait Factory[A, B] {
def make(thing: Thing): Foo[A, B]
}
class Thing
object Foo {
def apply[A, B](thing: Thing)(implicit ev: Factory[A, B]) = ev.make(thing)
private case class FooImpl[A, B](thing: Thing) extends Foo[A, B]
private case class AnotherFooImpl[A, B](thing: Thing) extends Foo[A, B]
implicit val fooImplFactory: Factory[Int, String] = new Factory[Int, String] {
override def make(thing: Thing): Foo[Int, String] = new FooImpl[Int, String](thing)
}
implicit val anotherFooImplFactory: Factory[String, String] = new Factory[String, String] {
override def make(thing: Thing): Foo[String, String] = new AnotherFooImpl[String, String](thing)
}
And now:
def main(args: Array[String]): Unit = {
import Foo._
val fooImpl = Foo[Int, String](new Thing)
val anotherFooImpl = Foo[String, String](new Thing)
println(fooImpl)
println(anotherFooImpl)
}
Yields:
FooImpl(testing.X$Thing#4678c730)
AnotherFooImpl(testing.X$Thing#c038203)
Using TypeTags (to overcome erasure of type parameters), we can call the respective hidden implementations based on the type parameters passed in to the apply method like below. It correctly instantiates the respective implementations but the type information for Foo is lost, in fact its coming some garbage like _202 etc? I don't know why that is happening and how to retain the correct types for Foo. Maybe someone can throw light on this.
trait Foo[A,B]
object Foo {
def apply[A: TypeTag, B: TypeTag](thing: Thing) =
if(typeTag[A] == typeTag[Int])
FooImpl(thing)
else if(typeTag[A] == typeTag[String])
AnotherFooImpl(thing)
else
new Foo[Double,Double] {}
private case class FooImpl(thing: Thing) extends Foo[Int, String]
private case class AnotherFooImpl(thing: Thing) extends Foo[String, String]
}
Foo[Int,String](new Thing) // Foo[_202, _203] = FooImpl($sess.cmd123$Thing#50350b75)
The actual types for _203 and _203 are: ???
// type _203 >: String with _201, type _202 >: Int with _200
Foo[String,String](new Thing) //Foo[_202, _203] = AnotherFooImpl($sess.cmd123$Thing#51d80d6)

Scala Mutually Convertible Generic Types

I'm very new to Scala programming, and I really like the degree to which code is composable. I wanted to write some traits that deal with two related objects that are convertible to each other, and build more functionality by continuing to extend that trait so that when I create objects I can specify the related types for my generics. Here is a working toy example of the type of code I'm talking about:
trait FirstConverter[First] {
def toFirst: First
}
trait SecondConverter[Second] {
def toSecond: Second
}
trait TwoWayConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] {
def firstToSecond(x: First) = x.toSecond
def secondToFirst(x: Second) = x.toFirst
}
trait RoundTripConverter[First <: SecondConverter[Second], Second <: FirstConverter[First]] extends TwoWayConverter[First, Second] {
def firstToFirst(x: First) = secondToFirst(firstToSecond(x))
def secondToSecond(x: Second) = firstToSecond(secondToFirst(x))
}
case class A(s: String) extends SecondConverter[B] {
def toSecond: B = B((s.toInt) + 1)
}
case class B(i: Int) extends FirstConverter[A] {
def toFirst: A = A((i * 2).toString)
}
object ABConverter extends RoundTripConverter[A, B]
object Main {
def main(args: Array[String]): Unit = {
println(ABConverter firstToSecond A("10")) // 11
println(ABConverter secondToFirst B(42)) // 84
println(ABConverter firstToFirst A("1")) // 4
println(ABConverter secondToSecond B(2)) // 5
}
}
While this works, I'm not sure if it's idiomatic Scala. I'm asking if there are any tricks to make the type definitions more concise and if I can somehow define the type restrictions only once and have them used by multiple traits which extend other traits.
Thanks in advance!
One way to improve your design would be to use a type class instead of inheriting from FirstConverter and SecondConverter. That way you could use multiple conversion functions for the same types and convert between classes you don't control yourself.
One way would be to create a type class which can convert an A into a B :
trait Converter[A, B] {
def convert(a: A): B
}
trait TwoWayConverter[A, B] {
def firstToSecond(a: A)(implicit conv: Converter[A, B]): B = conv.convert(a)
def secondToFirst(b: B)(implicit conv: Converter[B, A]): A = conv.convert(b)
}
trait RoundTripConverter[A, B] extends TwoWayConverter[A, B] {
def firstToFirst(a: A)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) =
secondToFirst(firstToSecond(a))
def secondToSecond(b: B)(implicit convAB: Converter[A, B], convBA: Converter[B, A]) =
firstToSecond(secondToFirst(b))
}
We could create type class instances for the following two classes Foo and Bar similar to your A and B
case class Foo(s: String)
case class Bar(i: Int)
implicit val convFooBarFoor = new Converter[Foo, Bar] {
def convert(foo: Foo) = Bar((foo.s toInt) + 1)
}
implicit val convBarFoo = new Converter[Bar, Foo] {
def convert(bar: Bar) = Foo((bar.i * 2) toString)
}
We then could create a FooBarConverter :
object FooBarConverter extends RoundTripConverter[Foo, Bar]
FooBarConverter firstToSecond Foo("10") // Bar(11)
FooBarConverter secondToFirst Bar(42) // Foo(84)
FooBarConverter firstToFirst Foo("1") // Foo(4)
FooBarConverter secondToSecond Bar(2) // Bar(5)
The only problem is because we can not pass parameters to a trait, we can not limit the types to types with a Converter type class instance. So you can create the StringIntConverter below even if no Converter[String, Int] and/or Convert[Int, String] instances exist.
object StringIntConverter extends TwoWayConverter[String, Int]
You cannot call StringIntConverter.firstToSecond("a") because the firstToSecond method needs the implicit evidence of the two mentioned type class instances.