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

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

Related

How to change base class field in functional fashion in scala

Say I have this hierarchy
trait Base {
val tag: String
}
case class Derived1(tag: String = "Derived 1") extends Base
case class Derived2(tag: String = "Derived 2") extends Base
//etc ...
and I want to define method with following signature
def tag[T <: Base](instance: T, tag: String): T
that returns an instance of type T with modified tag: String. So when e.g. a Derived1 instance is passed in a modified instance of the same type is returned.
This goal could be easily accomplished by using mutable tag variable var tag: String. How to achieve desired behaviour using scala and functional programming?
My thought:
I could create a type class and its instances
trait Tagger[T] {
def tag(t: T, state: String): T
}
implicit object TaggerDerived1 extends Tagger[Derived1] {
override def tag(t: Derived1, state: String): Derived1 = ???
}
implicit object TaggerDerived2 extends Tagger[Derived2] {
override def tag(t: Derived2, state: String): Derived2 = ???
}
implicit object TaggerBase extends Tagger[Base] {
override def tag(t: Base, state: String): Base = ???
}
and a method
def tag[T <: Base](instance: T, tag: String)(implicit tagger: Tagger[T]): T = tagger.tag(instance, tag)
This is not ideal, because first of all user must be aware of this when defining their own derived classes. When not defining one, the implicit resolution would fall back to base implementation and narrow the returning type.
case class Derived3(tag: String = "Derived 3") extends Base
tag(Derived3(), "test") // falls back to `tag[Base](...)`
Now I am leaning towards using mutable state by employing var tag: String. However, I would love to hear some opinions how to resolve this purely functionally in scala.
You can derive your type class Tagger and then the users will not have to define its instances for every new case class extending Base
// libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.10"
import shapeless.labelled.{FieldType, field}
import shapeless.{::, HList, HNil, LabelledGeneric, Witness}
trait Tagger[T] {
def tag(t: T, state: String): T
}
trait LowPriorityTagger {
implicit def notTagFieldTagger[K <: Symbol : Witness.Aux, V, T <: HList](implicit
tagger: Tagger[T]
): Tagger[FieldType[K, V] :: T] =
(t, state) => t.head :: tagger.tag(t.tail, state)
}
object Tagger extends LowPriorityTagger {
implicit def genericTagger[T <: Base with Product, L <: HList](implicit
generic: LabelledGeneric.Aux[T, L],
tagger: Tagger[L]
): Tagger[T] = (t, state) => generic.from(tagger.tag(generic.to(t), state))
implicit val hnilTagger: Tagger[HNil] = (_, _) => HNil
implicit def tagFieldTagger[T <: HList]:
Tagger[FieldType[Witness.`'tag`.T, String] :: T] =
(t, state) => field[Witness.`'tag`.T](state) :: t.tail
}
case class Derived1(tag: String = "Derived 1") extends Base
case class Derived2(tag: String = "Derived 2") extends Base
case class Derived3(i: Int, tag: String = "Derived 3", s: String) extends Base
tag(Derived1("aaa"), "bbb") // Derived1(bbb)
tag(Derived2("ccc"), "ddd") // Derived2(ddd)
tag(Derived3(1, "ccc", "xxx"), "ddd") // Derived3(1,ddd,xxx)
Alternatively for single-parameter case classes you can constrain T so that it has .copy
import scala.language.reflectiveCalls
def tag[T <: Base {def copy(tag: String): T}](instance: T, tag: String): T =
instance.copy(tag = tag)
For multi-parameter case classes it's harder to express in types the existence of .copy because the method signature becomes unknown (to be calculated).
So you can make tag a macro
// libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def tag[T <: Base](instance: T, tag: String): T = macro tagImpl
def tagImpl(c: blackbox.Context)(instance: c.Tree, tag: c.Tree): c.Tree = {
import c.universe._
q"$instance.copy(tag = $tag)"
}
Or you can use runtime reflection (Java or Scala, using Product functionality or not)
import scala.reflect.{ClassTag, classTag}
import scala.reflect.runtime.{currentMirror => rm}
import scala.reflect.runtime.universe.{TermName, termNames}
def tag[T <: Base with Product : ClassTag](instance: T, tag: String): T = {
// Product
val values = instance.productElementNames.zip(instance.productIterator)
.map {case fieldName -> fieldValue => if (fieldName == "tag") tag else fieldValue}.toSeq
// Java reflection
// val clazz = instance.getClass
// clazz.getMethods.find(_.getName == "copy").get.invoke(instance, values: _*).asInstanceOf[T]
// clazz.getConstructors.head.newInstance(values: _*).asInstanceOf[T]
// Scala reflection
val clazz = classTag[T].runtimeClass
val classSymbol = rm.classSymbol(clazz)
// val copyMethodSymbol = classSymbol.typeSignature.decl(TermName("copy")).asMethod
// rm.reflect(instance).reflectMethod(copyMethodSymbol)(values: _*).asInstanceOf[T]
val constructorSymbol = classSymbol.typeSignature.decl(termNames.CONSTRUCTOR).asMethod
rm.reflectClass(classSymbol).reflectConstructor(constructorSymbol)(values: _*).asInstanceOf[T]
}

