Generic traits with companion object - scala

I am using scala 2.10. I am still (very) new to scala and I am not able to understand why I cant access name field of Person case class inside the print method of trait Printer[T].
This is the sample code:
it prints out
Person(Mark)
Person(Will)
// Model
abstract class BaseModel[T] {
def all: List[T]
}
case class Person(name: String)
object Person extends BaseModel[Person] {
val people = Set(Person("Mark"), Person("Will"))
def all = people.toList.sortBy(_.name)
}
// Controller
trait Printer[T] {
val model: BaseModel[T]
def print = model.all.foreach { p =>
// p.name gives error "value name is not a member of type parameter T"
println(p)
}
}
object PersonPrinter extends Printer[Person] {
val model = Person
}
// Call
object MyApp extends App {
PersonPrinter.print
}

If you put no constraints to T, that is, say some requirements about it, you cannot 'know' that you can call any specific method (except toString, hashCode, equals and some more methods that exists on all objects).
One way you could do that is by not using a generic like you do at all, but instead be specific:
trait Printable {
def text: String
}
trait Printer {
def model: BaseModel[Printable]
def print = model.all.foreach(p => println(p.text))
}
Or you could use a type bound for your T that expresses a requirement for what T is allowed to be:
trait Printer[T <: Printable] {
def model: BaseModel[T]
def print = model.all.foreach(p => println(p.text))
}
This way you can only create implementations of Printer where the concrete type you put in implements the Printable trait.

I guess this would compile:
trait Printer[T<:Person] {
val model: BaseModel[T]
def print = model.all.foreach { p =>
// p.name gives error "value name is not a member of type parameter T"
println(p.name)
}
}
or using structural typing:
trait Printer[T<: {val name:String}] {
val model: BaseModel[T]
def print = model.all.foreach { p =>
// p.name gives error "value name is not a member of type parameter T"
println(p.name)
}
}

Related

Scala Factory Pattern return the concrete class depending on the generic type

I use the factory pattern with generics. The idea is to create the right implementation (BlockType1Impl or BlockType2Impl) depending on the type of A which is a case class( BlockchainType1 or BlockchainType2). I don't put any Type Bounds constraints.
Code
After looking at this example on the apply method with generic types
trait BlockTypeFactory[A]{
def findTransactions( blocks: Seq[A], address: String): Seq[TransactionResponse]
}
object BlockTypeFactory{
// I want this method to return the correct implementations
def getBlockExplorer[A](blockType: A): BlockTypeFactory[A] = {
blockType match {
case type1: BlockchainType1 => new BlockTypeFactory[BlockchainType1](new BlockType1Impl)
// error : Expression of type BlockTypeFactory[BlockType1Impl] doesn't conform with the expected type BlockTypeFactory[A]
case type2: BlockchainType2 => new BlockType2Impl
}
}
def apply[A](implicit ev: BlockTypeFactory[A],blockType: A):BlockTypeFactory[A] = ev
}
But I get an error about expected type . What is exactly wrong ?
Other classes
class BlockType1Impl extends BlockTypeFactory[BlockchainType1]
class BlockType2Impl extends BlockTypeFactory[BlockchainType2]
case class BlockchainType1(...)
case class BlockchainType2(...)
Your code doesn't work because the compiler doesn't know where to get the implicit instances of BlockTypeFactory.
In order to achieve your goal you can use Type Classes.
This way is extensible, you can have more than one factory per class if you want (you need to play with implicits scope) and you can define standard factories for some types.
You can code implicit instances of your case classes inside BlockTypeFactory object, but this is the way it is usually done.
// your type class
trait BlockTypeFactory[A] {
def create:A
}
case class BlockchainType1()
object BlockchainType1 {
// type 1 impl
implicit val factory:BlockTypeFactory[BlockchainType1] = new BlockTypeFactory[BlockchainType1] {
def create: BlockchainType1 = BlockchainType1()
}
}
case class BlockchainType2()
object BlockchainType2 {
// type 2 impl
implicit val factory:BlockTypeFactory[BlockchainType2] = new BlockTypeFactory[BlockchainType2] {
def create: BlockchainType2 = BlockchainType2()
}
}
object BlockTypeFactory {
// get factory
def apply[A:BlockTypeFactory]:BlockTypeFactory[A] = implicitly[BlockTypeFactory[A]]
// or create
def create[A:BlockTypeFactory]:A = implicitly[BlockTypeFactory[A]].create
}
val instance1 = BlockTypeFactory[BlockchainType1].create
val instance2 = BlockTypeFactory.create[BlockchainType2]
This pattern is called Type Class, and it is used to get ad hoc polymorphism. In your example, you need a polymorphic method findTransactions for each class defined on BlockTypeFactory.

Scala abstract types implement trait that extends from generic trait

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

How can I reference a companion object's method in a generic class?

