Can I mixin a trait to a existed object?

527 views
Skip to first unread message

linjie nie

unread,
Apr 7, 2011, 10:17:27 PM4/7/11
to scala...@googlegroups.com
Hi list -

As a newbie, I know I can mixin a trait when create a object, val foo=new Foo() with Bar.
My question is, can I mixin a trait to a object, which is created by someone else?

val foo=new Foo()
....
val foo2=foo with Bar //error

Thanks a lot
Jason

Sciss

unread,
Apr 7, 2011, 10:21:22 PM4/7/11
to linjie nie, scala...@googlegroups.com

Kevin Wright

unread,
Apr 7, 2011, 10:31:05 PM4/7/11
to Sciss, linjie nie, scala...@googlegroups.com
Almost... this is currently the live one: https://github.com/kevinwright/Autoproxy-Lite

Though in all fairness, I should point out that you can get 80% of that through an implicit conversion from some object instance to a contained member.
 

On 8 Apr 2011, at 03:17, linjie nie wrote:

> Hi list -
>
> As a newbie, I know I can mixin a trait when create a object, val foo=new Foo() with Bar.
> My question is, can I mixin a trait to a object, which is created by someone else?
>
> val foo=new Foo()
> ....
> val foo2=foo with Bar //error
>
> Thanks a lot
> Jason




--
Kevin Wright

gtalk / msn : kev.lee...@gmail.com
mail: kevin....@scalatechnology.com
vibe / skype: kev.lee.wright
quora: http://www.quora.com/Kevin-Wright
twitter: @thecoda

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra

Sciss

unread,
Apr 7, 2011, 10:37:13 PM4/7/11
to Kevin Wright, linjie nie, scala...@googlegroups.com
very interesting - can you outline why it's called Autoproxy-Lite? has it somehow reduced functionality?

best, -sciss-

Kevin Wright

unread,
Apr 7, 2011, 11:11:58 PM4/7/11
to Sciss, linjie nie, scala...@googlegroups.com
On 8 April 2011 03:37, Sciss <con...@sciss.de> wrote:
very interesting - can you outline why it's called Autoproxy-Lite? has it somehow reduced functionality?

best, -sciss-

Indeed I can :)

It's lite because it can only add delegates for methods already on the interface of a class.  Technically, this means that the program is syntactically valid after the type-checking compiler phase (but before the delegates are generated).  In practice, this means that you *normally* have to also inherit from the type you're proxying.

Stefan Langer

unread,
Apr 8, 2011, 3:46:27 AM4/8/11
to linjie nie, scala...@googlegroups.com
The easiest way to realize this is create a wrapper class that has the
mixin and use implicits to convert.

example:

val foo = new Foo()

case class RichFoo(foo: Foo) extends Bar

implicit def foo2RichFoo(foo: Foo): RichFoo = RichFoo(foo)
implicit def richFoo2Foo(richFoo: RichFoo): Foo = richFoo.foo

now you can simply do

val foo2: RichFoo = foo
val foo: Bar = foo

you can also simply call foo.methodInBar and the implicit will take
care of the rest.

Be aware that this will always happen when implicits are in scope

-Stefan
2011/4/8 linjie nie <niel...@gmail.com>:

Kevin Wright

unread,
Apr 8, 2011, 6:18:55 AM4/8/11
to Stefan Langer, linjie nie, scala...@googlegroups.com
implicit conversion from an instance to some contained member is one of my favourite tricks, though there are a couple of situations where it's less powerful than a true mixin.

1. The Rich type should subclass the underlying type, acting as a decorator and adding some state.  Implicit conversion from RichFoo to Foo and back again will lose this information.  This is really only relevant if mutability will also be involved.

2. You use the Rich type to selectively override some aspect of behaviour, but also need it to directly implement the underlying interface to be used with e.g. reflection

3. You need this stuff to be usable from Java


I'll accept that mutability (and use of Java) are very often bad practices to be avoided, but they're also necessary evils for a great many people.

