Why does x.func below return "B extends B extends B"?
How to arrange this code so that it returns "B extends A extends Base"?
trait Base {
def name = "Base"
def func = name
}
trait A extends Base {
override def name = "A"
override def func = name + " extends " + super.func
}
trait B extends Base {
override def name = "B"
override def func = name + " extends " + super.func
}
val x = new Base with A with B
println(x.func)
Update: One arrangement could be as follows. It now has identical definitions of func1 in A and B. It does not work if I try to move it to the Derived class. Any ideas how to remove the repetition of func1?
trait Base {
def name = "Base"
def func1(s: String) = s
}
trait Derived extends Base {
def func = func1(name)
}
trait A extends Derived {
override def func1(s: String) = s + " extends " + super.func1(super.name)
override def name = "A"
}
trait B extends Derived {
override def func1(s: String) = s + " extends " + super.func1(super.name)
override def name = "B"
}
val x = new Base with A with B
println(x.func)
I think the inheritance order may actually be the one your are seeking. If you replace the " extends " with one that shows which method of which trait is called:
trait Base {
def name = "Base"
def func = "Base." + name
}
trait A extends Base {
override def name = "A"
override def func = name + " A.extends " + super.func
}
trait B extends Base {
override def name = "B"
override def func = name + " B.extends " + super.func
}
val x = new Base with A with B
println(x.func)
// B B.extends B A.extends Base.B
It's just that name is always "B". In other words:
trait Base { def func = "Base" }
trait A extends Base { override def func = "A extends " + super.func }
trait B extends Base { override def func = "B extends " + super.func }
val x = new Base with A with B
println(x.func)
// B extends A extends Base
which is what you want...
The full linearization of your example is:
Object, B, A, Base, ScalaObject, AnyRef, Any
(see http://ofps.oreilly.com/titles/9780596155957/ScalaObjectSystem.html#Linearization for a practical explanation on how to figure out the linearization)
Edit to answer comment: why is the name always returns "B"? That's because the def name method is overridden by the trait B to return "B". That's the whole point of inheritance, to be able to use in superclasses behavior that is refined in subclasses:
trait Legs {
def legs: Int
def printLegs() { println("I have " + legs + " legs") }
}
class Dog extends Legs { def legs = 4 }
class Chicken extends Legs { def legs = 2 }
new Dog printLegs
// I have 4 legs
new Chicken printLegs
// I have 2 legs
legs in trait Legs is not a separate one than legs in Dog depending on if you refer to it in Legs or Dog... Similarly, your def name will always return "B" if your object is a B.
It looks like you want to use name as a private method:
trait Base {
private def _name() = "Base"
def func = _name
}
trait A extends Base {
private def _name() = "A"
override def func = _name + " extends " + super.func
}
trait B extends Base {
private def _name() = "B"
override def func = _name + " extends " + super.func
}
val x = new Base with A with B
println(x.func)
// B extends A extends Base
I find that if there isn't a clear object model, using trait and inheritance quickly gets complicated. I assume you sanitized/simplified the example to use generic names like A, B, Base, func so that you get to the core of the issue, but on the other hand it doesn't give me any insights on what changes you could do to make it work for you. As you asked I've arrange the code so that it prints "B extends A extends Base". I'm sure there are a bunch of other constraints that aren't in the question why it won't work for you.
Related
I was following along this tutorial by Jonas Bonér on how to achieve AspectJ like aspect oriented programming in Scala. The mixins got me quite confused with the abstract overrides. I eventually got the implementation working by matching parsePointcutExpression. However, The pointcutExpression matching is incorrect:
My Invocation case class:
package aspect2
import java.lang.reflect.Method
object aspect {
case class Invocation(val method: Method, val args: Array[AnyRef], val target: AnyRef) {
def invoke: AnyRef = method.invoke(target, args:_*)
override def toString: String = "Invocation [method: " + method.getName + ", args: " + args + ", target: " + target + "]"
}
}
My interceptor and advice methods for matching pointcutExpressions and logging: Note I want to match against "execution(* *.bar(..))".
package aspect2
import aspect2.aspect.Invocation
import org.aspectj.weaver.tools.{PointcutExpression, PointcutParser}
object InterceptorImpl {
trait Interceptor {
protected val parser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution
protected def matches(pointcut: PointcutExpression, invocation: Invocation): Boolean = {
pointcut.matchesMethodExecution(invocation.method).alwaysMatches ||
invocation.target.getClass.getDeclaredMethods.exists(pointcut.matchesMethodExecution(_).alwaysMatches) ||
false
}
def invoke(invocation: Invocation): AnyRef
}
trait LoggingInterceptor extends Interceptor {
val loggingPointcut = parser.parsePointcutExpression("execution(* *.bar(..))")
abstract override def invoke(invocation: Invocation): AnyRef =
if (matches(loggingPointcut , invocation)) {
println("=====> Enter: " + invocation.method.getName + " # " + invocation.target.getClass.getName)
val result = super.invoke(invocation)
println("=====> Exit: " + invocation.method.getName + " # " + invocation.target.getClass.getName)
result
} else super.invoke(invocation)
}
}
My factory methods to wire in the interceptors using Java Dynamic Proxy API
package aspect2
import java.lang.reflect.{InvocationHandler, Method, Proxy}
import aspect2.aspect.Invocation
object ManagedComponentFactory {
def createComponent[T](intf: Class[T] forSome {type T}, proxy: ManagedComponentProxy): T =
Proxy.newProxyInstance(
proxy.target.getClass.getClassLoader,
Array(intf),
proxy).asInstanceOf[T]
}
class ManagedComponentProxy(val target: AnyRef) extends InvocationHandler {
override def invoke(proxy: AnyRef, m: Method, args: Array[AnyRef]): AnyRef = invoke(Invocation(m, args, target))
def invoke(invocation: Invocation): AnyRef = invocation.invoke
}
My main function to run the demo:
package aspect2
import aspect2.InterceptorImpl.LoggingInterceptor
import aspect2.aspect.Invocation
object aspectDemo extends App{
var foo = ManagedComponentFactory.createComponent[Foo](
classOf[Foo],
new ManagedComponentProxy(new FooImpl)
with LoggingInterceptor{
override def invoke(invocation:Invocation):AnyRef={
super.invoke(invocation)
}
})
foo.foo("foo")
foo.bar("bar")
}
Foo and Bar are implemented as follows:
trait Foo {
def foo(msg: String)
def bar(msg: String)
}
class FooImpl extends Foo {
val bar: Bar = new BarImpl
def foo(msg: String) = println("msg: " + msg)
def bar(msg: String) = bar.bar(msg)
}
trait Bar {
def bar(msg: String)
}
class BarImpl extends Bar {
def bar(msg: String) = println("msg: " + msg)
}
My results show that my pointcut ("execution(* *.bar(..))") gets both foo.bar("bar") and foo.foo("foo")
The problem was in the line invocation.target.getClass.getDeclaredMethods.exists(pointcut.matchesMethodExecution(_).alwaysMatches) in the object InterceptorImpl which matches all methods of the class. Since both methods foo and bar belong to trait Foo which is extended by class FooImpl the pointcutExpression matches logging happens for both methods.
I know I can add a companion object to a class for static def/val but my problem is I want it to comfirm to a trait. I want access to this static val or def as an abstract type (using the word static here in terms of the behaviour expected from java static)
Consider this code
trait A {
def aBehavior(): Unit
}
trait B {
def bBehavior(): Unit
def description: String
}
case class M extends A with B {
override def aBehavior() = print("A behavior of M")
override def bBehavior() = print("B behavior of M")
override def description = "I'm M"
}
I want to be able to call M.description as a static method without having an instance of M. My use case is I have a spark dataset of M objects and I want to see the description property of M without getting a record from the dataset because that will result in a spark action / job
Is there a scala pattern I can use for this. Thanks
Just create a companion object for M which defines the static value and then reference that in the case class
object M {
val description = "I'm M"
}
case class M extends A with B {
override def description = M.description
}
or assuming commonality between subtypes
trait Description {
val title: String
val description = s"I'm ${title}"
}
object M extends Description {
val title = "M"
}
object N extends Description {
val title = "N"
}
case class M() extends A with B {
override def description = M.description
}
case class N() extends A with B {
override def description = N.description
}
You can refactor description of B into another trait like:
trait BInfo {
def description: String
}
trait B extends BInfo {
def bBehavior(): Unit
def bInfo: BInfo
final override def description = bInfo.description
}
case class M() extends A with B {
override def aBehavior() = print("A behavior of M")
override def bBehavior() = print("B behavior of M")
override def bInfo = M
}
object M extends BInfo {
override def description = "I'm M"
}
val m = M()
M.description // I'm M
m.description // I'm M
This is the simplified code of a class(object) I'm working on:
object T {
val default = A
val options = List(A,B,C)
sealed trait T
object A extends T {
override def toString = "A"
}
object B extends T {
override def toString = "B"
}
object C extends T {
override def toString = "C"
}
}
This hierarchy maps directly to GUI element which requires a options = List(A,B,C) to build.
Problem with current approach:
Every time I add an extra object I have to change the option manually. This isn't too much work however the code isn't too elegant this way.
My question is:
Can I generate a list of inner objects during compile time? I wouldn't like to do this during runtime, it would be an overkill.
To add to #Samar's comment, to make it clear. The following is what you need:
import scala.reflect.runtime.universe._
case object K {
val default = A
val options = getObjects[this.type]
sealed trait T
object A extends T {
override def toString = "A"
}
object B extends T {
override def toString = "B"
}
object C extends T {
override def toString = "C"
}
def getObjects[T: TypeTag] = typeOf[T].members.collect {
case m: ModuleSymbol if m.isModule => m
}.toList
}
I have a FAMILY of types that I want to modularly "enrich" using mixins. For example:
trait Family {
self =>
trait Dog {
def dogname:String
def owner:self.Person
}
trait Person {
def name:String
def pet:self.Dog
}
}
trait SerializableFamily extends Family {
trait Dog extends super.Dog {
def toSimpleString:String = "Dog(" + dogname + ")"
}
trait Person extends super.Person {
def toSimpleString:String = "Person(" + name + ") and his pet " + pet.toSimpleString
}
}
trait SerializableFamily2 extends Family {
trait Dog extends super.Dog {
def toLoudString:String = "Dog(" + dogname.toUpperCase + ")"
}
trait Person extends super.Person {
def toLoudString:String = "Person(" + name.toUpperCase + ") and his pet " + pet.toLoudString
}
}
However, the above does not work ( Scala 2.9.1 ). The last expression fails to compile ( pet.toSimpleString ).
This is just a random strategy I picked out of several I tried: self typing, abstract types, super[...], etc.
I want to be able to do something like this, eventually:
val family = new Family with SerializableFamily with TraversableFamily with FooFamily {}
Where each mixin adds a set of cooperating methods to one or more types within the family.
This is a common pattern that I have seen solved by using implicit wrappers, pattern-matching based visitors, etc. But since it is just a recursive application of the regular mixin pattern I wonder if there might be a simpler way to achieve it.
The error in your case is expected, since Dog and Person in mixins don't override Dog and Person in Family, so that self.Person still refers to Family.Person.
This may be closer to what you want
trait Family {
// type DogType = Dog won't work because then two different mixins
// have incompatible DogType implementations
type DogType <: Dog
type PersonType <: Person
trait Dog {
def dogname:String
def owner:PersonType
}
trait Person {
def name:String
def pet:DogType
}
}
trait SerializableFamily extends Family {
type DogType <: Dog
type PersonType <: Person
trait Dog extends super.Dog {
def toSimpleString:String = "Dog(" + dogname + ")"
}
trait Person extends super.Person {
def toSimpleString:String = "Person(" + name + ") and his pet " + pet.toSimpleString
}
}
But then you have something yucky like
new Family with SerializableFamily with TraversableFamily with FooFamily {
type DogType = super[SerializableFamily].Dog with super[TraversableFamily].Dog with super[FooFamily].Dog
}
Suppose I have some abstract value field defined in a trait:
trait Base {
val toBeOverride: String
}
case class Impl(other:Int) extends Base {
override val toBeOverride = "some value"
}
How can I write a function that I can easily get a cloned instance only overriding the toBeOverride value, like this:
// copy only available to case class instance
// v does not have method 'copy'
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
?
Edit
#som-snytt, I don't think this is a duplicate, just like a Trait is not the same as an Abstract Class. And the answers of that question do not satisfy me, see below.
#Blaisorblade, yes, it is a problem. For instances of each sub case class, the toBeOverride field are the same, so it should not appear in the constructor.
For now all the suggestions are to define an customized copy method in each(!) sub case class and that in my opinion is ugly and shows the incapability of the language.
The simplest solution is to just add the method you want to Base:
trait Base {
val toBeOverride: String
def copyBase(newToBeOverridden: String): Base
}
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = newToBeOverridden)
}
This also allows to directly create an instance of Impl while specifying the value of toBeOverride (which wasn't possible). The only disadvantage is that now pattern matches using Impl have to change syntax - please update your question and add a comment if that's a problem.
BTW, if you just want to add a prefix (as in your example), that's no problem:
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = toBeOverride + newToBeOverridden)
}
Here are two mechanisms.
Apparently, in the near future you'll be able to write a macro that can emit the anonymous subclass, but until then, I think this typeclass is not arduous.
Just kicking the tires on Dynamic here.
import scala.language.dynamics
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
trait Base {
def m: String
}
case class Impl(p: Int) extends Base {
override val m = "some value"
}
trait Basic extends Dynamic {
protected def m: String
def selectDynamic(f: String): Any =
if ("m" == f) m else reflecting(this, f)
protected def reflecting(b: Basic, f: String) = {
val im = cm.reflect(b)
val member = im.symbol.typeSignature member newTermName(f)
require(member != NoSymbol, s"No such member $f")
(im reflectMethod member.asMethod)()
}
}
case class Implic(p: Int) extends Basic {
override protected val m = "some value"
}
object Test extends App {
implicit class Copy[A <: Base](val b: A) {
def overriding(overm: String): A = (b match {
case impl: Impl => new Impl(impl.p) { override val m = overm }
case b: Base => new Base { override val m = overm }
}).asInstanceOf[A]
}
implicit class Proxy[A <: Basic : ClassTag](val b: A) {
def proximately(overm: String): Basic = new Basic {
override val m = overm
override def selectDynamic(f: String): Any =
if ("m" == f) overm else reflecting(b, f)
override def toString = b.toString
}
}
// asked for this
//def overriding[T <: Base](v: Base) = v.copy(m = "prefix" + v.m)
/* want something like this
def overriding[T <: Base](v: Base) = new Impl(v.p) {
override val m = "some value"
} */
val a = Impl(5)
val b = a overriding "bee good"
Console println s"$a with ${a.m} ~> $b with ${b.m}"
// or
val c = Implic(7)
val d = c proximately "dynomite"
Console println s"$c with ${c.m} ~> $d with ${d.m}"
}
Since traits don't get copy methods automatically, you can try using a Base case class instead:
case class Base(toBeOverride: String)
case class Impl(other: Int, someVal: String = "some value") extends Base(someVal)
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
The problem that you're going to run into though, is that copy returns an instance of Base and I don't think that you can convert it back to your original Impl class. For instance, this won't compile:
def overrideBaseValue[T <: Base](v: T): T =
v.copy(toBeOverride = "prefix" + v.toBeOverride)