Yoda
Yoda

Reputation: 452

Dynamic mixin in Scala in scala 2.11.2

I'm comparatively new to Scala. I want to use dynamic mixins with a class (whose name, I have it as string).

class Foo extends Baz {
}

trait bar {
}

trait biz {
}

var className = "Foo"

I want something like

var instance = (object of class className) with bar with biz

I've read the solution from Dynamic mixin in Scala - is it possible?. But the Interpreter class which was used in that solution was deprecated(In scala 2.11) and it doesn't have compileAndSaveRun method. Also the code knows what the class is.

I tried to use Imain class. It also doesn't have compileAndSaveRun method. I looked into compileSourcesKeepingRun method. I'm not sure how to use it.

Is there any there any possible workaround I can do?

Upvotes: 1

Views: 896

Answers (1)

b-studios
b-studios

Reputation: 78

It is possible to use reflection to implement some limited form of dynamic composition. Given an instance of your class f: Foo and an instance of trait b: bar, Foo with bar can be implemented by delegation to the underlying objects f and b. Lets say Foo and Bar have the following abstract methods:

abstract class Foo {
  def foo: Int
}

trait Bar {
  def bar: String
}

We can then give an instance of Foo with Bar by delegation:

val f: Foo = ...
val b: Bar = ...

val both = new Foo with Bar {
  def foo = f.foo
  def bar = b.bar    
}

This is essentially what my mixin composition library automatically does for you. It provides the method

def mix[A, B](a: A, b: B): A with B

that can be used to compose f and b by a simple call to mix(f, b). The library takes the approach of using a type-class

trait With[A, B] {
  def apply(a: A, b: B): A with B
}

as evidence that A and B can be composed. This has the advantage that multiple ways of providing this evidence are possible: (1) Using reflection, (2) using macros and (3) manually specifying an instance of With for particular arguments A and B.

However, as mentioned before, this form of dynamic composition is limited. Since this approach is based on forwarding, you do not get proper late binding of methods. This limitation is common to all solutions (like the decorator pattern) that are based on forwarding. Also expressing dependencies to other components via self-type annotations does not work, since the individual traits have to be instantiated separately and cannot have unfulfilled dependencies.

Upvotes: 2

Related Questions