Description
Compiler version
3.3.5
, 3.6.4
Minimized example
trait Actor
trait LoggingAdapter {
def print = println("LoggingAdapter")
}
trait DiagnosticLoggingAdapter extends LoggingAdapter {
override def print = println("DiagnosticLoggingAdapter")
}
trait ActorLogging {
def log: LoggingAdapter = new LoggingAdapter {}
}
trait DiagnosticActorLogging extends Actor {
val log: DiagnosticLoggingAdapter = new DiagnosticLoggingAdapter {}
}
trait MyDiagnosticActorLogging extends DiagnosticActorLogging {
def redefLog: DiagnosticLoggingAdapter = log
}
trait FSM extends Actor with ActorLogging
class MyActor extends FSM with MyDiagnosticActorLogging {
// override val log: DiagnosticLoggingAdapter = super[MyDiagnosticActorLogging].log // Desired option, does not work due to val
// override val log: LoggingAdapter = super[FSM].log // Type discrepancy, also not the desired behaviour but super[FSM].log works
// override val log: DiagnosticLoggingAdapter = redefLog // Workaround that gives the desired result
}
new MyActor().log.print
Output
Without override val log: DiagnosticLoggingAdapter = redefLog
error overriding method log in trait ActorLogging of type => Playground.LoggingAdapter;
value log in trait DiagnosticActorLogging of type Playground.DiagnosticLoggingAdapter class MyActor inherits conflicting members:
method log in trait ActorLogging of type => Playground.LoggingAdapter and
value log in trait DiagnosticActorLogging of type Playground.DiagnosticLoggingAdapter
(Note: this can be resolved by declaring an override in class MyActor.)
With override val log: DiagnosticLoggingAdapter = redefLog
DiagnosticLoggingAdapter
Expectation
A slightly different case to the one mentioned in #23061 - I hoped for a cleaner way to resolve the multiple-inheritance naming conflict but didn't find one, unfortunately. Mainly opening this issue since it may be tangentially relevant to the aforementioned ticket, so apologies if this is not an actual issue but maybe an accepted limitation due to technical or conceptual reasons.
https://scastie.scala-lang.org/EQGARTbATHODep7eGr9YBA
Given the above class/trait structure (where we only control the implementation of the types prefixed with My...), the compiler will complain about conflicting members during the declaration of class MyActor
, namely about def log: LoggingAdapter
in ActorLogging
(via FSM
) and val log: DiagnosticLoggingAdapter
in DiagnosticActorLogging
(via MyDiagnosticActorLogging
). The message also states "this can be resolved by declaring an override in class MyActor". However, when trying to declare it as override val log: DiagnosticLoggingAdapter = super[MyDiagnosticActorLogging].log
(which is the desired behaviour) it also does not compile because log
is a val
in MyDiagnosticActorLogging
/ DiagnosticActorLogging
.
Defining redefLog
in MyDiagnosticActorLogging
and referring to this def
when overriding the member log
in MyActor
seems to do the job as a workaround. Is the restriction of super
to def
members unavoidable? If so, is there a cleaner way to disambiguate between the inherited members?