low priority and high priority implicits in scala

强颜欢笑 提交于 2019-12-12 04:18:48

问题


In following code from Scala's puzzlers, it seems that there is no conflict in implicits because TestAlarmHandler is more specific. I didn't understand the explanation though. Why is TestAlarmHandler is more specific than DefaultAlarmHandler?

object Scanner {
  trait Console { def display(item: String) }
  trait AlarmHandler extends (() => Unit)
  def scanItem(item: String)(implicit c: Console) {
    c.display(item)
  }
  def hitAlarmButton()(implicit ah: AlarmHandler) { ah() }
}


class OperatingMode {
  implicit val ConsoleRenderer = new Scanner.Console {
    def display(item: String) { println(s"Found a ${item}") }
  }
  implicit val DefaultAlarmHandler = new Scanner.AlarmHandler {
    def apply() { println("ALARM! ALARM!") }
  }
}
object NormalMode extends OperatingMode
object TestMode extends OperatingMode {
  override implicit val ConsoleRenderer = new Scanner.Console {
    def display(item: String) { println("Found a detonator") }
  }
  implicit val TestAlarmHandler = new Scanner.AlarmHandler {
    def apply() { println("Test successful. Well done!") }
  }
}
import NormalMode._
scala> Scanner scanItem "knife"
Found a knife
scala> Scanner.hitAlarmButton()
ALARM! ALARM!
import TestMode._
scala> Scanner scanItem "shoe"
Found a detonator
scala> Scanner.hitAlarmButton()
Test successful. Well done!

回答1:


TestAlarmHandler is more specific than DefaultAlaramHandler because TestAlarmHandler is defined in an anonymous class which is derived from class OperatingMode defining DefaultAlarmHandler.


Formally, the Scala Language Specification specifies how to handle a case when more than one eligible arguments are found, as follows (note that both TestAlarmHandler and DefaultAlarmHandler are eligible because they have been imported by import TestMode._):

If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution.

Section 6.26.3 Overloading Resolution defines the concept of being more specific in terms of the concept of relative weight:

The relative weight of an alternative A over an alternative B is a number from 0 to 2, defined as the sum of

  • 1 if A is as specific as B, 0 otherwise, and
  • 1 if A is defined in a class or object which is derived from the class or object defining B, 0 otherwise.

The relative weight of TestAlarmHandler over DefaultAlarmHandler is 1 while that of DefaultAlarmHandler over TestAlarmHandler is 0. Note that TestAlarmHandler is defined in an anonymous class which is derived from class OperatingMode defining DefaultAlarmHandler. The first rule is of concern when resolving method overloading, but not relevant here.

An alternative A is more specific than an alternative B if the relative weight of A over B is greater than the relative weight of B over A.

TestAlarmHandler is more specific than DefaultAlaramHandler because the relative weight TestAlarmHandler over DefaultAlarmHandler is greater than that of the inverse.




回答2:


That's because TestMode is subclass of OperationMode, and scala at first look for implicits in scope of TestMode and only if not found it will lookup up in hierarchy.



来源:https://stackoverflow.com/questions/47339575/low-priority-and-high-priority-implicits-in-scala

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!