Covariant return type implementation

I'm trying to implement a covariant return type for a method in Scala. Let's assume we have the following scenario:
class Animal
class Dog extends Animal
class Cat extends Animal
abstract class M[-T]{
def get[U <: T](): U
}
val container = new M[Animal] {
override def get[U <: Animal](): U = ???
}
How should I do that?
If you're just curious, for example you can use Shapeless
import shapeless.{Generic, HNil}
def get[U <: Animal]()(implicit generic: Generic.Aux[U, HNil]): U =
generic.from(HNil)
get[Dog] // Dog() for case class, Dog#34340fab otherwise
get[Cat] // Cat() for case class, Cat#2aafb23c otherwise
get[Nothing] // doesn't compile
get[Null] // doesn't compile
get[Cat with Dog] // doesn't compile
Or you can use a macro
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def get[U <: Animal](): U = macro getImpl[U]
def getImpl[U: c.WeakTypeTag](c: blackbox.Context)(): c.Tree = {
import c.universe._
q"new ${weakTypeOf[U]}"
}
Or you can use runtime reflection
import scala.reflect.runtime.universe._
import scala.reflect.runtime
def get[U <: Animal : TypeTag](): U = {
val typ = typeOf[U]
val constructorSymbol = typ.decl(termNames.CONSTRUCTOR).asMethod
val runtimeMirror = runtime.currentMirror
val classSymbol = typ.typeSymbol.asClass
val classMirror = runtimeMirror.reflectClass(classSymbol)
val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
constructorMirror().asInstanceOf[U]
}
(see also example with Java reflection in #KrzysztofAtłasik's answer.)
Or you just can introduce a type class and define its instances manually
trait Get[U <: Animal] {
def get(): U
}
object Get {
implicit val dog: Get[Dog] = () => new Dog
implicit val cat: Get[Cat] = () => new Cat
}
def get[U <: Animal]()(implicit g: Get[U]): U = g.get()
Alternatively, you could use reflection to create new instances. You just need to get implicit classTag:
import scala.reflect.ClassTag
class Animal
class Dog extends Animal
class Cat extends Animal
abstract class M[-T] {
def get[U <: T](implicit ct: ClassTag[U]): U
}
val container = new M[Animal] {
override def get[U <: Animal](implicit ct: ClassTag[U]): U =
//it gets no argument constructor so obviosly it will only work if your classes has no params
ct.runtimeClass.getConstructor().newInstance().asInstanceOf[U]
}
container.get[Dog]

Construct Scala Object (Singleton) from ClassTag

Is it possible to do something like below? We have a ConcreteType which has trait definition and Object definition. At runtime I want to create Object version to access get method of some ConcreteType. Note code below throws cannot cast to SomeTrait exception at asInstanceOf. Also I am using some library that uses format below so have no choice but to work with this construct.
trait SomeType
trait SomeTrait[T <: SomeType] {
def get(i: Int): Option[SomeType]
}
trait ConcreteType extends SomeType
object ConcreteType extends SomeTrait[ConcreteType]
def temp[T <: SomeType]()(implicit tag: ClassTag[T]): Option[T] = {
asInstanceOf[SomeTrait[T]].get(1)
}
I'm not sure what you're doing (I asked several questions in comments), but yes, you can get the object from ClassTag
import scala.reflect.ClassTag
import scala.reflect.runtime
def temp[T <: SomeType]()(implicit tag: ClassTag[T]): Option[/*T*/SomeType] = {
val runtimeMirror = runtime.currentMirror
val classSymbol = runtimeMirror.classSymbol(tag.runtimeClass)
val companionSymbol = classSymbol.companion.asModule
val companionModuleMirror = runtimeMirror.reflectModule(companionSymbol)
val companionInstance = companionModuleMirror.instance
companionInstance.asInstanceOf[SomeTrait[T]].get(1)
}
temp[ConcreteType]()

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

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.