This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Language improvement proposal - dynamic mixins

1 reply
pkolaczk
Joined: 2010-01-14,
User offline. Last seen 2 years 38 weeks ago.

Hi everyone,

Currently we can mixin traits either when defining a new class or at
object construction. E.g. I like the fact how I can decorate the Map
with MultiMap:

scala> import collection.mutable._
import collection.mutable._

scala> val map = new HashMap[String, Set[String]] with MultiMap[String,
String]
map:
scala.collection.mutable.HashMap[String,scala.collection.mutable.Set[String]]
with scala.collection.mutable.MultiMap[String,String] = Map()

scala> map.addBinding("first", "1a")
res5: map.type = Map(first -> Set(1a))

scala> map.addBinding("first", "1b")
res6: map.type = Map(first -> Set(1b, 1a))

This is really cool. However, when I wanted to use the same construct
with a factory method instead of the constructor, it failed:

scala> HashMap("first" -> Set("1a")) with MultiMap[String, String]
:1: error: ';' expected but 'with' found.
HashMap("first" -> Set("1a")) with MultiMap[String, String]
^
This is pretty sad, because even the core Scala API encourages to use
factory methods in the companion objects and not using the constructor
directly. So I cannot use cool mixins with objects that I cannot control
every detail of construction.

Assume expression evaluates to type A.
What I propose is to add another use case for the "with" keyword with
the following syntax:

expression with T

It should evaluate to an object wrapper of type A with T. The wrapper
would delegate methods defined in type A to the original wrapped object,
but should also support the methods added / overriden by the mixed in
trait(s).

As for the implementation, I feel like it could be implemented using
techniques similar to what JDK dynamic proxies or CGLIB library can do.
The problem with JDK proxies is that they work only with interfaces, not
concrete classes, but CGLIB somehow overcomes this limitation (I don't
know how, but it works - see the net.sf.cglib.proxy.Enhancer class). Of
course, the code for creation of the proxy should be generated by the
compiler whenever it encounters a "expression with trait" construct.

If we had this, it would open many new interesting possibilities, and
for sure make traits more dynamic. You'd be able to add new methods or
roles to existing objects dynamically, which I find very interesting.
What do you think about it? What are the problems that I missed? Or
maybe there is a workaround and I can achieve such dynamic behaviour
right now in Scala 2.9?

Best regards,
Piotr

Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Language improvement proposal - dynamic mixins
Anything that uses CGLIB or any other bytecode manipulation tool will not port to other VM architectures, including Android. Unless you can come up with a way that does not involve bytecode manipulation, it is unlikely this would be added to the core scala. However it is always possible for someone to write a compiler plugin.


2011/11/21 Piotr Kołaczkowski <pkolaczk [at] elka [dot] pw [dot] edu [dot] pl>
Hi everyone,

Currently we can mixin traits either when defining a new class or at object construction. E.g. I like the fact how I can decorate the Map with MultiMap:

scala> import collection.mutable._
import collection.mutable._

scala> val map = new HashMap[String, Set[String]] with MultiMap[String, String]
map: scala.collection.mutable.HashMap[String,scala.collection.mutable.Set[String]] with scala.collection.mutable.MultiMap[String,String] = Map()

scala> map.addBinding("first", "1a")
res5: map.type = Map(first -> Set(1a))

scala> map.addBinding("first", "1b")
res6: map.type = Map(first -> Set(1b, 1a))

This is really cool. However, when I wanted to use the same construct with a factory method instead of the constructor, it failed:

scala> HashMap("first" -> Set("1a")) with MultiMap[String, String]
<console>:1: error: ';' expected but 'with' found.
      HashMap("first" -> Set("1a")) with MultiMap[String, String]
                                    ^
This is pretty sad, because even the core Scala API encourages to use factory methods in the companion objects and not using the constructor directly. So I cannot use cool mixins with objects that I cannot control every detail of construction.

Assume expression evaluates to type A.
What I propose is to add another use case for the "with" keyword with the following syntax:

expression with T

It should evaluate to an object wrapper of type A with T. The wrapper would delegate methods defined in type A to the original wrapped object, but should also support the methods added / overriden by the mixed in trait(s).

As for the implementation, I feel like it could be implemented using techniques similar to what JDK dynamic proxies or CGLIB library can do.
The problem with JDK proxies is that they work only with interfaces, not concrete classes, but CGLIB somehow overcomes this limitation (I don't know how, but it works - see the net.sf.cglib.proxy.Enhancer class). Of course, the code for creation of the proxy should be generated by the compiler whenever it encounters a "expression with trait" construct.

If we had this, it would open many new interesting possibilities, and for sure make traits more dynamic. You'd be able to add new methods or roles to existing objects dynamically, which I find very interesting.
What do you think about it? What are the problems that I missed? Or maybe there is a workaround and I can achieve such dynamic behaviour right now in Scala 2.9?

Best regards,
Piotr


Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland