I have the following class hierarchy:
abstract class Event(val timeStamp:Long,val id:Long )
case class StudentEvent(override val timeStamp:Long, override val id:Long,
firstName:String,lastName:String) extends Event(timeStamp,id )
case class TeacherEvent(override val timeStamp:Long, override val id:Long,
firstName:String,lastName:String.....) extends Event(timeStamp,id)
Now I have the following trait:
trait Action[T <: Event] {
def act[T](event:T)
}
Now I would like to extend this trait for students and teachers:
trait StudentAction extends Action[StudentEvent]{
def act(event:StudentEvent) = println(event)
}
trait TeacherAction extends Action[TeacherEvent]{
def act(event:TeacherEvent) = println(event)
}
Now I would like to to create Handler class which take cars for all type of events:
class Handler{
self:Action[Event] =>
def handle(event:Event) = act(event)
}
Now when I try to create Handler for some type of Event, I'm getting compilation error:
val studentHandler = new Handler with StudentAction
illegal inheritance; self-type Handler with StudentAction does not conform to Handler's selftype Handler
with Action[Event]
What am I missing?
Handler type had to be parametrized too:
scala> class Handler[T<:Event] {
| self:Action[T] =>
| def handle(event:T) = act(event)
| }
defined class Handler
#Ashalynd is correct. up voted.
also to extract the inherit logic into a purer code looks like this:
class PARENT
class CHILD extends PARENT
trait A[T <: PARENT]
trait AA extends A[CHILD]
class B[T <: PARENT] {
self: A[T] =>
}
val b = new B[CHILD]() with AA
Related
I have this class defined as follows:
abstract class MyHelper[T, E <: BaseHelper[T]](implicit clsTag: ClassTag[E]) {
val all: Array[E]
def parse(t: T): Try[E] = { ... }
}
and this is how I am using it:
trait IntHelper extends BaseHelper[Int] {}
object MyIntHelper extends MyHelper[Int, IntHelper] { }
How do I simplify MyHelper class definition to accept only the inner generic type T instead of passing two types, E and T?
There's no need for you to directly enforce T in MyHelper since you're only using E itself.
So something like this should be fine.
abstract class MyHelper[E <: BaseHelper[_]](implicit clsTag: ClassTag[E]) {
val all: Array[E]
}
A more fleshed out example looks like:
trait BaseHelper[T] {}
trait IntHelper extends BaseHelper[Int]
abstract class MyHelper[E <: BaseHelper[_]](implicit clsTag: ClassTag[E]) {
val all: Array[E]
}
object MyIntHelper extends MyHelper[IntHelper] {
override val all = Array(new IntHelper{}, new IntHelper{})
}
// just to ensure it works
MyIntHelper.all
I would like ask for some help for advanced scala developers. My problem is that I would like to access a type alias belonging to a type parameters of a class' parent.
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait Module[M, D] {
type Dispatcher = D
type Model = M
}
trait MySpecificModule[A <: Module[_, _]] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module[MyModel, MyDispatcher] {
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
So basically MySpecificModule extends a generic trait, and should know the type of the dispatcher method. In this case of MySpecificModuleClass it should be MyDispatcher. But when I try to compile this code I am getting compilation error because the type of the method, is not the same as defined: A#Dispatcher, however in the reality it is.
Error:(21, 18) overriding method dispatcher in trait MySpecificModule of type ()_$2;
method dispatcher has incompatible type
override def dispatcher(): MyDispatcher = MyDispatcher()
^
I would appreciate any advice you suggest. Thanks in advance,
Gabor
Resolved
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait AbstractModule {
type Dispatcher
type Model
}
trait Module[M, D] extends AbstractModule {
type Dispatcher = D
type Model = M
}
trait MySpecificModule[A <: AbstractModule] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module[MyModel, MyDispatcher] {
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
I don't fully understand Scala's reasoning here, but if you get rid of type parameters, things start to work:
case class MyModel(foo: String = "bar")
case class MyDispatcher()
trait Module {
type Dispatcher
type Model
}
trait MySpecificModule[A <: Module] {
def dispatcher(): A#Dispatcher
}
class ModuleClass extends Module {
type Model = MyModel
type Dispatcher = MyDispatcher
//...
}
class MySpecificModuleClass extends MySpecificModule[ModuleClass] {
override def dispatcher(): MyDispatcher = MyDispatcher()
}
And if you really want to have those type params, you can introduce a helper trait:
trait AbstractModule[M, D] extends Module {
type Model = M
type Dispatcher = D
}
class ModuleClass extends AbstractModule[MyModel,MyDispatcher]
I have the following problem: I would like to have an 'instance' (parameterized trait) and 'configuration', and the latter is parameterized by the instance type:
trait Kind
trait Kind1 extends Kind
trait Kind2 extends Kind
trait Instance[T <: Kind] {
def configuration: InstanceConfiguration[Instance[_]]
}
trait InstanceConfiguration[+T <: Instance[_]] {
}
class AInstance extends Instance[Kind1] {
override def configuration: AConfiguration = ???
}
class AConfiguration extends InstanceConfiguration[AInstance] {
}
class BInstance extends Instance[Kind1] {
override def configuration: AConfiguration = ???
}
So, the issue is that InstanceConfiguration[Instance[Kind2]] cannot be used as a configuration for Instance[Kind1], but now it is too generic, and I'd like compiler to give out error on BInstance.configuration.
So how do I change definition of configuration in the Instance trait to reference the concrete InstanceConfiguration of the concrete type?
You need to use F-Bounded polymophism. I recommend reading the section in Twitter's Scala School, but in brief, Instance needs to take the concrete type as a type parameter:
trait Kind
trait Kind1 extends Kind
trait Kind2 extends Kind
trait Instance[A <: Instance[A, T], T <: Kind] {
self: A =>
def configuration: InstanceConfiguration[A]
}
trait InstanceConfiguration[+T <: Instance[_, _]] {
}
class AInstance extends Instance[AInstance, Kind1] {
override def configuration: AConfiguration = ???
}
class AConfiguration extends InstanceConfiguration[AInstance] {
}
class BInstance extends Instance[BInstance, Kind1] {
override def configuration: AConfiguration = ???
}
say, I have a generic command trait with an execute method that takes an Input and returns an Output. Something like
trait Input;
trait Output;
trait Command[I <: Input, O <: Output] {
def execute(input: I): O;
}
Then, I am going to create various Commands, something like
class SampleInput extends Input
class SampleOutput extends Output
class SampleCommand extends Command[SampleInput, SampleOutput] {
def execute(input:SampleInput):SampleOutput = new SampleOutput()
}
The problem with this is I could create a Command with a SampleAInput and SampleBOutput and the compiler will accept that happily. How do I enforce that so the compiler fails with type mismatch error ?
Somehow, I need to group Input and Output under a type and pass that type to create a
command. How do I do that?
trait InputOutput {
type Input
type Output
}
trait Command[IO <: InputOutput] {
def execute(input: IO#Input): IO#Output
}
Here's some usage:
scala> trait SampleIO extends InputOutput {type Input = String; type Output = String}
defined trait SampleIO
scala> class SampleCommand extends Command[SampleIO] {def execute(input: String) = input}
defined class SampleCommand
scala> class SampleCommand extends Command[SampleIO] {def execute(input: String) = 1}
<console>:13: error: type mismatch;
found : Int(1)
required: SampleIO#Output
class SampleCommand extends Command[SampleIO] {def execute(input: String) = 1}
^
Since your constraint is that the type of Input and Output be the same, I would try the following:
trait Input[T]
trait Output[T]
trait Command[T] {
def execute[I <: Input[T], O <: Output[T]](i: I): O
}
Let's try this with two different types.
class SampleInput extends Input[String]
class SampleOutput extends Output[Int]
scala> class SampleCommand extends Command[String] {
| def execute(input: SampleInput): SampleOutput = new SampleOutput
| }
:10: error: class SampleCommand needs to be abstract, since method execute in trait Command of type [I <: Input[String],O <: Output[String]](i: I)O is not defined
class SampleCommand extends Command[String] {
^
I'm a little bit late, but how about this:
object inout {
trait ~>[I, O]
trait FooInput
trait FooOutput
trait BarOutput
//this specifies a valid input-output combination
implicit object fooInOut extends ~>[FooInput,FooOutput]
class Command[I, O](implicit val valid: I ~> O) {
def execute(input: I): O;
}
class FooCommand extends Command[FooInput, FooOutput]
//won't compile:
//class FubarCommand extends Command[FooInput, BarOutput]
}
I would like to have a sealed trait which have a declared method that returns the
actual class that extends the trait. Should I use an abstract type, a parameter type or
is there any other nice way to solve this?
sealed trait Foo {
type T
def doit(other: T): T
}
or
sealed trait Foo[T] {
def doit(other: T): T
}
Note that T must be a subtype of Foo in this example. If I do it like this the type
information feels too repeated:
case class Bar(name: String) extends Foo[Bar] {
def doit(other: Bar): Bar = ...
}
They are mostly interchangeable. According to Odersky, the reason was mainly for completeness: That similarly to the fact that methods and fields (values) can be either abstract or passed as parameters, so can types.
It is better to use an abstract type when you intend to mix several traits that all use the same type name. With type parameters you need to explicitly pass the type to each
Here's an article explaining all of this: http://www.artima.com/weblogs/viewpost.jsp?thread=270195
You can cut down on the repetition somewhat by having your doit method return a factory function:
trait Foo[T] {
self: T =>
def doit: T => T
}
case class Bar(name: String) extends Foo[Bar] {
// note: types omitted
def doit = { other => Bar(name + other.name) }
}
It's not possible to do the same with an abstract type:
trait Foo {
self: T => // won't compile because T isn't defined yet
type T
def doit: T => T
}
You can write:
trait Foo[T] {
self:T =>
def doit(other: T): T
}
case class Bar(name: String) extends Foo[Bar] {
def doit(other: Bar): Bar = ...
}
The difference to your example is that Bar can't be instantiated in any other way (e.g. case class Bar(name: String) extends Foo[String]).
trait Foo[A <: Foo[A]]
This trait can only be mixed in if A is a subtype of Foo[A] and the only type satisfying that is the class Foo is being mixed into. I saw this solution in the Mapper traits in Lift.
EDIT - Below is my original answer. Your comment indicates that you wish to return an arbitrary instance of a matching type but I don't really believe that this is in any way sensible. Suppose it were, via the T.type syntax:
trait T { def foo : T.type }
trait U extends T { def foo = new U } //must be a U
class W extends U
val w : W = (new W).foo //oh dear.
This is accomplishable via this.type:
scala> trait T {
| def foo : this.type
| }
defined trait T
scala> class W extends T {
| def foo = this
| }
defined class W
scala> (new W).foo
res0: W = W#22652552
scala> res0.foo
res1: res0.type = W#22652552
And then also:
scala> ((new W) : T)
res4: T = W#45ea414e
scala> res4.foo.foo.foo
res5: res4.type = W#45ea414e