Stefan Langer

unread,
Apr 8, 2011, 7:04:14 AM4/8/11
to Kevin Wright, linjie nie, scala...@googlegroups.com
Good point about the mutablitity I tend to forget about it since I
prefer immutable structures especially when working with case classes.

2011/4/8 Kevin Wright <kev.lee...@gmail.com>:

john sullivan

unread,
Apr 9, 2011, 1:10:32 PM4/9/11
to Stefan Langer, linjie nie, scala...@googlegroups.com
I'm not an expert on the Scala type system yet, so I haven't worked this out yet, but it vaguely seems to me that there should be a way to do this without relying on implicits by using traits and self types..
--
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy.

Naftoli Gugenheim

unread,
Apr 9, 2011, 11:43:12 PM4/9/11
to john sullivan, Stefan Langer, linjie nie, scala...@googlegroups.com
On Sat, Apr 9, 2011 at 1:10 PM, john sullivan <sullym...@gmail.com> wrote:
I'm not an expert on the Scala type system yet, so I haven't worked this out yet, but it vaguely seems to me that there should be a way to do this without relying on implicits by using traits and self types..

It's not so much about the type system as it's about the JVM.

As it is when you write

val v = new MyClass with MyTrait

you are doing something that the JVM can't do directly. What's happening behind the scenes is that scalac is generating a new class automatically that extends MyClass, implements MyTrait's interface, and forwards to MyTrait's method implementations, and compiling your code to new AutoGeneratedClass.

If scalac would compile

val v = new MyClass
val x = v with MyTrait

what would it compile it to?

Sciss

unread,
Apr 9, 2011, 11:50:03 PM4/9/11
to Naftoli Gugenheim, john sullivan, Stefan Langer, linjie nie, scala...@googlegroups.com
maybe i'm mistaken, but i don't see this as a problem of the JVM. the type of v is known to the compiler, so it could equally produce a class that extends the type of v (as seen by the compiler) and MyTrait and puts synthetic forwarders to the underlying objects. as far as i understand, that is more or less what kevin wright's autoproxy plugin is doing anyway.

best, -sciss-

HamsterofDeath

unread,
Apr 10, 2011, 5:22:06 AM4/10/11
to scala...@googlegroups.com
and groovy's @Delegate

Kevin Wright

unread,
Apr 10, 2011, 9:33:16 AM4/10/11
to HamsterofDeath, scala...@googlegroups.com
Mixins (the regular sort, not my autoproxy stuff) work via a three--pronged approach.

1. The trait becomes an interface, exposing both abstract and concrete method signatures for the trait
2. A helper class is created, containing static methods that correspond to non-abstract methods on the trait.  These are transformed to an instance of the trait's self-type as the first parameter
3. When used as a mix-in, entire method bodies can be directly cloned into the receiving type.  This is far more common than creating fowarders to the static methods, though I won't go into the exact rules right now covering when a specific approach is used.

At present, all autoproxy does is to create synthetic forwarders.  One future planned optimisation is to directly us the static methods that traits generate, this should make life significantly easier for the JVM to squeeze out a bit of extra performance.

Either way... the necessary structure for this to happen is already largely in place.  As an alternate approach, a quick websearch for "Scala Roles" will bring up a different, and rather interesting, take on the whole idea.

Tupshin Harper

unread,
Apr 10, 2011, 2:37:24 PM4/10/11
to scala-user
FWIW, I have updated the Scala Roles code (http://mp.binaervarianz.de/
scala_roles/) so that it builds with 2.8 or 2.9 and put it on github
here (https://github.com/tupshin/Scala-Roles). Feel free to contact me
if you are interested in working with roles.

-Tupshin
> gtalk / msn : kev.lee.wri...@gmail.com
> <kev.lee.wri...@gmail.com>mail: kevin.wri...@scalatechnology.com
Reply all
Reply to author
Forward
0 new messages