I discovered that using abstract types affects the scala compiler ability to detect overrides and it interprets seemingly correct code as erroneous.
trait I {
type T
def doThings(t : T) : Unit
}
type IT[X] = I { type T = X}
trait A extends I {
override type T = AnyRef
def doThings(t : T) : Unit = println("A")
}
trait Z[X] extends I { this : IT[X] =>
abstract override def doThings(t : T) : Unit = {
println("Z")
super.doThings(t)
}
}
object Use {
val az = new A with Z[AnyRef] {}
}
The scala compiler fires such error:
OverloadAbstract.scala:44: error: object creation impossible, since method doThings in trait Z of type (t: this.T)Unit is marked `abstract' and `override', but no concrete implementation could be found in a base class
val az = new A with Z[AnyRef] {}
What is the proper way to express such relations between trait mixing and implementation?
For the comparison that code works fine:
trait I {
def doThings() : Unit
}
class A extends I {
def doThings() : Unit = println("A")
}
trait Z extends I {
abstract override def doThings() : Unit = {
println("Z")
super.doThings()
}
}
object Use {
val az = new A with Z {}
}
The real use case is to implement a forwarder for the akka.event.EventBus:
object PartialEventBus {
type ApplyEvent[E] = EventBus { type Event = E }
}
trait ForwardEventBus[E] extends EventBus { this : PartialEventBus.ApplyEvent[E] =>
def relay : PartialEventBus.ApplyEvent[E]
abstract override def publish(event : Event) : Unit = {
relay.publish(event)
super.publish(event)
}
}
Type parametrization for the ForwardEventBus is needed for compiler to match object-wide this.Event type with external relay.Event type. Compiler would fail without such hint because of scala's path-dependent types restrictions.
Perhaps I'm confused, shouldn't the question be "Why does abstract override succeed?" Section 5.2.4 of the spec covers abstract override, and it says, "The override modifier has an additional significance when combined with the abstract modifier. That modifier combination is only allowed for value members of traits."
I hope a language lawyer can weigh in, but it looks like this should not be legal.
Related
I am new to scala and thus my question might be due to a lack of understanding of abtract types and traits.
I currently have a Sensor trait which is generic and defines a value and newValue method.
trait Sensor[T] {
def value: T
def newValue(): Unit = {}
}
One concrete implementation of Sensor is MemorySensor, which just uses a variable to store the value and has a set value method which sets the value and fires the newValue method.
class MemorySensor[T] extends Sensor[T] {
var internalValue: T = null.asInstanceOf[T]
def setValue(newVal: T): Unit = {
internalValue = newVal
newValue()
}
def value: T = internalValue
}
There is also an AbstractSO (SO = subject + Observer) class which uses abstract types to implement Subject/Observer pairs.
class AbstractSO {
type O <: AbstractObserver
type S <: AbstractSubject
trait AbstractSubject {
this: S =>
def register(observer: O) = {
//we could use mutable collection here too
observers = observer :: observers
}
var observers: List[O] = List[O]()
def notifyObservers() = {
observers.foreach(o => o.notifyObserver(this))
}
}
trait AbstractObserver {
def notifyObserver(subject: S)
}
}
One example of a concrete Subject/Observer is the ActionSO
object ActionSO extends AbstractSO {
type S = ActionSubject
type O = ActionObserver
trait ActionSubject extends AbstractSubject {
def action() = {
notifyObservers()
}
}
trait ActionObserver extends AbstractObserver {
override def notifyObserver(actionSubject: ActionSubject) = {
println("action observer called")
}
}
}
Now I want to implement a concrete Subject/Observer-Pair for Sensors with the requirement that the SensorSubject should be a mixin trait for sensors.
So I guess the target would be to use the SensorSubject like this:
val x = new MemorySensor[Int] with SensorSubject[Int]
However whatever I try to implement the SensorSO, I always get either some kind of "illegal inheritance" error or "self-type does not conform to..".
As far as I know this cannot be done without creating an extra class that extends from AbstractSO, but uses generic types. (but I don´t know how this helps me to achieve my target anyways)
It would be very nice if someone could help me out!
EDIT:
As SergGr wanted to see my SensorSubject (which is what I don´t know how to implement, I will post one of my various tries)
Note however that this does NOT COMPILE
object SensorSO extends AbstractSensorSO {
//TODO: i shouldn´t use "Any" here - this won´t work
override type S = SensorSubject[Any]
trait SensorSubject[T] extends AbstractSensorSubject with Sensor[T] {
this: S => //this generates problems as well
}
}
Here is my AbstractSensorSO
class AbstractSensorSO extends AbstractSO {
type S <: AbstractSensorSubject
type O <: AbstractSensorObserver
trait AbstractSensorSubject extends AbstractSubject {
this: S =>
}
trait AbstractSensorObserver extends AbstractObserver {
}
}
As you can see the AbstractSensorSO basically doesn´t do anything, I just added it because it was mentioned in a hint to the solution that one needs an subclass of AbstractSO, before creating the concrete SensorSO object.
One problem I am facing is that the Sensor trait is generic so for the SensorSubject to use the Sensor trait AFAIK i have to make the SensorSubject generic too.
Normally this wouldn´t be a problem, but as i use abstract types I would have to define the "S" type in the SensorSO with generics too (e.g.
type S = SensorSubject[T]
But as the generic type "T" is not known in that context it obviously gives an error (as the generic "T" is only available the context of the generic trait SensorSubject)
If I try to drop the generic paramater when defining the type S, I also get an error message that the generic type parameter is missing.
And just writing
type S = SensorSubject[Any]
doesn´t solve the problem either
EDIT2:
To clarify what my target is:
SensorSubject should be an Mixin Trait, such that i can use normal Sensors(not only MemorySensors) and that if I want I can add "with SensorSubject[Int]" to the creation of the Sensor and then it functions as a SensorSubject
Which means i can register an observer and the observer is notified when i change the value of the Sensors(that now functions as SensorSubject)
Here is an example how I would like to use the SensorSubject[T] Trait:
//creating a sensor WITH the SensorSubject Trait
val sensorWithSubject= new MemorySensor[Int] with SensorSubject[Int]
sensorWithSubject.registerObserver(..)
//creating a normal Sensor WITHOUT SensorSubject
val normalMemSensor = new MemorySensor[Int]
You didn't provide any example of expected usage so my guess might be wrong. Still here is my attempt:
trait Sensor[T] {
def value: T
def newValue(): Unit = {}
}
class MemorySensor[T] extends Sensor[T] {
var internalValue: T = null.asInstanceOf[T]
def setValue(newVal: T): Unit = {
internalValue = newVal
newValue()
}
def value: T = internalValue
}
//////////////////////////////////
trait AbstractSubject[S <: AbstractSubject[S, O], O <: AbstractObserver[S, O]] {
this: S =>
def register(observer: O) = {
//we could use mutable collection here too
observers = observer :: observers
}
private var observers: List[O] = List[O]()
def notifyObservers() = {
observers.foreach(o => o.notifyObserver(this))
}
}
trait AbstractObserver[S <: AbstractSubject[S, O], O <: AbstractObserver[S, O]] {
def notifyObserver(subject: S)
}
//////////////////////////////////
trait SensorSubject[T, S <: SensorSubject[T, S, O], O <: SensorObserver[T, S, O]] extends Sensor[T] with AbstractSubject[S, O] {
this: S =>
}
trait SensorObserver[T, S <: SensorSubject[T, S, O], O <: SensorObserver[T, S, O]] extends AbstractObserver[S, O]
//////////////////////////////////
class MemorySensorSubject[T] extends MemorySensor[T] with AbstractSubject[MemorySensorSubject[T], MemorySensorObserver[T]] {
override def setValue(newVal: T): Unit = {
super.setValue(newVal)
notifyObservers()
}
}
trait MemorySensorObserver[T] extends AbstractObserver[MemorySensorSubject[T], MemorySensorObserver[T]]
and with that you can do
def test(): Unit = {
val sensor = new MemorySensorSubject[Int]
val observer = new MemorySensorObserver[Int] {
override def notifyObserver(subject: MemorySensorSubject[Int]): Unit = {
println(s"New value of $subject is ${subject.value}")
}
}
sensor.register(observer)
sensor.setValue(42)
}
and the output will be
New value of so.Main$MemorySensorSubject#363ee3a2 is 42
Probably the most important thing here is that MemorySensorSubject is an explicitly named type that thus can be used as S in F-bound generic constraint
I am using several classes like this:
class MyClassOne {
doSomething(a : A) : B
...
}
class MyClassTwo {
doSomething(a : A) : B
...
}
The source for the classes is not under my control. Although the classes have methods with the same signature they don't implement an interface. I would like to define methods that work on all the classes.
So I've made a Trait like this:
trait MyTrait {
doSomething(a : A) : B
}
And have made implicit conversions for all the classes:
implicit class MyClassOneMyTrait(myClassOne : MyClassOne) {
def doSomething(a : A) = myClassOne.doSomething(a)
}
Is there a way to take advantage of the naming conventions used in the classes and avoid explicitly delegating to the objects passed into the constructor? More generally, is using a Trait with implicit classes the best approach to this problem?
Actually, there is scala feature exactly for your situation. It's called structural types.
For structural types type requirements are expressed by interface structure instead of a concrete type. Internal implementation uses reflection, so be performance-aware!
type A = String
type B = String
class MyClassOne {
def doSomething(a: A): B = {
println("1")
"1"
}
}
class MyClassTwo {
def doSomething(a: A): B = {
println("2")
"2"
}
}
type MyClassType = {
def doSomething(a: A): B
}
List[MyClassType](new MyClassOne, new MyClassTwo).foreach(_.doSomething("test"))
List(new MyClassOne, new MyClassTwo).foreach {
case a: MyClassType => a.doSomething("test")
case _ =>
}
I have a library where an abstract class Base[T] is over a type T supplied by the user. There are many specific Base[T] sub-classes, some are over types T and S, like Specific[T, S], but this is irrelevant. The user might specify any T of course while creating and instance, but I want to treat it as T with a trait AdditionalAbilities or in other words I want to 'gift' the user's type with AdditionalAbilities. How can I do that in Scala? I hope the title is correct for this question.
Example (might not be syntactically correct)
class Specific[T **with trait Additional**]() extends Base[T](){
def doSomething() : T = {
val something = new T()
something.ability(2)
println(something.additional)
something
}
}
trait Additional{
var additional : Integer
def ability(i : Integer) : Unit = {
additional = i
}
}
Would work with any T.
When you define a parametric class you can require the parameter type to descend from a certain type:
trait AdditionalAbilities {
def doStuff(): Unit = println("Hey There")
}
object NoAbility extends AdditionalAbilities {
override def doStuff(): Unit = ()
}
abstract class Base[T] { ... }
class Specific[T <: AdditionalAbilities] extends Base[T] {
def f(t: T): Unit = t.doStuff()
}
Then when you try to instantiate a Specific type:
scala> new Specific[Int] {}
<console>:13: error: type arguments [Int] do not conform to class Specific's type parameter bounds [T <: AdditionalAbilities]
scala> val b = new Specific[NoAbility.type] {}
b: Specific[NoAbility.type] = $anon$1#517cd4b
scala> b.f(NoAbility)
//did nothing
Also, if you want to add a behaviour to an existing concrete class, you can do so at the time of instantiation:
trait CoolAbilities { def doStuff(): Unit = println("Hey there") }
class A { }
scala> val a = new A with CoolAbilities
a: A with CoolAbilities = $anon$1#6ad3381f
scala> a.doStuff()
Hey there
Perhaps implicit classes could help? Implicit classes allow you to add functionality to an existing type without needing to modify the existing type, or be the one instantiating it (so that you could mix in a trait).
The following compiles, and prints: 3
class Specific[T] {
implicit class TAdditional(t: T) {
var additional: Integer = 0
def ability(i: Integer) = {
additional = i
}
}
def doSomething(t: T) = {
doSomethingAdditional(t)
}
private def doSomethingAdditional(t: TAdditional) = {
t.ability(3)
println(t.additional)
}
}
val s = new Specific[Int]
s.doSomething(5)
Note: We need to do something to make sure we are accessing the same instance
of TAdditional, that's why I made the private doSomethingAdditional method that takes a TAdditional as an argument. If we call ability and additional in 'doSomething', separate instances of TAdditional would be created when we try to access #ability and #additional, and '0' would be printed.
I have 3 classes:
class AClass
class Base { val a = "a" }
class BaseOne extends Base { val b = "b" }
class BaseTwo extends Base { val c = "c" }
I want to extend a trait which contains a generic method, I'm not allowed to change the trait
trait Converter {
def toAClass[T <: Base](e: T): AClass
def fromAClass[T <: Base](s: AClass): T
}
I want to extend it in several different objects
object ConverterBaseOne extends Converter {
// ERROR
override def toAClass(e: BaseOne) : AClass = { printf(e.b) } // b is known
override def fromAlcass(a: AClass) : BaseTwo = {....}
}
I know there is a way to do it with class parameter: trait Converter[T <: Base]
and also saw this post https://stackoverflow.com/a/4627144/980275
I'm asking if there is a solution without changing the trait ???
Thank you
You are changing the signature of the method, so it is not a legal override, it would break polymorphism. You must either parametrize the Converter trait or use another method name.
You can, however, receive a Base object and cast it, but it is not recommended practice since it may result in an exception at runtime:
object ConverterBaseOne extends Converter {
override def toAClass[T <: Base](e: T): AClass = {
printf(e.asInstanceOf[BaseOne].b)
// ...
}
}
The access on Manifest seems to be tricky from a trait in scala.
How could this code compile in scala ?
trait SomeTraitOf[+A] {
def newInstanceOfA : A = /* necessary code to make it work */
}
(Related, it works fine as a parametized class :
class SomeTraitOf[A : Manifest] {
def newInstanceOfA(implicit m : Manifest[A]) : A =
m.erasure.newInstance.asInstanceOf[A]
}
but not with a covariant type parameter (+A))
Edit : The real stuff
sealed trait RootPeerProxy[+A] extends Proxy {
def peer: A
def self = peer
def peerManifest[B >: A](): Option[Manifest[B]]
private[scalavaadin] def newInstance() : Option[A]
}
trait PeerProxy[+A] extends RootPeerProxy[A] {
override def peerManifest[B >: A](): Option[Manifest[B]]
override def peer(): A = this.newInstance match {
case None => {throw new IllegalStateException("oups")}
case Some(a) => a
}
private[scalavaadin] override def newInstance() : Option[A] = peerManifest map { m => m.erasure.newInstance.asInstanceOf[A] }
}
Since traits cannot provide manifest for the parametized trait, the class implementing the trait should, but I am not getting it.
About covariance:
Since Manifest[A] is invariant in the parameter A, you can't do what you want directly. The usual strategy is to weaken the return type,
trait SomeTraitOf[+A] {
def newInstance[B >: A](implicit m: Manifest[B]): B = {
m.erasure.newInstance.asInstanceOf[B]
}
}
You can use the trait as follows,
class Parent
class Child extends Parent
val childBuilder = new SomeTraitOf[Child] {}
val parentBuilder: SomeTraitOf[Parent] = childBuilder
parentBuilder.newInstance // returns a Parent!
About View Bounds:
From your comment below, I guess you're also asking about "view bounds", which are just a concise way of declaring an implicit parameter. Your declaration
class SomeTraitOf[A : Manifest] { ...
basically translates to
class SomeTraitOf[A]()(implicit m0: Manifest[A]) { ....
Traits can't have view bounds because they can't take any (value) parameters. But that's not really a problem here, because in your example
class SomeTraitOf[A : Manifest] {
def newInstanceOfA(implicit m : Manifest[A]) : A =
m.erasure.newInstance.asInstanceOf[A]
}
you're not using the view bound! (You're using the parameter m instead.) If you wanted to use the view bound, you could do it this way:
class SomeTraitOf[A : Manifest] {
def newInstanceOfA : A =
implicitly[Manifest[A]].erasure.newInstance.asInstanceOf[A]
}