0

I'm trying to write a method in a trait that's recursive on types, but I'm running into the problem that I can't write the base case in such a way that the compiler is convinced I know what I'm doing.

Here's a gist:

trait InheritableBehavior {
  def superClassWithInheritableBehavior: Option[Class[_]] = {
    // reflection and magic (from some library's code)
  }

  def doSomething() {
    if (this.superClassWithInheritableBehavior.isDefined) {
      super.doSomething()
    } else {
      // base case here, which relies on local fields
    }
  }
}

The compiler suggests I mark doSomething() with abstract override, but there is no concrete implementation. Everything is in that one method.

I suppose I could split the trait into two--BaseInheritableTrait, which doesn't call super, and DerivedInheritableTrait which includes the super call, but is there any better way to deal with this?

What I'd love to be able to do is super.asInstanceOf[InheritableTrait].doSomething(), but that doesn't seem to be possible.

Todd O'Bryan
  • 2,234
  • 17
  • 30

1 Answers1

1

Sometimes the compiler is right when it is convinced that we don't know what we're doing.

I'm not sure what you mean by "there is no concrete implementation."

Normally, abstract override means you'll be mixed in with a class that has a concrete implementation. Otherwise, there would be nothing to invoke.

Possibly, you mean, "I have a class with InheritableTrait, and I want to extend it and mix in InheritableTrait again." But actually, you can't do that. Your mix-ins are linearized once.

There was a recent question with a great answer, which I'll try to find for you. And maybe we can mark this as dupe.

Update: here's a similar recent question which may help answer or help improve your question. It includes a fine and thorough answer, though frankly I prefer the other answer which received no love but includes fun code.

Consideration:

is there any better way to deal with this?

Maybe what you're looking for is a self-type here, where you want to specify that you're mixed-in with something:

trait Me { _: Konkret =>
  def run() = concrete()
}

Maybe there are different kinds of Konkret and you want to determine reflectively what to do?

Or maybe you just want a template method:

trait Me {
  def doSomething(): Unit
  def run() = doSomething()
}
Community
  • 1
  • 1
som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • What I meant by "no concrete implementation" is that the same method works for the base and any derived classes, so the method that calls super would work as a concrete implementation if the compiler wouldn't insist it say abstract override. I'm going to try two versions of the trait. Not clean, but I think I can make it work. – Todd O'Bryan Jul 14 '13 at 20:38