Mixin to wrap every method of a Scala trait - scala

Suppose I have a trait Foo with several methods. I want to create a new trait which extends Foo but "wraps" each method call, for example with some print statement (in reality this will be something more complicated / I have a couple of distinct use cases in mind).
trait Foo {
def bar(x: Int) = 2 * x
def baz(y: Int) = 3 * y
}
I can do this manually, by overriding each method. But this seems unnecessarily verbose (and all too easy to call the wrong super method):
object FooWrapped extends FooWrapped
trait FooWrapped extends Foo {
override def bar(x: Int) ={
println("call")
super.bar(x)
}
override def baz(y: Int) ={
println("call")
super.baz(y)
}
}
scala> FooWrapped.bar(3)
call
res3: Int = 6
I was hoping to write a mixin trait, that I would be able to reuse with other traits, and use as:
trait FooWrapped extends Foo with PrintCall
That way I don't have to manually override each method (the mixin would do this for me).
Is it possible to write such a mixin trait in Scala? What would it look like?

Update Here is the macro. It was much less painful than I thought it will be because of quasiquotes. They are awesome. This code does only a little and you probably will have to improve it. It may not account some special situations. Also it assumes that neither parent class nor it's method has type params, it wraps only the methods of the given class or trait, but not it's parents methods, it may not work if you have auxilary constructors etc. Still I hope it will give you an idea of how to do that for your specific needs, making it working for all of the situations unfortunately is too big job for me right now.
object MacrosLogging {
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def log_wrap[T](): T = macro log_impl[T]
def log_impl[T : c.WeakTypeTag](c: blackbox.Context)(): c.Expr[T] = {
import c.universe._
val baseType = implicitly[c.WeakTypeTag[T]].tpe
val body = for {
member <- baseType.declarations if member.isMethod && member.name.decodedName.toString != "$init$"
method = member.asMethod
params = for {sym <- method.paramLists.flatten} yield q"""${sym.asTerm.name}: ${sym.typeSignature}"""
paramsCall = for {sym <- method.paramLists.flatten} yield sym.name
methodName = member.asTerm.name.toString
} yield {
q"""override def ${method.name}(..$params): ${method.returnType} = { println("Method " + $methodName + " was called"); super.${method.name}(..$paramsCall); }"""
}
c.Expr[T] {q""" { class A extends $baseType { ..$body }; new A } """}
}
}
If you do not want to create an instance, but you do want to add logging only for your trait so you could mixin further, you can do this with relatively the same code, but using macro paradise type annotations: http://docs.scala-lang.org/overviews/macros/annotations These allow you to tag your class definitions and perform modifications right inside the definitions
You could do something like you want with Dynamic, but there is a catch - you can't make it of original type, so it's not a mixin. Dynamic starts to work only if type checks fails, so you can't mixin real type (or I do not know how to do that). The real answer would probably require macros (as #AlexeyRomanov suggested in comments), but I am not sure how to write one, maybe I'll come up with it later. Still Dynamic might work for you if you are not looking for DI here
trait Foo {
def bar(x: Int) = 2 * x
def baz(y: Int) = 3 * y
}
import scala.reflect.runtime.{universe => ru}
import scala.language.dynamics
trait Wrapper[T] extends Dynamic {
val inner: T
def applyDynamic(name: String)(args: Any*)(implicit tt: ru.TypeTag[T], ct: ClassTag[T]) = {
val im = tt.mirror.reflect(inner)
val method = tt.tpe.decl(ru.TermName(name)).asMethod
println(method)
val mm = im.reflectMethod(method)
println(s"$name was called with $args")
mm.apply(args:_*)
}
}
class W extends Wrapper[Foo] {
override val inner: Foo = new Foo() {}
}
val w = new W // Cannot be casted to Foo
println(w.bar(5)) // Logs a call and then returns 10
You can read more about Dynamic here: https://github.com/scala/scala/blob/2.12.x/src/library/scala/Dynamic.scala

Related

Custom and multiple constructor inheritance in Scala?

