my question below is definately a nonsense but answering it will help me for another problem.
How force a trait to be mixed only by a specific class (or its subclass). I thought about use require() inside it :
abstract class Aclass(c_attribut1 : Int){
var attribut1 : Int = c_attribut1
def getAttribut1() : Int = this.attribut1
}
class Bclass extends Aclass(1) with Trait1{
}
class Cclass extends Aclass(2) with Trait1{
}
trait Trait1{
require(this.isInstanceOf[Aclass]);
def f() : Int = this.getAttribut1() * 2 // it obviously does not work
}
Then, I don't know how considere Trait1 as a Aclass (in order to avoid asInstanceOf every where). I know the function f should be in the Aclass but, as I said, I would like to know how properly force a trait to be mixed by a specific class and how to get messages of this class in the trait.
I wonder this because I need a trait is mixed by a specific class with template :
trait TraitBuiltHost extends Observable{
require(this.isInstanceOf[BuiltInfrastructure[_ <: TraitHostDefinition]]);
.
.
.
}
Thank you.
Self typing:
class MyClass1
class MyClass2
trait MyTrait {
self: MyClass1 =>
val i = 1
}
scala> new MyClass1 with MyTrait
res0: MyClass1 with MyTrait = $anon$1#3f0762f6
scala> new MyClass2 with MyTrait
<console>:1: error: illegal inheritance;
self-type MyClass2 with MyTrait does not conform to MyTrait's selftype MyTrait with MyClass1
new MyClass2 with MyTrait
^
See also Self references part of scala tag wiki.
Related
I recently discovered that Scala compiler has an interesting feature for case class: Since it generates both a class & an object signature, if defined as an inner class, it can be used to override an abstract type definition and a function definition of its super class with minimal boilerplate code, here is an example:
object InnerCaseClassOverridingBoth {
trait AALike
trait SS {
type AA <: AALike
def AA(): AnyRef
}
trait SS_Clear extends SS {
def AA(): AnyRef
}
class SSA extends SS_Clear {
case class AA() extends AALike
}
object SSA extends SSA {}
}
This will compile without any error. However the shortcut stops here, if the function definition def AA is parameterized, then neither the inner case class nor inner object is capable of overriding it: the apply function of the inner object doesn't automatically expand to a method of its outer class:
trait SS_Parameterised extends SS {
def AA(ii: Int): AnyRef
}
class SSB extends SS_Parameterised {
case class AA(ii: Int) extends AALike
}
object SSB extends SSB {}
This gives an error:
class SSB needs to be abstract, since method AA in trait
SS_Parameterised of type (ii: Int)AnyRef is not defined
class SSB extends SS_Parameterised {
My question is, is there a shortcut in this case? Why is the Scala compiler is designed to link case 1 but not case 2?
It's not particularly designed at all; or, it is, but not in the way you seem to think. You aren't overriding def AA() with a method that constructs AA, you are overriding it with the object AA itself. Notice
trait T {
type I <: AnyRef
def I(): AnyRef
}
object O extends T {
case class I(val i: Int)
}
This works fine.
> (O: T).I()
I
> (O: T).I().getClass
class O$I$
> O.I(5)
I(5)
> O.I(5).getClass
class O$I
The salient design choices are "objects can override no-param defs" (and so can vals, vars and, of course, no-param defs) and "case classes automatically generate objects". "Inner case classes override methods of the same name in their outer class with their constructors," is not one of Scala's rules. object O contains a case class I and an object I, and the abstract def I(): AnyRef is overridden to return said object I. The contents of object I don't matter, because def I() only has to return an AnyRef, which means no restrictions are imposed. It makes perfect sense that
trait U {
type I <: AnyRef
def I(i: Int): AnyRef
}
object P extends U {
case class I(i: Int)
}
fails, then. object P contains a case class I and an associated object I, but it also needs a def I(i: Int): AnyRef, which it lacks.
I am guessing it is simply related to the role apply plays in case classes. See Case Class default apply method
SSA satisfies SS_Clear.AA via companion object of SSA (SSA.apply).
When you add a parameter to the method you no longer have the 0-parameter apply method to fulfill that role.
OK I found 2 ways of doing this
Method 1: overriden by case class:
trait SS_Parameterised {
type AA <: AALike
def AA: Int => AnyRef
}
Method 2: overriden by implicit class:
trait SS_Parameterised {
type AA <: AALike
implicit def AA(ii: Int): AnyRef
}
class SSB extends SS_Parameterised {
implicit class AA(ii: Int) extends AALike
}
End of story :) One case class overriding 2 declarations? No problem.
(Method 2 works as scala internally generates an implicit function for every implicit class)
If I have 1 trait and 2 objects:
trait MyClass {
type T <: MyClass
def foo(): ClassTag[T] = {...}
}
object ChildClass1 extends MyClass {
type T = String
}
object ChildClass2 extends MyClass {
type T = Option[String]
}
is it possible to implement foo() in MyClass, such that ChildClass1.foo() yields ClassTag[String], and ChildClass2.foo() yields ClassTag[Option].
If not, what's the easiest way to bypass it? It should be noted that the implementation of T may be inner classes/objects, so hacking reflection may have some side effects.
Ok, it's possible that I don't completely understand your goal, but from what I can see, you are trying to create a trait with an upper bound type, and you also want to be able to get the type at runtime, correct?
So let's assume you have a Foo trait:
class MyClass // not important
trait Foo[T <: MyClass] {
def foo: ClassTag[T]
}
If you want an object implementation, the solution is trivial, since you know the type at compile time:
class MyClassSubclass extends MyClass // also not important
object FooObject extends Foo[MyClassSubclass] {
def foo: ClassTag[MyClassSubclass] = ClassTag(classOf[MyClassSubclass])
}
But if you want a class, then you can solve the problem with the implicitly + context bound combo in a pretty readable way:
class FooImpl[T <: MyClass : ClassTag] extends Foo[T] {
def foo: ClassTag[T] = implicitly[ClassTag[T]]
}
I would like to propose a dirty and impaired answer, please advice me if you have any better idea:
lazy val mf: ClassTag[T] = {
val clazz = this.getClass
val name = clazz.getName
val modifiedName = name + "T"
val reprClazz = Utils.classForName(modifiedName)
Manifest.classType(reprClazz)
}
it only works if the subclass is a singleton object.
Assuming I have a simple abstract base class like so:
abstract class MyAbstractBaseClass {
def hello : Unit
}
and then I write a "stacking" trait like so:
trait MyTrait extends MyAbstractBaseClass {
abstract override def hello : Unit =
{
super.hello
println("How are you?");
}
}
then why won't Scala let me define a subclass as follows:
class MyClass extends MyAbstractBaseClass with MyTrait {
override def hello : Unit = println("Hello!")
}
error: overriding method hello in trait MyTrait of type => Unit;
method hello needs `abstract override' modifiers
If I try their suggestion of using 'abstract override':
class MyClass extends MyAbstractBaseClass with MyTrait {
abstract override def hello : Unit = println("Hello!")
}
error: `abstract override' modifier only allowed for members of traits
Can anyone help me understand this?
P.S. I know that the below does work:
class MyClass extends MyAbstractBaseClass {
override def hello : Unit = println("Hello!")
}
val x = new MyClass with MyTrait
x.hello
Hello!
How are you?
but am trying to understand why the former does not.
In summary: why can't I provide an implementation of the abstract base class - while also taking advantage of the trait's functionality?
The trick is that you can't have an "abstract" method in the flow of the linearization, that is called from a super call.
Try this, you will see it compiles:
abstract class MyAbstractBaseClass {
def hello : Unit
}
class SubClass extends MyAbstractBaseClass {
def hello {
println("toto")
}
}
trait MyTrait extends MyAbstractBaseClass {
abstract override def hello : Unit =
{
super.hello
println("How are you?")
}
}
class MyClass extends SubClass with MyTrait { //note the CONCRETE SubClass here
override def hello : Unit = println("Hello!")
}
new MyClass().hello
You got the error, because the compiler starts with MyTrait (at the top of the stack, so the first to be called) and that MyTrait calls through super an abstract method... (of MyAbstractBaseClass) => it crashes since your super call can't target immediately a concrete method.
In my code snippet, you will notice that MyTrait is "at the top" (during linearization) of a concrete Subclass class, that makes the trick.
I have a program that in part deals with a type hierarchy. All I'm trying to achieve here is to have the 'oldType' def make use of the covariant return type feature I'm accustomed from Java.
trait NumericMember extends NumericTypedef{ }
trait Type
trait NumericType extends Type
trait Typedef { def oldType : Type }
class TypedefImpl extends Typedef {
//can't use a val since it will get overriden
def oldType : Type = ???
}
trait NumericTypedef extends Typedef with NumericType {
abstract override def oldType : NumericType = super.oldType.asInstanceOf[NumericType]
}
class NumericTypedefImpl extends TypedefImpl with NumericTypedef{ }
class NumericMemberImpl extends NumericMember {
private val autoType = new NumericTypedefImpl
override def oldType: NumericType = autoType.oldType
}
The compiler blindly tells me that oldType in NumericMemberImpl needs to be an abstract override and then changes its mind when I obey it, figuring out NumericMemberImpl is actually a class.
I might be on a wrong avenue here, since I realize abstract override is used for the stacking traits. When I all I want is to have to have general and specialized return values for oldType.
Help, anyone?
I've skipped all classess thing here, but the idea is:
trait Type
trait NumericType extends Type
trait Typedef { def oldType : Type }
class NumericMember extends Typedef {
def oldType: NumericType = new NumericType{}
}
The return type is already covariant in both scala and java. You don't need any explicit type-conversion.
About this one:
trait NumericTypedef extends Typedef with NumericType {
override def oldType : NumericType = super.oldType.asInstanceOf[NumericType]
}
There is nothing to override, as neither Typedef nor NumericType has concrete implementation of oldType. There is also no super-class (which is the reason of abstract override recomendation) with implemented method. Abstract override is used to access super's method which is not implemented yet (but will be in the concrete class). You don't need it much as you don't need to call super to get the right type.
To implement some custom type provider:
abstract class NumericMember extends Typedef
trait MyNumericTypeProvider extends Typedef {
def oldType = new NumericType{}
}
trait MyNumericTypeProvider2 extends Typedef {
def oldType = new NumericType{}
}
scala> new NumericMember with MyNumericTypeProvider
res0: NumericMember with MyNumericTypeProvider = $anon$1#19a26a1
scala> new NumericMember with MyNumericTypeProvider2
res1: NumericMember with MyNumericTypeProvider2 = $anon$1#16bdcbe5
scala> res0.oldType
res2: NumericType = MyNumericTypeProvider$$anon$1#2be1fa9c
Look at res2: NumericType - scala's type inference automatically found the right type with respect to covariance.
I have a super class:
class P(name:String)
And a helper trait:
trait SysConfig {
def prop(key:String) = System.getProperty(key)
}
Then I want to define an object which extends P:
object C extends P(prop("user.name")
It's not compiled, because it can't find the prop method. So I with the SysConfig:
object C extends P(prop("user.name") with SysConfig
Unfortunately, it still can't be compiled
Is there any way to make it work?
The arg is evaluated in a context outside the current definition, so no.
You have to put the computation in another object.
If you were thinking this, the answer also turns out to be no:
scala> class P(name: String)
defined class P
scala> trait Prop { def prop(k: String) = sys.props(k) }
defined trait Prop
scala> class C(p: String = C.prop("user.name")) extends P(p); object C extends C() with Prop
<console>:9: error: module extending its companion class cannot use default constructor arguments
class C(p: String = C.prop("user.name")) extends P(p); object C extends C() with Prop
^
That's because default args are methods defined by the companion.
Similarly,
scala> class C(p: String) extends P(p); object C extends C(C.prop("user.name")) with Prop
<console>:9: error: super constructor cannot be passed a self reference unless parameter is declared by-name
class C(p: String) extends P(p); object C extends C(C.prop("user.name")) with Prop
^
If I dont misunderstand this :), I think there are 2 things are impossible here.
trait composition or stackable trait is always make right trait wins. In this example, it tries to use left one override the right one.
when we use trait composition, trait structure would not change. The only flexible thing we can do is the sub-trait polymorphism. Cake pattern is using this way, but linearization is a problem. However, it is not related to this.
I think the correct way to do this, is to create a class/trait to do the override thing
class P(name:String)
trait SysConfig {
def prop(key:String) = System.getProperty(key)
}
class C extends P("123") with SysConfig {
override def prop(key: String) = "123"
}
trait Foo extends P with SysConfig {
override def prop(key: String) = "123"
}
new C