2

I want to do this:

trait Renderable {
    def render: String
}

trait Parens extends Renderable {
    abstract override def render = "(" + super.render + ")"
}

object Foo extends Renderable with Parens {
    def render = "Hello"
}

But this does not work because the linearization order puts Parens after Foo (Foo always comes, of course) so Parens can't advise Foo.render.

I end up doing this:

trait FooRender {
    def render = "Hello"
}

object Foo extends FooRender with Parens {
}

But sometimes I really don't want to do that because it breaks things up. As far as I can tell, linearization order is the only thing getting in the way, but I don't know a way to change that. What might make this cleaner?

Owen
  • 38,836
  • 14
  • 95
  • 125

1 Answers1

2

How about separating the presentation logic (render) and the actual contents (value)?

trait Renderable {
  def value : String
  def render = value // default presentation logic, simple rendering.
}

trait Parens extends Renderable {
  override def render :String = "(" + value + ")" // parens rendering.
}

object Foo extends Parens {
  def value = "Hello"
}

println(Foo.render) // prints '(Hello)'

Edit

Found a way you can do pretty much what you wanted, check it out:

trait Renderable {
  def render: String
}

trait Parens extends Renderable {
  abstract override def render = "(" + super.render + ")"
}

class Foo extends Renderable {
  def render = "Hello"
}

val foo = new Foo with Parens
println(foo.render)

You can't use an object since you need to implement the trait at creation time, but if you can control the instance creation then this might work :).

I'm pretty sure it's not possible to do it otherwise (someone please correct me if I'm wrong)

Pablo Fernandez
  • 103,170
  • 56
  • 192
  • 232
  • Because then traits don't stack anymore. That's another option I've used occasionally, though. – Owen Oct 23 '11 at 02:39
  • what do you mean by "traits don't stack" ? – Pablo Fernandez Oct 23 '11 at 02:42
  • The problem with the code you posted is that your `Foo` already has the `render` method defined, so there's no need to go up the call hierarchy looking for another implementation. It will always execute the `Foo` method – Pablo Fernandez Oct 23 '11 at 02:47
  • I mean that if Parens has `value` in the "inside" and `render` on the "outside" it can't be used like a mixin; ie, it cannot be composed with other traits defined along the same pattern, which is really what I'm going for. – Owen Oct 23 '11 at 03:32
  • What is "stackable" here is the rendering behavior. The value is not – Pablo Fernandez Oct 23 '11 at 03:46
  • Right... but if Parens refers to `value`, then it isn't stackable anymore. – Owen Oct 23 '11 at 04:29
  • I do like the idea of separating the presentation logic out with a trait... in fact many times this limitation has forced me into making a better design. There are times though when I wish I could get around it. – Owen Oct 23 '11 at 06:03
  • Found a new way of doing it, check it out! – Pablo Fernandez Oct 23 '11 at 23:30