So I am a bit new to scala.
How does one write scala code to reference a method from case class's companion object in a generic fashion? I have tried a couple of different approaches and can't seem to find one that works.
Below is some sample code that works, but I have to manually build each subclass.
For example:
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
I would much rather do something like:
class AllOfThem[T <: LettersClass, S <: LettersSingleton] extends Act[T] {
val intro = S.sayhi
}
but I can't seem to find syntax that works or will compile. What is the proper way to do this, or am I looking for something that is not supported in the language? I recognise I am probably a little off on how I am structuring my classes and traits, but I am not sure how to best tackle this desired behaviour.
Additionally, is there a way to something similar to what I have commented out in the method 'actionTwo' in the Act class?
Sample Code listing:
trait LettersSingleton {
def sayhi() : String
}
trait LettersClass {
val id : Int
}
// trait Letters extends LettersClass with LettersSingleton { }
object LetterA extends LettersSingleton {
def sayhi = "Hi I am A"
}
object LetterB extends LettersSingleton {
def sayhi = "Hi I am B"
}
case class LetterA( val id : Int ) extends LettersClass { }
case class LetterB( val id : Int, val name:String ) extends LettersClass { }
abstract class Act[ T <: LettersClass ] {
val intro : String
def actionOne( a : T ) = {
println( a.id + " is my id" )
}
def actionTwo() = {
// println( T.sayhi )
}
}
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
class Two extends Act[LetterB] {
val intro = LetterB.sayhi
}
So you can't do exactly what you want, but you can get very close with the commonly used typeclass pattern:
//add a type parameter, now you have a typeclass
trait LettersSingleton[T] {
def sayhi() : String
}
//LettersClass stays the same
object Implicits {
//implicit classes/objects have to go inside an object
//create typeclass instances as implicit objects
implicit object LetterASingleton extends LettersSingleton[LetterA] {
def sayhi = "Hi I am A"
}
implicit object LetterBSingleton extends LettersSingleton[LetterB] {
def sayhi = "Hi I am B"
}
}
import Implicits._
//add an implicit parameter to the class
abstract class Act[ T <: LettersClass ](implicit singleton: LettersSingleton[T]) {
def actionTwo() = {
println( singleton.sayhi )
}
}
(new Act[LetterA]).actionTwo() //prints "Hi I am A"
(new Act[LetterB]).actionTwo() //prints "Hi I am B"
So basically what happens is any time you create a new Act[T], the compiler is going to try to fill in the implicit parameter for you by looking for any implicit objects or vals of the correct type in scope. So
val a = new Act[LetterA]
will actually become
val a = new Act[LetterA](LetterASingleton)
You'll notice that the singletons are no longer the companion objects of the case classes, which is fine. You have to define a trait regardless, so it doesn't make much different whether it's the companion object or some other object that implements it.

Can I "Pimp my Library" on a parameterized trait with method returning this.type?

I want to extend my parameterized trait Field[T] with method returning this.type using Pimp my Library pattern. But I stuck with compiler errors. I tried some variants, but without success.
Am I doing it wrong? Or asking for the impossible?
Here is my test example:
trait Field[T]
class IntField extends Field[Int] {
def getInt = 5
}
// Variant 1: return field.type
object Var1 {
implicit class RichField[T](val field: Field[T]) {
def bar(fn: T => String): field.type = {
// some actions using T
field
}
}
new IntField().bar(_.toString).getInt // Error: value getInt is not a member of Field[Int]
}
// Variant 2: use two type parameters
object Var2 {
implicit class RichField[T, F <: Field[T]](val field: F) {
def bar(fn: T => String): F = {
// some actions using T
field
}
}
new IntField().bar(_.toString).getInt // <-- Error: value bar is not a member of IntField
}
// Variant 3: use higher kinds
object Var3 {
import scala.language.higherKinds
implicit class RichField[F[X] <: Field[X], T](val field: F[T]) {
def bar(fn: T => String): F[T] = {
// some actions using T
field
}
}
new IntField().bar(_.toString).getInt // <-- Error: value getInt is not a member of Field[Int]
}
Update: Parameter T is important for method bar, it cannot be ignored.
In variant 2, you are not using T anywhere. Just remove it and the compiler won't be confused anymore:
implicit class RichField[F <: Field[_]](val field: F) {
def bar: F = field
}
UPDATE: If you actually need T, as you mentioned in a comment, a possible workaround is this:
implicit class RichField[T, F <: Field[_]](val field: F with Field[T]) {
def bar(fn: T => String): F = {
// some actions using T
field
}
}
And here's a proof that it works as expected (using toString as in your example is not a good test given that toString is available on every class, so even if the compiler inferred Any the code would have compiled):
scala> case class Foo(name: String)
defined class Foo
scala> class FooField extends Field[Foo] {
| def getInt = 5
| }
defined class FooField
scala> new FooField().bar(_.name).getInt
res8: Int = 5

Add a trait to parametric type in a class

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.