3

Are there cases where it's preferable to mixin traits to access the functionality of "static" methods, rather than importing objects with those methods?

Say we want to access the functionality of a method a(). Would we ever extend a trait that contains a() rather than import an object that contains a()?

If we look at the following example:

1)

trait A {
  def a() {}
}

...

class B extends A {
  val b = a()
}

vs.

2)

object A {
  def a() {}
}

...

import A._
class B {
  val b = a()
}

Is there any reason to prefer the first approach, even if there is no "is-a" relationship between the two classes B and A?

1
  • You need a trait when a) it has abstract members (type parameter, type member, abstract mehod), b) when there may be different implementations (e.g. overriding something), c) when it carries mutable state. Otherwise, I see no reason why would want to mix in a trait that only contains "static" members. Commented Jul 19, 2013 at 21:03

2 Answers 2

4

Maybe things that extend B don't want to keep re-importing A?

Maybe the method relies upon other "static" methods but you actually want to override the implementation?

If B is final (or an object) and the methods really are static (and don't refer to implementations that you might want to change in B), then there's not much point in mixing in a trait. The only exception is if there are implicit conversions defined, where if you mix in the implicit it will have lower priority than if you declare it yourself.

(Check out scala.LowPriorityImplicits which is mixed into scala.Predef for examples.)

Sign up to request clarification or add additional context in comments.

Comments

2

All that Rex said...

And keep in mind as well that an import brings artifacts (methods, fields) into the current scope, but doesn't expose them on the new class' interface.

Mixing in a trait may expose artifacts (either public, protected, or ...) by making them "part of" the new class/trait interface.

3 Comments

I see. I think B will usually include A's artifacts in its interface only if B is logically a subtype of A.
That is definitely the perspective you should take. You'll often end up in trouble if you violate logical "IS-A"-ness by inheriting where you should instead be composing. If not now, then later...
Ok, so I think the solution to using a trait, but not mixing it in, is to use self-type annotations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.