Scala generics function call - scala

I have the following trait in scala:
trait BaseDao {
type T <: BaseModel
def saveModel(model: T)
}
I created a class which extends BaseDao:
class Sample (dynamoDBMapper: DynamoDBMapper) extends BaseDao with LazyLogging {
checkNotNull(dynamoDBMapper)
protected def classType: Class[T] = implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]]
override def saveModel(model: T): Unit ={
model.validate()
dynamoDBMapper.save(model)
}
Now, when I create the instance of above class and try to call save method:
val testModel = new TestModel();
testModel.setHashKey("a")
testModel.setSortKey("b")
testModel.setCreatedOn(new Date())
testModel.setModifiedOn(new Date())
sample.saveModel(testModel)
It gives the following error:
Type mismatch expected: Sample#T, actual: TestModel model class extends BaseModel class
I am new in scala and I am not able to figure out what is wrong here?

You haven't defined type T in Sample.
Rewrite your Sample class to look somewhat like this:
class Sample (dynamoDBMapper: DynamoDBMapper) extends BaseDao with LazyLogging {
checkNotNull(dynamoDBMapper)
type T = TestModel
override def saveModel(model: T): Unit ={
model.validate()
dynamoDBMapper.save(model)
}
}

Related

Referencing the parent class inside a Trait

I have a class that extends a Trait and I want to write Traits that can mix in with the class and override some of the methods.
The trait that my class is extending looks like this
trait CharSource {
def source: Iterator[Char]
def words: Iterator[String] = {
while(source.hasNext){
//Logic to get the next word from a Char Iterator
}
}
final def chars: Iterator[Char] = words.toString().toIterator
}
The class that extends CharSource
class IteratorDocumentSource(iterator: Iterator[Char]) extends CharSource {
def source = iterator
}
Now I want to write a trait to override the source def in IteratorDocutmentSource for some special behavior
trait PunctuationRemover extends Transformer {self: CharSource =>
override
/** Character source. Overriding should be in terms of `super.source` for
stackability. */
abstract val source: Iterator[Char] = {
super.source
//additional logic ...
}
}
The transformer trait that PunctioationRemover extends
trait Transformer {self: CharSource =>
protected def source: Iterator[Char]
def words: Iterator[String]
}
I get an error when making this call
new IteratorDocumentSource("Hello World!".iterator) with PunctuationRemover
Error:
An exception or error caused a run to abort:
SampleSuite$$anonfun$2$$anon$3.document$PunctuationRemover$$super$source()Lscala/collection/Iterator;
java.lang.AbstractMethodError:
SampleSuite$$anonfun$2$$anon$3.document$PunctuationRemover$$super$source()Lscala/collection/Iterator;
I referenced this post but I think my situation is a little different
Can I override a scala class method with a method from a trait?

Scala - Using guice multibinder on a generic interface fails

I have the following interface:
trait Subject[T] {
def fetch() :Future[Option[T]]
}
And class:
class ChildSubject#Inject()(dao:Dao) extends Subject[String]{
def fetch(): Future[Option[String]] ={
dao.find("10").map{ name => Some(name)
}
}
And a module:
class SubjectModule extends AbstractModule with ScalaModule{
override def configure(): Unit = {
val subMulti = ScalaMultibinder.newSetBinder[Subject](binder)
subMulti.addBinding.to[ChildSubject]
}
}
And I try to inject this Set:
#Singleton
class SomeClass #Inject()(subjects: Set[Subject]){
subjects.map{
//do somthing
}
}
And I get the following error:
play.sbt.PlayExceptions$CompilationException: Compilation error[kinds
of the type arguments (com.test.Subject) do not conform to the expected
kinds of the type parameters (type T).
com.test.Subject's type parameters do not match type T's expected
parameters:
trait Subject has one type parameter, but type T has none]
Any idea??
Thanks!
You need a new TypeLiteral<Subject<String>>() for binding - generically typed interface like Subject<T> in Guice from Java. It's very likely that Scala requires the same in some form.
Something like this may work:
class SubjectModule extends AbstractModule with ScalaModule{
override def configure(): Unit = {
val subMulti = ScalaMultibinder.newSetBinder[Subject[String]](binder)
subMulti.addBinding.to[ChildSubject]
}
}

Using trait method in the class constructor

I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}

Scala Generic Subtypes and Cake Pattern

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

How to tell Scala that a def returns TypeRef[this.type]

I have a set of objects like the following:
abstract class RecordType[T <: Record]
object RecordType1 extends RecordType[Record1]
object RecordType2 extends RecordType[Record2]
...
I'd like to use them in the following way, i.e. each RecordX has a def recordType: RecordType[RecordX], but I have not been able to figure out the proper syntax (assuming that this is possible):
abstract class Record {
def recordType: RecordType[this.type]
}
class Record1 extends Record {
override def recordType: RecordType[Record1] = RecordType1
}
class Record2 extends Record {
override def recordType: RecordType[Record2] = RecordType2
}
...
This produces the error that the overriding methods have incompatible types.
I've tried the following as a starting point / compromise
abstract class Record {
def recordType[T <: Record]: RecordType[T]
}
class Record1 extends Record {
override def recordType: RecordType[Record1] = RecordType1
}
but this produces the error
type mismatch;
[error] found : RecordType1.type
[error] required: RecordType[Record1]
Is there a way to accomplish the first goal of requiring that each Subclass return RecordType[Subclass], or barring that is there a way to fix the second set of code?
Your solution is one of the standard approaches for this problem. Another is to use type members:
abstract class Record {
type ThisType <: Record
def recordType: RecordType[ThisType]
}
class Record1 {
type ThisType = Record1
override def recordType: RecordType[Record1] = RecordType1
}
I think I may have found a solution:
abstract class RecordType[T <: Record[T]]
object RecordType1 extends RecordType[Record1]
abstract class Record[T <: Record[T]] {
def recordType: RecordType[T]
}
class Record1 extends Record[Record1] {
override def recordType: RecordType[Record1] = RecordType1
}