abstract class and generics in Scala - scala

i am trying to move my existing app written in java to scala,but i am struggling against
this particular one,.
In java, i have the following abstract class :
public abstract class AbstractHibernateDao<T, ID extends Serializable> extends
HibernateDaoSupport implements GenericDao<T, ID> {
private final Class<? extends T> persistentClass;
public AbstractHibernateDao(Class<? extends T> persistentClass) {
this.persistentClass = persistentClass;
}
I am trying to write that in Scala, but i am struggling with the variable persistentClass, which is of type Class
i have tried the following but it fails big time
abstract class ScalaHibernateDao[T, ID <: Serializable](persistentClass <: T) extends
HibernateDaoSupport with GenericDao[T, ID] {
could anyone assist pls?
w/kindest regards
Marco

You will need to use the specification Class[_ <: T] here to match the Java style:
abstract class ScalaHibernateDao[T, ID <: Serializable](persistentClass: Class[_ <: T]) extends HibernateDaoSupport with GenericDao[T, ID] { ...

I belive the following is idiomatic Scala approach:
abstract class ScalaHibernateDao[T: ClassTag, ID <: Serializable] extends HibernateDaoSupport with GenericDao[T, ID] {
private val persistentClass = classTag[T].runtimeClass
}
When using ClassTags you won't have to pass Class[_] instance manually, the compiler will do it for you:
class SomeEntityDao extends ScalaHibernateDao[SomeEntity, Long]
Class[SomeEntity] then will be automatically resolved.

Related

Scala TypeTag missing class name

I'm trying to get some information using Scala's reflect library :
abstract class Model
class Person extends Model
class Car extends Model
abstract class AbstractDao[T <: Model]
object PersonDao extends AbstractDao[Person]
object CarDao extends AbstractDao[Car]
object DataLoader {
val daos = Seq(PersonDao, CarDao)
val modelToString = daos.map(genericImportEntities(_))
val modelToString2 = Seq(genericImportEntities(PersonDao), genericImportEntities(CarDao))
private def genericImportEntities[T <: Model](dao: AbstractDao[T])
(implicit
t2: TypeTag[T]
): String = {
t2.tpe.toString
}
}
If I call modelToString, the output is
List(_1, _1)
With modelToString2, it is
List(Person, Car)
Any idea how can I make modelToString work?
The issue is that type of daos is Seq[AbstractDao[_]]. So when calling daos.map(genericImportEntities(_)), T is an unknown type which the compiler calls _1. Generally, TypeTags are only useful when you know the static types at the point where the compiler should insert them, and in this case you don't.
The easiest way to fix this would be to move TypeTag into AbstractDao:
abstract class AbstractDao[T <: Model](implicit val tag: TypeTag[T])
private def genericImportEntities[T <: Model](dao: AbstractDao[T]) =
dao.tag.tpe.toString
Then the compiler inserts the tags at definition of PersonDao and CarDao and they can be used later in genericImportEntities.

How to apply generic type to another classes generic in Scala

There is a class in Slick ORM called TableQuery. Its companion object has apply method:
def apply[E <: AbstractTable[_]]: TableQuery[E] =
macro TableQueryMacroImpl.apply[E]
I have class Users extends Table that extends AbstractTable so I can write this:
class Users(tag: Tag) extends Table[User](tag, "users") {..some code..}
val query = TableQuery[Users]
I want to generalize work with database so I created class Dao
class Dao[A, B <: AbstractTable[A]] {
private val query = TableQuery[B]
}
Here compiler says: "class type required but B found". When I change B <: AbstractTable[A] to B: ClassTag it doesn't run too.
So what generic type do I have to use to send it to TableQuery?

Is it possible to achieve class type inference?

Consider following code (which not compilable):
trait Entity {
type T <: Reality
def liveIn: Option[Class[_ <: Unit#T]]
}
abstract class World extends Entity {
def liveIn = None
}
class Universe extends World { type T = Real.type }
class ParallelUniverse extends World { type T = Unreal.type }
abstract class Humanoid {
def liveIn = Some(classOf[World#T])
}
class Human extends Humanoid { type T = Real.type }
class Alien extends Humanoid { type T = Unreal.type }
sealed trait Reality
case object Real extends Reality
case object Unreal extends Reality
Is it possible to infer or somehow implicitly place concrete class instance at Some(classOf[???])?
Seems my problem solved in other way:
trait Entity[T <: Reality] {
def liveIn: Option[Class[_ <: Entity[T]]]
}
abstract class World[T <: Reality] extends Entity[T] {
def liveIn = None
}
class Universe extends World[Real.type]
class ParallelUniverse extends World[Unreal.type]
abstract class Humanoid[T <: Reality] extends Entity[T] {
def liveIn = Some(classOf[World[T]])
}
class Human extends Humanoid[Real.type]
class Alien extends Humanoid[Unreal.type]
sealed trait Reality
case object Real extends Reality
case object Unreal extends Reality

Clarification needed about Scala variance and type bounds

I have a scala trait defined as follows:
trait AdvertisementDAO[A <: Advertisement] extends CrudRepository[A, Integer] {
...
I would like to be able to get an instance of this DAO that would work for both subclasses of Advertisement or the base Advertisement class itself. I am not sure how to achieve the desired effect.
Here is what I tried:
#Inject
var advertisementDAO: AdvertisementDAO[+Advertisement] = _
Can anyone help?
It looks like you are trying to define the type parameter, A, of the trait, AdvertisementDAO, as covariant. Below is a variant of the code example from the previous answer using the covariance annotation, +.
trait Advertisement {}
class AdvertisementImpl extends Advertisement{}
class CrudRepository[+A,B] {}
trait AdvertisementDAO[+A <: Advertisement] extends CrudRepository[A, Integer] {}
class AdvertisementDAOImpl[+A <: Advertisement] extends AdvertisementDAO[A]{}
class AdvertisementDAOImpl2 extends AdvertisementDAO[AdvertisementImpl]{}
class AdvertisementDAOImpl3 extends AdvertisementDAO[Advertisement]{}
object Tester
{
def main(args:Array[String]):Unit =
{
var advertisementDAO: AdvertisementDAO[Advertisement] = null
advertisementDAO = new AdvertisementDAOImpl
advertisementDAO = new AdvertisementDAOImpl2
advertisementDAO = new AdvertisementDAOImpl3
}
}
Another example of a covariant generic is scala.collection.immutable.List. Defining a generic (class or trait) C as covariant means that C[S] is a subtype of C[T], if type S is a subtype of type T. For instance, AdvertisementDAO[AdvertisementImpl] is a subtype of AdvertisementDAO[Advertisement] because AdvertisementImpl is a subtype Advertisement (since AdvertisementImpl extends Advertisement). I published a paper, which contains tutorial on variance as it occurs in many languages (e.g. Scala, C#, Java). Slides are also available for a quick overview. Hope this helps.
I tried a lot of combinations but I receive one which compile with scala 2.9.1
var advertisementDAO: AdvertisementDAO[_ <:Advertisement] = _
advertisementDAO = new AdvertisementDAOImpl
advertisementDAO = new AdvertisementDAOImpl2
advertisementDAO = new AdvertisementDAOImpl3
My code:
trait Advertisement {}
class AdvertisementImpl extends Advertisement{}
class CrudRepository[A,B] {}
trait AdvertisementDAO[ A <: Advertisement] extends CrudRepository[A, Integer] {}
class AdvertisementDAOImpl[A <: Advertisement] extends AdvertisementDAO[A]{}
class AdvertisementDAOImpl2 extends AdvertisementDAO[AdvertisementImpl]{}
class AdvertisementDAOImpl3 extends AdvertisementDAO[Advertisement]{}

How to use Manifest with Enumeration in Scala?

If I have the following Scala code:
trait BaseTrait[EnumType <: Enumeration] {
protected val enum: EnumType
protected val valueManifest: Manifest[EnumType#Value]
}
object MyEnum extends Enumeration {
val Tag1, Tag2 = Value
}
And I want to create a class which implements BaseTrait using MyEnum, I can do it like this:
class BaseClass[EnumType <: Enumeration]
(protected val enum: EnumType)
(implicit protected val valueManifest: Manifest[EnumType#Value])
extends BaseTrait[EnumType] {
}
class Test extends BaseClass(MyEnum)
But how can I do it without an intermediary base class? All other attempts always resulted in a compile error.
You did not write what you tried but my guess is that you had your class extend BaseTrait[MyEnum]. As MyEnum is an object the type MyEnum does not exist (unless you also define a class or trait with that name).
You have to explicitly supply the singleton type MyEnum.type as type parameter.
class Test extends BaseTrait[MyEnum.type] {
protected val enum = MyEnum
protected val valueManifest = manifest[MyEnum.type#Value]
}