1

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?

Community
  • 1
  • 1
Yoda
  • 442
  • 3
  • 14
  • You can't achieve that with "standard" scala. Byt I'm pretty sure that with scala macros and quasi quotes more specifically it's doable – Eugene Zhulenev Sep 14 '14 at 05:07

1 Answers1

2

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.

b-studios
  • 78
  • 1
  • 6
  • That's a pretty slick library! What do you mean by not getting proper late binding of methods? Does that refer to the inability of either type to have abstract members at the time of composition? – acjay Sep 14 '14 at 14:40
  • The composition operator `A with B` in my library is right biased. Thus if a method `foo` occurs in both `A` and `B` a call to the method will be forwarded to `B`. However, if `foo` is called from within `A` the receiver of the method call is not set to be the composed object `A with B` (which would be the case with proper late binding) but is set to the object of type `A`. Another way of phrasing it is, that by using the composition operator `c = mix(a, b)` the reference `this` of `a` and `b` is not updated to `c`. – b-studios Sep 15 '14 at 10:58
  • Gotcha -- which would affect the ability to do self-type annotations or abstract members. Yeah, hopefully this is something that can be addressed in future Scala versions. Runtime composition is super useful for plugin/component systems, where one wants to mixin common functionality. – acjay Sep 15 '14 at 15:39