I have the following classes in Scala:
class A {
def doSomething() = ???
def doOtherThing() = ???
}
class B {
val a: A
// need to enhance the class with both two functions doSomething() and doOtherThing() that delegates to A
// def doSomething() = a.toDomething()
// def doOtherThing() = a.doOtherThing()
}
I need a way to enhance at compile time class B with the same function signatures as A that simply delegate to A when invoked on B.
Is there a nice way to do this in Scala?
Thank you.
In Dotty (and in future Scala 3), it's now available simply as
class B {
val a: A
export a
}
Or export a.{doSomething, doOtherThing}.
For Scala 2, there is unfortunately no built-in solution. As Tim says, you can make one, but you need to decide how much effort you are willing to spend and what exactly to support.
You can avoid repeating the function signatures by making an alias for each function:
val doSomething = a.doSomething _
val doOtherthing = a.doOtherThing _
However these are now function values rather than methods, which may or may not be relevant depending on usage.
It might be possible to use a trait or a macro-based solution, but that depends on the details of why delegation is being used.
Implicit conversion could be used for delegation like so
object Hello extends App {
class A {
def doSomething() = "A.doSomething"
def doOtherThing() = "A.doOtherThing"
}
class B {
val a: A = new A
}
implicit def delegateToA(b: B): A = b.a
val b = new B
b.doSomething() // A.doSomething
}
There is this macro delegate-macro which might just be what you are looking for. Its objective is to automatically implement the delegate/proxy pattern, so in your example your class B must extend class A.
It is cross compiled against 2.11, 2.12, and 2.13. For 2.11 and 2.12 you have to use the macro paradise compile plugin to make it work. For 2.13, you need to use flag -Ymacro-annotations instead.
Use it like this:
trait Connection {
def method1(a: String): String
def method2(a: String): String
// 96 other abstract methods
def method100(a: String): String
}
#Delegate
class MyConnection(delegatee: Connection) extends Connection {
def method10(a: String): String = "Only method I want to implement manually"
}
// The source code above would be equivalent, after the macro expansion, to the code below
class MyConnection(delegatee: Connection) extends Connection {
def method1(a: String): String = delegatee.method1(a)
def method2(a: String): String = delegatee.method2(a)
def method10(a: String): String = "Only method I need to implement manually"
// 96 other methods that are proxied to the dependency delegatee
def method100(a: String): String = delegatee.method100(a)
}
It should work in most scenarios, including when type parameters and multiple argument lists are involved.
Disclaimer: I am the creator of the macro.
Related
I am trying to make a wrapper class around ParSeq, in order to extend with some of my own functionality. This is what I have so far
class MyParSeq[A](s: ParSeq[A]) extends ParSeq[A] {
override def apply(i: Int): A = s(i)
override def length: Int = s.length
override def seq: Seq[A] = s.seq
override protected def splitter: SeqSplitter[A] = ???
}
I understand what the splitter does and I would like the same parallel semantics as ParSeq, only problem; the splitter is marked protected. How do I wrap around ParSeq without redefining the SeqSplitter?
Since SeqSplitter is protected, then you shouldn't really try to redefine it.
The more canonical way to extend classes with additional methods in Scala is by using a pattern called extension methods (also called implicit classes in Scala).
implicit class ParSeqOps[A](parSeq: ParSeq[A]) {//name of parameter doesn't matter, only type
def second: A = parSeq(1) //you can define multiple methods here
def isLengthEven: Boolean = parSeq.length % 2 == 0
}
Whenever implicit class ParSeqOps is in scope, you'd be able to use all methods you defined like they were members of ParSeq:
ParSeq(1,2,3,4).second // 2
ParSeq(1,2,3,4).isLengthEven //true
How can I run methods from inside a specific ExecutionContext only?
For example, consider this code:
trait SomeTrait {
private var notThreadSafe = 0 // mutable var!
def add(i: Int) = ???
def subtract(i: Int) = ???
}
This code is only correct if methods add and subtract are called from the same thread only. What are the ways to make those methods always use a specific ExecutionContext (which would make sense if there is exactly 1 worker in the EC)? Any easy ways?
To get a grasp on the question, here are some example answers:
Answer1: wrap the body of all methods in Future.apply, like this:
class SomeClass {
private implicit val ec: ExecutionContext = ???
private var notThreadSafe = 0
def add(i: Int) = Future {
???
}
def subtract(i: Int) = Future {
???
}
}
Answer2: use an akka actor, convert all methods to incoming actor messages and use the ask pattern to work with the actor. If you don't mess things up intentionally, all methods will run from your actor-s EC.
Answer3: maybe write a macro function that would convert a trait to its Future-ized version? Like expanding this code:
MyTrickyMacro.futurize(underlying: SomeTrait)(ec)
to this:
class MacroGeneratedClass(underlying: SomeTrait)(implicit ec: ExecutionContext) {
def add(i: Int) = Future(underlying.add(i))
def subtract(i: Int) = Future(underlying.subtract(i))
}
Now, I think Answer1 is generally OK, but prone to errors and a bit of boilerplate. Answer2 still requires boilerplate code to be written, forces you to create case classes to contain function arguments and requires akka. And I didn't see any implementations Answer3.
So... Is there an easy way to do that?
I am using a library which has a class that has a generic type that can be quite complicated. I need to write a method that takes a parameter with the generic type that a val of the library class has, and I would like to avoid having to write out the type in the method signature. I thought I might be able to create an implicit class which adds a type to the val that I could use in the method signature, kind of like:
// This comes from a library and can't be changed
case class LibraryClass[A](a: A)
//----------------------------------
object MyCode {
val thing = LibraryClass(3)
implicit class LibraryClassWithType[A](lc: LibraryClass[A]) {
type TheType = A
}
def doStuff(something: thing.TheType): Unit = {
println(something)
}
}
This does not compile (TheType is not a member of LibraryClass). But if I wrap it in the class myself, it works
val thingWithType = LibraryClassWithType(thing)
def doStuff(something: thingWithType.TheType): Unit = {
println(something)
}
Is there something I am missing that will make this work, or is this kind of implicit conversion not valid Scala?
I haven't been able to do this sort of thing with implicits, but I have had to do something similar where I just instantiated these sorts of type holders:
case class LibraryClass[A](a: A)
object MyCode {
val thing = LibraryClass(3)
class HigherTypeHolder[A,F[A]](a: F[A]) {
type AT = A
}
val th = new HigherTypeHolder(thing)
def doStuff(something: th.AT): Unit = {
println(something)
}
}
You can do what (I think) you want like this:
implicit val thing = LibraryClass(3)
def doStuff[A](something: A)(implicit lc: LibraryClass[A])
What I don't understand is why this needs to be so complicated. Why not for example stick with your second approach, without implicits, that works, or why not just do
def doStuff[A](something: A) to begin with?
Is there any possibility to implicitly forward some of class methods to encapsulated object?
case class Entity(id: Int, name: String,) {
private lazy val lastScan = new LastScan
def getLastScanDate = lastScan.getLastScanDate
def updateLastScanDate = lastScan.updateLastScanDate
}
I want to avoid creating def updateLastScanDate = lastScan.updateLastScanDate just to forward methods to wrapped object.
In the plain language this is not possible. There used to be a compiler plugin by Kevin Wright to achieve this automatic delegation.
He seems to be working on an Autorproxy "Rebooted" version now that is macro based, making it straight forward to include in your project. I'm pasting here an example from its test sources:
trait Bippy {
def bippy(i : Int): String
}
object SimpleBippy extends Bippy {
def bippy(i: Int) = i.toString
}
#delegating class RawParamWrapper(#proxy pivot: Bippy)
val wrapper = new RawParamWrapper(SimpleBippy)
assert(wrapper.bippy(42) == "42")
Consider the following typical Scala 'pimp' code:
class PimpedA(a:A){
def pimp() = "hi"
}
implicit def pimpA(a:A) = new PimpedA(a)
new A(){
pimp() //<--- does not compile
}
However, changing it to:
new A(){
this.pimp()
}
Makes it work.
Shouldn't it be the same to the Scala compiler?
EDIT : Is there any solution that can make it work without having to add the this.?
Not at all. For it to work, pimp needs to be either an object or an imported member of a value, and it is neither. A class has an "implicit" import this._. It has not a mechanism that auto-prepends this to stuff to see if it compiles.
In this case you should give compiler a hint that pimp() is not a random function. When you write
this.pimp()
compiler know there isn't pimp function on class A so it's an error and before giving up it searches implicit conversion in scope and finds it.
pimpA(this).pimp()
And when you just call pimp() compiler doesn't know what object to pass to the pimpA(a: A) implicit function.
UPDATE
It is hard to understand what is your goal. I can only suggest to make PimpedA a typeclass (Pimp[T] in this example).
trait Pimp[T] {
def action(p: T): String
}
implicit object PimpA extends Pimp[A] {
override def action(p: A) = "some actions related to A"
}
def pimp[T: Pimp](p: T) = implicitly[Pimp[T]].action(p)
class A {
val foo = pimp(this)
}
scala> new A foo
res2: String = some actions related to A