type of a child trait in a parent trait in scala

I have some scala traits with same self-type declared as following.

trait BookDbModule {
  self: DbConfig => // Abstract this to a parent trait
  /* ... */
}

trait AuthorDbModule {
  self: DbConfig => // Abstract this to a parent trait
  /* ... */
}

I am trying to abstract the self-type declaration to a parent trait such that each of these traits does not have to define self-type. I tried the following.

trait DbModule {
  self: DbConfig =>
  // Some common DbModule methods
}

// !!! Illegal Inheritance, self-type BookDbModule does not conform to DbConfig
trait BookDbModule extends DbModule {
  // What needs to be used instead of extends?
  /* ... */
}

// !!! Illegal Inheritance, self-type AuthorDbModule does not conform to DbConfig
trait AuthorDbModule extends DbModule {
  // What needs to be used instead of extends?
  /* ... */
}

The error messages Illegal Inheritance makes sense to me as BookDbModule does not extend DbConfig .

Is there any way in Scala to enforce self-type of children traits in a parent trait?

Update: It seems like the question is little bit confusing.

What I want to achieve is, I want to omit necessity to set self-type for BookDbModule and AuthorDbModule by extending (or any other scala feature) the parent trait DbModule while has the self-type DbConfig .

So, basically, I am looking for a way to make children traits ( BookDbModule and AuthorDbModule ) be extended by only those classes with DbConfig by declaring self-type in parent DbModule but not in those children traits.

// This works but is there any way to omit necessity to write
// self: DbConfig =>
trait AuthorDbModule extends DbModule {
  self: DbConfig =>
  /* ... */
}

Please let me know if it is still confusing.

Thank You!


Take a look at this:

scala> trait DbConfig { def f = 123 }
defined trait DbConfig

DbModule that requires DbConfig implementation:

scala> trait DbModule { self: DbConfig => }
defined trait DbModule

BookDbModule is of type DbModule , still requires DbConfig implementation:

scala> trait BookDbModule extends DbModule { self: DbConfig => }
defined trait BookDbModule
scala> new BookDbModule with DbConfig {}.f
res0: Int = 123

BookDbModule is of type BookDbModule , requires DbConfig implementation directly:

scala> trait BookDbModule { self: DbConfig => }
defined trait BookDbModule
scala> new BookDbModule with DbConfig {}.f
res1: Int = 123

BookDbModule is of type BookDbModule , requires DbModule implementation, which in turn requires DbConfig implementation:

scala> trait BookDbModule { self: DbModule => }
defined trait BookDbModule

scala> new BookDbModule with DbConfig {}.f
<console>:14: error: illegal inheritance;
 self-type BookDbModule with DbConfig does not conform to BookDbModule's selftype BookDbModule with DbModule
       new BookDbModule with DbConfig {}.f
           ^

scala> new BookDbModule with DbConfig with DbModule {}.f
res3: Int = 123

You can also use inheritance:

trait BookDbModule extends DbModule with DbConfig
scala> new BookDbModule with DbConfig {}.f
res4: Int = 123

However you can't inherit a self type annotation somehow, so you can either resort to inheritance, or annotate with self types explicitly. Note that this simplification is also possible:

scala> trait DbConfig { def f = 123 }
defined trait DbConfig

scala> trait DbModule { self: DbConfig => }
defined trait DbModule

scala> trait DbModuleService extends DbModule with DbConfig
defined trait DbModuleService

Closest to what you are looking for, but has to use intermediate trait DbModuleService that is "complete":

scala> trait BookDbModule extends DbModuleService
defined trait BookDbModule

scala> new BookDbModule {}.f
res0: Int = 123

Or:

scala> trait DbConfig { def f = 123 }
defined trait DbConfig

scala> trait DbModule { self: DbConfig => }
defined trait DbModule

scala> trait DbModuleService extends DbModule with DbConfig
defined trait DbModuleService

scala> trait BookDbModule { self: DbModuleService => }
defined trait BookDbModule

scala> new BookDbModule with DbModuleService {}.f
res0: Int = 123

The answer is no. It is not possible. In fact what you say is against the purpose of self typing.

trait DbModule {
  self: DbConfig =>
}

trait BookDbModule extends DbModule {
}

In your example (summarized here), DbModule says my children must somehow provide the functionality defined in DbConfig . But trait BookDbModule cannot show that unless it either extends DbConfig or explicitly self type it. And that is against what you wanted...

链接地址: http://www.djcxy.com/p/51026.html

上一篇: 重写Scala中通用特征的方法

下一篇: 在scala中的父特征中的一个子特征的类型