Scala tends to encourage the use of closures instead of the type of hooks you're talking about (most of which it can't implement conveniently due to static typing and compilation).
This requires you to know in advance where flexibility in the common behavior may be desired, but is very powerful and easy to use when it's available. For example, suppose you have a method that prints out people's names:
case class Name(first: String, last: String) {
def title = last + ", " + first(0).toUpper + "."
}
trait Familiar extends Name {
override def title = first + " " + last(0).toUpper + "."
}
def listing(names: Array[Name]) = names.foreach(name => println(name.title))
val jd1 = new Name("John","Doe)
listing(Array(jd1)) // Prints Doe, J.
val jd2 = new Name("John","Doe") with Familiar
listing(Array(jd2)) // Prints John D.
but if you're really going to be changing name-printing a lot, you're better off building that in:
case class Name(first: String, last: String) {
def title = last + ", " + first(0).toUpper + "."
}
def listing(names: Array[Name], address: Name => String = _.title) =
names.map(address).foreach(println)
val jd = new Name("John", "Doe")
listing(Array(jd)) // Uses default, so prints Doe, J.
listing(Array(jd), n => n.first + " " + n.last(0).toUpper + ".") // Prints John D.