I am working on upgrading some code from Scala 2.13 to Scala 3 and I came across some differences with trait mixins with inner traits having same names.
This code compiles in Scala 2.13:
trait First {
val first: Service
trait Service {
def someMethod(): Int
}
}
trait LiveFirst extends First {
override val first: Service = new Service {
override def someMethod(): Int = 1
}
}
trait Second {
val second: Service
trait Service {
def someMethod(): Int
}
}
trait LiveSecond extends Second {
override val second: Service = new Service {
override def someMethod(): Int = 2
}
}
type Mixed = First with Second
val mixed: Mixed = new LiveFirst with LiveSecond
But fails with following compiler error in Scala 3:
[error] 32 |val mixed: Mixed = new LiveFirst with LiveSecond
[error] | ^
[error] |error overriding trait Service in trait First;
[error] | trait Service in trait Second cannot be used here - class definitions cannot be overridden
What exactly has changed here?
Related
I want to define an abstract variable with type bound in trait and implement in the respective extended class. Something similar to this
trait Animal {
def makeSound(): Unit
}
class Lion extends Animal {
override def makeSound(): Unit = println("Roar")
def scarySound(): Unit = println("Rooooaaarrrrr")
}
trait AnimalCostume {
val animal: _ <: Animal
def locate(): Unit = {
animal.makeSound()
}
}
class LionCostume extends AnimalCostume {
override val animal = new Lion()
def scareEveryOne(): Unit = animal.scarySound()
}
The code is not compiling with the following exception
unbound wildcard type
val animal: _ <: Animal
Can you help in understanding how do I achieve something like this and why it is failing with error that type is not bounded if I have explicitly defined the upper bound here
There is the following API for Slick CRUD (Slick-2.1.0, Scala-2.11.4):
trait HasId {
type Id
def id: Option[Id]
}
trait HasIdColumn[E <: HasId] {
def id: scala.slick.lifted.Column[E#Id]
}
trait SlickExtensions {
val driver: scala.slick.driver.JdbcProfile
import driver.simple._
trait BaseDAO[T <: Table[E], E] {
val query: TableQuery[T]
}
trait HasIdActions[T <: Table[E] with HasIdColumn[E], E <: HasId]
extends BaseDAO[T, E] {
//line L1: this implicit val is needed to execute query.filter(_.id === id)
// what can be done in order to save the user from the necessity
// to override this value?
implicit val mappingId: BaseColumnType[E#Id]
def findById(id: E#Id)(implicit session: Session): Option[E] =
query.filter(_.id === id).firstOption
...
}
}
I apply this SlickExtensions as follows:
case class Entity(id: Option[Long] = None, value: String) extends HasId {
type Id = Long }
trait EntityComponent extends SlickExtensions {
import driver.simple._
class EntitiesTable(tag: Tag) extends Table[Entity](tag, "entities")
with HasIdColumn[Entity] {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def value = column[String]("value", O.NotNull)
def * = (id.?, value) <>(Entity.tupled, Entity.unapply)
}
object Entities extends HasIdActions[EntitiesTable, Entity] {
val query = TableQuery[EntitiesTable]
/* line L2: from slick library: ImplicitColumnTypes */
override implicit val mappingId = driver.simple.longColumnType
}
}
End point to execute queries:
val c = new EntityComponent {
lazy val driver = play.api.db.slick.Config.driver
}
db.withSession { implicit session =>
c.Entities.findById(1) foreach println
}
The main question is how to get rid of "implicit val mappingId" overriding in line L2?
I tried to create a class:
abstract class IdImplicits[E<:HasId](implicit val mappingId:BaseColumnType[E#Id])
and inherited it as follows:
object Entities extends IdImplicits[EntitiesTable, Entity]
with HasIdActions[EntitiesTable, Entity] {
val query = TableQuery[EntitiesTable]
//override implicit val mappingId: driver.simple.longColumnType
}
However it seems to me that such approach is redundant.
It would be great if I could hide "implicit val mappingId" inside SlickExtensions.
Here is the link to the same question
UPD:
In my project, I'd like to add HasName, HasValue[V] and some other mixins to construct the following DAOs:
object EntitiesDAO extends HasIdActions
with HasNameActions
with HasValueActions with NameToIdActions with ValueToIdActions {
...
override def nameToId(name:String):Option[E#Id]
override def valueToId(value:E#ValueType):Option[E#Id]
...
}
It leads to the following problems:
1) implicits for BaseColumnTypes, mentioned in my topic, should be taken into consideration for HasId, HasValue mixins
2) If implicits BaseColumnTypes are used as parameters of constructor of abstract classes then these classes can't be mixed in one EntityDAO object (the problem is described here).
3) If one abstract class is used for each variant of EntityDAO, then we get ugly-looking combinations, for example:
abstract class IdValueNameImplicits[E <: HasId with HasValue with HasName]
(implicit val idMapper:BaseColumnType[E#Id],
implicit val valueMapper:BaseColumnType[E#ValueType])
You can't do that because you are inside a trait and E#Id is only defined when you have a concrete implementation of it.
As you already discovered, you have to define your BaseColumnType when your trait is implemented because only then you have a defined type for E#Id.
Another option is not to have a trait but an abstract class where you can have a implicit BaseColumnType passed to the constructor.
I have a small project that does exactly what you are looking for. You can find it here: https://github.com/strongtyped/active-slick
There is also an Activator template.
http://typesafe.com/activator/template/slick-active-record
You can use it as is or as inspiration for your own.
Have fun!
How to describe an API interface in terms of several layered service interfaces that deal with abstract types, the representations of which can be chosen by concrete implementations.
// interfaces
trait API {
val serviceA: ServiceA
val serviceB: ServiceB[ServiceA]
def op_API: Unit = serviceA.op_A(serviceB.op_B)
}
trait ServiceA {
type X
def op_A(x: X): Unit
}
trait ServiceB[A <: ServiceA] {
def op_B: A#X
}
// implementations
object API_Impl extends API {
val serviceA = ServiceA_Impl
val serviceB = ServiceB_Impl
}
object ServiceA_Impl extends ServiceA {
type X = String
def op_A(x: String): Unit = println(x)
}
object ServiceB_Impl extends ServiceB[ServiceA_Impl.type] {
def op_B: String = "test"
}
Unfortunately this code leads to a type mismatch:
found : ServiceA#X
required: API.this.serviceA.X
def op_API: Unit = serviceA.op_A(serviceB.op_B)
^
I suppose one approach is to have the outer service layer maintain an instance of the inner service layer, define the types in terms of that instance, and then assign the API's service members through the service member of the outer layer:
// interfaces
trait API {
lazy val serviceA: serviceB.serviceA.type = serviceB.serviceA
val serviceB: ServiceB[_ <: ServiceA]
def op_API: Unit = serviceA.op_A(serviceB.op_B)
}
trait ServiceA {
type X
def op_A(x: X): Unit
}
trait ServiceB[A <: ServiceA] {
val serviceA: A
def op_B: serviceA.X
}
// implementations
object API_Impl extends API {
val serviceB = ServiceB_Impl
}
object ServiceA_Impl extends ServiceA {
type X = String
def op_A(x: String): Unit = println(x)
}
object ServiceB_Impl extends ServiceB[ServiceA_Impl.type] {
val serviceA = ServiceA_Impl
def op_B: String = "test"
}
In Scala in Depth there is this example:
trait Logger {
def log(category: String, msg: String) : Unit = {
println(msg)
}
}
trait DataAccess {
def query[A](in: String) : A = {
...
}
}
trait LoggedDataAccess {
val logger = new Logger
val dao = new DataAccess
def query[A](in: String) : A = {
logger.log("QUERY", in)
dao.query(in)
}
}
I am a little confused by the initialization of Logger and DataAccess in the trait LoggedDataAccess. In the REPL, when I type out this code, I get the following exception:
error: trait Logger is abstract; cannot be instantiated
val logger = new Logger
Can a trait actually be initialized like that?
Trait can't be instantiated, but you can create an instance of anonymous implementation of trait:
scala> trait Test
defined trait Test
scala> new Test
<console>:9: error: trait Test is abstract; cannot be instantiated
new Test
^
scala> new Test{}
res0: Test = $anon$1#7fafd333
scala> new Object with Test
res1: Test = $anon$1#4fe11d82
new Test{} and new Object with Test means the same. They create new anonymous class and instantiate it right away.
I am new to Scala and dont know why i have to do an (unintuitive for me) type cast related to path dependent types in the following code.
(I don't like getters, setters nor nulls, they are here to separate operations and disambiguate the source of errors)
// Module A public API
class ModA {
trait A
}
// Module B public API that depends on types defined in Module A
class ModB(val modA: ModA) {
trait B {
def getA: modA.A;
def setA(anA: modA.A);
}
}
// One implementation of Module A
class ModAImpl extends ModA {
class AImpl extends A
}
// One implementation of Module B
class ModBImpl(mod: ModA) extends ModB(mod) {
class BImpl extends B {
private[this] var privA: modA.A = _;
override def getA = privA;
override def setA(anA: modA.A) = privA = anA;
}
}
object Main {
def main(args: Array[String]): Unit = {
// wiring the modules
val modAImpl = new ModAImpl;
val modBImpl = new ModBImpl(modAImpl);
// wiring objects
val a = new modAImpl.AImpl;
val b = new modBImpl.BImpl;
b.setA(a); //don't compile and complain: type mismatch; found: modAImpl.A required: modBImpl.modA.A
//i have to do this horrible and coutnerintuitive cast to workaround it
b.setA(a.asInstanceOf[modBImpl.modA.A]);
var someA: modAImpl.A = null;
someA = b.getA; // don't compile with same reason
someA = b.getA.asInstanceOf[modAImpl.A]; // horrible cast to workaround
println(a == b.getA); // however this prints true
println(a eq b.getA); // this prints true too
}
}
I have read about singleton types to inform the compiler when two types are the same, but I don't know how to apply this here.
Thanks in advance.
You can stick a type parameter on the ModB types:
class ModA { trait A }
class ModB[AA](val modA: ModA { type A = AA }) {
trait B {
def getA: AA
def setA(anA: AA)
}
}
class ModAImpl extends ModA { class AImpl extends A }
class ModBImpl[AA](
mod: ModA { type A = AA }) extends ModB(mod) {
class BImpl extends B {
private[this] var privA: AA = _
override def getA = privA
override def setA(anA: AA) = privA = anA
}
}
And the type inference all works out as desired:
scala> val modAImpl = new ModAImpl
modAImpl: ModAImpl = ModAImpl#7139edf6
scala> val modBImpl = new ModBImpl(modAImpl)
modBImpl: ModBImpl[modAImpl.A] = ModBImpl#1dd7b098
scala> val a = new modAImpl.AImpl
a: modAImpl.AImpl = ModAImpl$AImpl#4cbde97a
scala> val b = new modBImpl.BImpl
b: modBImpl.BImpl = ModBImpl$BImpl#63dfafd6
scala> b.setA(a)
Let's start by simplifying your code ridding out the unnecessary complexity.
class Aout {
class Ain
}
class Bout(val link: Aout) {
class Bin(val field: link.Ain)
}
object Main {
def main(args: Array[String]): Unit = {
// wiring outer object
val aout: Aout = new Aout;
val bout: Bout = new Bout(aout);
// wiring inner object
val ain: aout.Ain = new aout.Ain;
val bin: bout.Bin = new bout.Bin(ain); //don't compile and complain: type mismatch; found: aout.Ain required: bout.link.Ain
}
}
Answer:
The compiler complains with a type mismatch error because he compares the paths of the two declared types involved in the assignment, and they are different.
The compiler is not intelligent enough to notice that at that point aout eq bout.link. You have to tell him.
So, replacing the line
val ain: aout.Ain = new aout.Ain;
with
val ain: bout.link.Ain = new bout.link.Ain;
solves the path-dependent type mismatch.
Anyway, correcting the type's path in your original code is not enough because there is also an inheritance problem.
One solution to that is to make the class ModBImpl know the ModAImpl class like this:
class ModA {
trait A
}
class ModB[M <: ModA](val modA: M) { // type parameter added
trait B {
def getA: modA.A;
def setA(anA: modA.A);
}
}
class ModAImpl extends ModA {
class AImpl extends A
}
class ModBImpl(mod: ModAImpl) extends ModB(mod) { // changed type of `mod` parameter from `ModA` to `ModAImpl`
class BImpl extends B {
private[this] var privA: modA.A = _;
override def getA: modA.A = privA;
override def setA(anA: modA.A): Unit = privA = anA;
}
}
object Main {
def main(args: Array[String]): Unit = {
val modAImpl = new ModAImpl;
val modBImpl = new ModBImpl(modAImpl);
val a: modBImpl.modA.AImpl = new modBImpl.modA.AImpl; // changed the path of the type
val b: modBImpl.BImpl = new modBImpl.BImpl;
b.setA(a); // here IntellijIde complains with a type mismatch error, but the ScalaIDE (eclipse) and the scala compiler work fine.
}
}
If the rules of your business don't allow that the ModBImpl class has knowledge of the ModAImpl class, tell me so we can find another solution.