As I understand the semantics of a custom constructor may be typically added to a class via a companion object. Is there then, any way to inherit a custom constructor while inheriting a class?
On the one hand I have found that companion objects are not synthetically inherited along a case class, and on the other, I am not aware of a way of creating custom constructors inside a class itself, so that they are inherited. And yet inheriting custom constructors seems to be a perfectly valid use case to me. So is it supported in some (straightforward) way in Scala?
A naive demonstration of intent:
class A {}
object A {
def apply(n: Int) = {
println(n)
new A
}
}
class B extends A {}
object Test {
val a1 = A
val a2 = A(3)
val b1 = B // compile error
val b2 = B(3) // compile error
P.S. I have even found the arcane/deviant technique of defining this custom constructors result in a custom constructor that does not in actuality get inherited (it does work for just creating custom constructors, but quite oddly and unfortunately those do not get inherited). Demonstrating code:
class A {
def this(n: Int) = {
this
println(n)
}
}
class B extends A {}
object Test {
val a1: A = new A
val a2: A = new A(3)
val b1 = new B
val b2 = new B(3) // compile error
}
Clarification of Intent Edit:
consider "constructor" and "companion factory methods" interchangeable for the sake of this question.
You can't inherit constructors directly, and because you can't you also can't inherit things that use them without a little bit of work. But you can abstract away anything beyond the constructor call.
Let's suppose we have
class Foo(text: String) {
override def toString = "Foo: " + text
}
object Foo {
def apply(text: String) = new Foo(text) // Auto-generated for case class
def apply(i: Int) = new Foo(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
and we then decide to
class Bar(text: String) extends Foo(text) {
override def toString = "Bar: " + text
}
Now, what do we do about object Bar? Instead of writing all the logic over again, we create a trait to separate and abstract the object creation from the computation of the constructor parameter(s):
trait FooCompanionLike[A <: Foo] {
def apply(text: String): A // I am abstract!
def apply(i: Int): A = apply(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
Now we can
object Foo extends FooCompanionLike[Foo] {
def apply(text: String) = new Foo(text)
}
object Bar extends FooCompanionLike[Bar] {
def apply(text: String) = new Bar(text)
}
So you can't completely escape boilerplate, but you can reduce it to extending from a trait and a single method call.
If you do it this way (where the abstract apply perfectly matches the constructor), you can even get case classes to work without manually defining the abstract apply method in the companion:
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}
Short answer: no straightforward way; try to workaround and resist the desire.
Constructors in Scala are defined in the body of the class and take parameters after the class name e.g.
class A(i: Int) {
println(i)
}
The println(i) in this case is the constructor logic. If you now extend A, like this:
class B(i: Int) extends A(i)
and instantiate B, val b1 = new B(2) you'll see that the constructor is indeed inherited.
As you've already found out, Scala allows you to define alternative constructors by defining functions called this. But these alternative constructors must call the primary constructor.
The way I understand it is that there is really only one constructor for any Scala class, the alternative constructors just filter into it. For example:
class A(x: Int, y: Int) {
// do some constructing!
def this(x: Int) = {
this(x, 1) // provide a default value for y
}
}

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.

Write generic code in scala without inheritance hierarchy

I have few classes which do not derive from any superclass. They all have bunch of same methods defined. For example,
class A {
def getMsgNum = 1
}
class B {
def getMsgNum = 2
}
I would like to write a generic function that will return message num based on object function is called with. So something like,
def getMsgNum[T](t: T) = t.getMsgNum
I think that because of type erasure I cannot expect that to work but I was looking at view bound and context bound with ClassTag but that still does not work.
def getType[T: ClassTag](msg: T) = {
msg.getMsgNum
}
I come from C++ background and I am trying to achieve something to the effect of template compilation for every type.
Thanks for your time!
I personally prefer adhoc polymorphism with TypeClass (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html) pattern. I think it will be much more "true scala way" solution for this kind of problem. Also structural typing more expensive at runtime because it use reflection for field access.
class A
class B
trait ToMsgNum[T] {
def getMsgNum: Int
}
implicit object AToMsgNum extends ToMsgNum[A] {
def getMsgNum = 1
}
implicit object BToMsgNum extends ToMsgNum[B] {
def getMsgNum = 2
}
def getMsgNum[T: ToMsgNum](t: T) =
implicitly[ToMsgNum[T]].getMsgNum
println(getMsgNum(new A))
println(getMsgNum(new B))
def getMsgNum[T](t: T)(implicit ev: T => { def getMsgNum: Int }) = t.getMsgNum
where { def getMsgNum: Int } is a structural type. From the documentation:
A structural type is a type of the form Parents { Decls } where Decls contains declarations of new members that do not override any member in Parents.
and
Structural types provide great flexibility because they avoid the need to define inheritance hierarchies a priori
Please note that the above solution uses an implicit reflective call to access the field of the structural type, a language feature that has to be explicitly enabled by adding the import
import scala.language.reflectiveCalls
This is not too different from Eugene's solution but I think it's a bit clearer:
// predefined classes you have no access to
class Foo { def someMethod = "foo" }
class Bar { def someMethod = "bar" }
there's no way in Scala other than reflection or structural types (which is reflection in disguise) to generically call someMethod on these types. The way this can be made to work though, is by defining adapter objects that know how to deal with each type individually, and you then make generic calls on those instead:
trait HasSomeMethod[T] { def someMethod(x: T): String }
object FooHasSomeMethod extends HasSomeMethod[Foo] { def someMethod(x: Foo) = x.someMethod }
object BarHasSomeMethod extends HasSomeMethod[Bar] { def someMethod(x: Bar) = x.someMethod }
now you can pass one of those adapter objects into the method that needs generic access to Foo#someMethod and Bar#someMethod:
def invokeSomeMethod[T](x: T)(adapter: HasSomeMethod[T]) =
adapter.someMethod(x)
invokeSomeMethod(new Foo)(FooHasSomeMethod) // returns "foo"
invokeSomeMethod(new Bar)(BarHasSomeMethod) // returns "bar"
(we could have used a single parameter list here but later we'll nede 2 lists anyway)
however, this is obviously not as useful as we'd like as we have to pass in the adapter manually. Let's introduce implicits to make Scala automatically look up the right adapter object and pass that in to our generic but inheritance'less method:
implicit object FooHasSomeMethod extends HasSomeMethod[Foo] { ... }
implicit object BarHasSomeMethod extends HasSomeMethod[Bar] { ... }
def invokeSomeMethod[T](x: T)(implicit adapter: HasSomeMethod[T]) =
adapter.someMethod(x)
now these work:
invokeSomeMethod(new Foo) // returns "foo"
invokeSomeMethod(new Bar) // returns "bar"
The above 2 calls get translated automatically to the longer calls in the previous version; Scala looks up suitable values for the implicit adapter parameter automatically from the implicit objects (and also vals and defs, to be precise) available in the "environment" of the call.
You can also define invokeSomeMethod like this, which is just syntactic sugar over the above definition:
def invokeSomeMethod[T: HasSomeMethod](x: T) =
implicitly[HasSomeMethod[T]].someMethod(x)
or, since T: HasSomeMethod auto-generates a second parameter list implicit evidence$1: HasSomeMethod[T], this also works:
def invokeSomeMethod[T: HasSomeMethod](x: T) =
evidence$1.someMethod(x)
The above "pattern" is known as Type Classes. So for example the T: HasSomeMethod bit can be read as "some type T that belongs to the type class HasSomeMethod" (or "...has been made an instance of the type class HasSomeMethod").
For more on Type Classes, see e.g. http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html.
You can also define the HasSomeMethod type class instance for classes that don't even have someMethod nor bear no other resemblance to Foo and Bar whatsoever, if needed:
implicit object IntHasSomeMethod extends HasSomeMethod[Int] {
def someMethod(x: Int) = "this is an int: " + x
}
invokeSomeMethod(3) // returns "this is an int: 3"
If you need to define an instance of that type class for many classes, you can have a helper (with a name that matches the type class, for niceness):
def HasSomeMethod[T](fn: T => String) = new HasSomeMethod[T] {
def someMethod(x: T) = fn(x)
}
now you can define type class instances (adapters) very concisely:
implicit val FooHasSomeMethod = HasSomeMethod[Foo](_.someMethod)
implicit val BarHasSomeMethod = HasSomeMethod[Bar](_.someMethod)
implicit val IntHasSomeMethod = HasSomeMethod[Int]("this is an int: " + _)
implicit val PersonHasSomeMethod = HasSomeMethod[Person](_.name)
// etc
If you dont want to use structural type (reflection) and implicit, how about create Adaptor on top of it, so you own method getMsgNum will implement based on the Adaptor instead of already existing class.
class A {
def getMsgNum = 1
}
class B {
def getMsgNum = 2
}
class C {
def getMsgNum = 3
}
trait Adaptor[T] {
def getMsgNum: Int
}
class AdaptorA(t: A) extends Adaptor[A] {
def getMsgNum = t.getMsgNum
}
class AdaptorB(t: B) extends Adaptor[B] {
def getMsgNum = t.getMsgNum
}
class AdaptorC(t: C) extends Adaptor[C] {
def getMsgNum = t.getMsgNum
}
def getMsgNum[T](t: Adaptor[T]) = t.getMsgNum
getMsgNum(new AdaptorA(new A)) //1
getMsgNum(new AdaptorB(new B)) //2
getMsgNum(new AdaptorC(new C)) //3

Scala: Multiple implicit conversions with same name

Using scala 2.10.3, my goal is to make the following work:
object A {
implicit class Imp(i: Int) {
def myPrint() {
println(i)
}
}
}
object B {
implicit class Imp(i: String) {
def myPrint() {
println(i)
}
}
}
import A._
import B._
object MyApp extends App {
3.myPrint()
}
This fails with
value myPrint is not a member of Int
If I give A.Imp and B.Imp different names (for example A.Imp1 and B.Imp2), it works.
Diving a bit deeper into it, there seems to be the same problem with implicit conversions.
This works:
object A {
implicit def Imp(i: Int) = new {
def myPrint() {
println(i)
}
}
implicit def Imp(i: String) = new {
def myPrint() {
println(i)
}
}
}
import A._
object MyApp extends App {
3.myPrint()
}
Whereas this doesn't:
object A {
implicit def Imp(i: Int) = new {
def myPrint() {
println(i)
}
}
}
object B {
implicit def Imp(i: String) = new {
def myPrint() {
println(i)
}
}
}
import A._
import B._
object MyApp extends App {
3.myPrint()
}
Why? Is this a bug in the scala compiler? I need this scenario, since my objects A and B derive from the same trait (with a type parameter) which then defines the implicit conversion for its type parameter. In this trait, I can only give one name for the implicit conversion. I want to be able to import more of these objects into my scope. Is there a way to do that?
edit: I can't give the implicit classes different names, since the examples above are only breaking down the problem. My actual code looks more like
trait P[T] {
implicit class Imp(i: T) {
def myPrint() {
...
}
}
}
object A extends P[Int]
object B extends P[String]
import A._
import B._
The implicits just have to be available as a simple name, so you can rename on import.
Just to verify:
scala> import A._ ; import B.{ Imp => BImp, _ }
import A._
import B.{Imp=>BImp, _}
scala> 3.myPrint
3
Actually, it works if you replace
import A._
import B._
with
import B._
import A._
What happens, I think, is that A.Imp is shadowed by B.Imp because it has the same name. Apparently shadowing applies on the function's name and do not take the signature into account.
So if you import A then B, then only B.Imp(i: String) will be available, and if you import B then A, then only A.Imp(i: Int) will be available.
If you need to use both A.Imp and B.Imp, you must rename one of them.
In case anyone else runs into this issue, there is a partial workaround, which I found here:
https://github.com/lihaoyi/scalatags/blob/3dea48c42c5581329e363d8c3f587c2c50d92f85/scalatags/shared/src/main/scala/scalatags/generic/Bundle.scala#L120
That code was written by Li Haoyi, so you can be pretty confident that no better solution exists...
Essentially, one can still use traits to define methods in terms of each other, but it will require boilerplate to copy those implicits into unique names. This example might be easier to follow:
trait Chainable
object Chainable {
implicit val _chainableFromInt = IntChainable.chainable _
implicit val _chainableFromIntTrav = IntChainable.traversable _
implicit val _chainableFromIntOpt = IntChainable.optional _
implicit val _chainableFromIntTry = IntChainable.tried _
implicit val _chainableFromDom = DomChainable.chainable _
implicit val _chainableFromDomTrav = DomChainable.traversable _
implicit val _chainableFromDomOpt = DomChainable.optional _
implicit val _chainableFromDomTry = DomChainable.tried _
private object IntChainable extends ImplChainables[Int] {
def chainable(n:Int) = Constant(n)
}
private object DomChainable extends ImplChainables[dom.Element]{
def chainable(e:Element) = Insertion(e)
}
private trait ImplChainables[T] {
def chainable(t:T):Chainable
def traversable(trav:TraversableOnce[T]):Chainable =
SeqChainable(trav.map(chainable).toList)
def optional(opt:Option[T]):Chainable =
opt match {
case Some(t) => chainable(t)
case None => NoneChainable
}
def tried(tried:Try[T]):Chainable =
optional(tried.toOption)
}
}
In other words, never write:
trait P[T] {
implicit def foo(i: T) = ...
}
object A extends P[X]
Because defining implicits in type parameterized traits will lead to these naming conflicts. Although, incidentally, the trait in mentioned in the link above is parameterized over many types, but idea there is that none of the implementations of that trait are ever needed in the same scope. (JSDom vs Text, and all._ vs short._ for those familiar with Scalatags)
I also recommend reading: http://www.lihaoyi.com/post/ImplicitDesignPatternsinScala.html
It does not address this issue specifically but is an excellent summary of how to use implicits.
However, putting all these pieces together, this still seems to be an issue:
trait ImplChainables[AnotherTypeClass]{
type F[A] = A=>AnotherTypeClass
implicit def transitiveImplicit[A:F](t: A):Chainable
implicit def traversable[A:F](trav: TraversableOnce[A]):Chainable = ...
}
What this trait would allow is:
object anotherImpl extends ImplChainables[AnotherTypeClass] {...}
import anotherImpl._
implicit val string2another: String=>AnotherTypeClass = ...
Seq("x"):Chainable
Because of the type parameter and the context binding (implicit parameter) those cannot be eta-expanded (i.e: Foo.bar _ ) into function values. The implicit parameter part has been fixed in Dotty: http://dotty.epfl.ch/blog/2016/12/05/implicit-function-types.html
I do not know if a complete solution would be possible, needless to say this is a complex problem. So it would be nice if same name implicits just worked and the whole issue could be avoided. And in any case, adding an unimport keyword would make so much more sense than turning off implicits by shadowing them.

How to mix-in a trait to instance?

Given a trait MyTrait:
trait MyTrait {
def doSomething = println("boo")
}
it can be mixed into a class with extends or with:
class MyClass extends MyTrait
It can also be mixed upon instantiating a new instance:
var o = new MyOtherClass with MyTrait
o.doSomething
But...can the trait (or any other if that makes a difference) be added to an existing instance?
I'm loading objects using JPA in Java and I'd like to add some functionality to them using traits. Is it possible at all?
I'd like to be able to mix in a trait as follows:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
I have a idea for this usage:
//if I had a class like this
final class Test {
def f = println("foo")
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](val obj:Test) extends MyTrait
}
you can use this trait as below:
import MyTrait._
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
for your example code:
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
I hope this can help you.
UPDATED
object AnyTrait {
implicit def innerObj[T](o: MixTest[T]):T = o.obj
def ::[T](o: T) = new MixTest(o)
final class MixTest[T] private[AnyTrait](val obj: T) extends MyTrait
}
but this pattern has some restrict, you can't use some implicit helper method that defined already.
val a = new Test
a.f
val b = a :: AnyTrait
b.f1
b.f
val c = "say hello to %s" :: AnyTrait
println(c.intern) // you can invoke String's method
println(c.format("MyTrait")) //WRONG. you can't invoke StringLike's method, though there defined a implicit method in Predef can transform String to StringLike, but implicit restrict one level transform, you can't transform MixTest to String then to StringLike.
c.f1
val d = 1 :: AnyTrait
println(d.toLong)
d.toHexString // WRONG, the same as above
d.f1
An existing runtime object in the JVM has a certain size on the heap. Adding a trait to it would mean altering its size on the heap, and changing its signature.
So the only way to go would be to do some kind of transformation at compile time.
Mixin composition in Scala occurs at compile time. What compiler could potentially do is create a wrapper B around an existing object A with the same type that simply forwards all calls to the existing object A, and then mix in a trait T to B. This, however, is not implemented. It is questionable when this would be possible, since the object A could be an instance of a final class, which cannot be extended.
In summary, mixin composition is not possible on existing object instances.
UPDATED:
Related to the smart solution proposed by Googol Shan, and generalizing it to work with any trait, this is as far as I got. The idea is to extract the common mixin functionality in the DynamicMixinCompanion trait. The client should then create a companion object extending DynamicMixinCompanion for each trait he wants to have the dynamic mixin functionality for. This companion object requires defining the anonymous trait object gets created (::).
trait DynamicMixinCompanion[TT] {
implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj
def ::[OT](o: OT): Mixin[OT] with TT
class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)
}
trait OtherTrait {
def traitOperation = println("any trait")
}
object OtherTrait extends DynamicMixinCompanion[OtherTrait] {
def ::[T](o: T) = new Mixin(o) with OtherTrait
}
object Main {
def main(args: Array[String]) {
val a = "some string"
val m = a :: OtherTrait
m.traitOperation
println(m.length)
}
}
I usually used a implicit to mix in a new method to an existing object.
See, if I have some code as below:
final class Test {
def f = "Just a Test"
...some other method
}
trait MyTrait {
def doSomething = {
println("boo")
}
}
object HelperObject {
implicit def innerObj(o:MixTest) = o.obj
def mixWith(o:Test) = new MixTest(o)
final class MixTest private[HelperObject](obj:Test) extends MyTrait
}
and then you can use MyTrait method with an already existing object Test.
val a = new Test
import HelperObject._
val b = HelperObject.mixWith(a)
println(b.f)
b.doSomething
in your example, you can use like this:
import HelperObject._
val o = mixWith(DBHelper.loadMyEntityFromDB(primaryKey));
o.doSomething
I am thinking out a prefect syntax to define this HelperObject:
trait MyTrait {
..some method
}
object MyTrait {
implicit def innerObj(o:MixTest) = o.obj
def ::(o:Test) = new MixTest(o)
final class MixTest private[MyTrait](obj:Test) extends MyTrait
}
//then you can use it
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
// for your example
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething
What about an implicit class? It seems easier to me compared to the way in the other answers with a final inner class and a "mixin"-function.
trait MyTrait {
def traitFunction = println("trait function executed")
}
class MyClass {
/**
* This inner class must be in scope wherever an instance of MyClass
* should be used as an instance of MyTrait. Depending on where you place
* and use the implicit class you must import it into scope with
* "import mypackacke.MyImplictClassLocation" or
* "import mypackage.MyImplicitClassLocation._" or no import at all if
* the implicit class is already in scope.
*
* Depending on the visibility and location of use this implicit class an
* be placed inside the trait to mixin, inside the instances class,
* inside the instances class' companion object or somewhere where you
* use or call the class' instance with as the trait. Probably the
* implicit class can even reside inside a package object. It also can be
* declared private to reduce visibility. It all depends on the structure
* of your API.
*/
implicit class MyImplicitClass(instance: MyClass) extends MyTrait
/**
* Usage
*/
new MyClass().traitFunction
}
Why not use Scala's extend my library pattern?
https://alvinalexander.com/scala/scala-2.10-implicit-class-example
I'm not sure what the return value is of:
var o = DBHelper.loadMyEntityFromDB(primaryKey);
but let us say, it is DBEntity for our example. You can take the class DBEntity and convert it to a class that extends your trait, MyTrait.
Something like:
trait MyTrait {
def doSomething = {
println("boo")
}
}
class MyClass() extends MyTrait
// Have an implicit conversion to MyClass
implicit def dbEntityToMyClass(in: DBEntity): MyClass =
new MyClass()
I believe you could also simplify this by just using an implicit class.
implicit class ConvertDBEntity(in: DBEntity) extends MyTrait
I particularly dislike the accepted answer here, b/c it overloads the :: operator to mix-in a trait.
In Scala, the :: operator is used for sequences, i.e.:
val x = 1 :: 2 :: 3 :: Nil
Using it as a means of inheritance feels, IMHO, a little awkward.