Аномалия перегрузки функции Scala

В Scala, почему эта перегрузка была разрешена?

class log {
  def LogInfo(m: String, properties: Map[String, String]): Unit = {
    println(m)
  }

  def LogInfo(m: String, properties: Map[String, String], c: UUID = null): Unit = {
    println(m + c.toString())
  }
}

Во втором определении функции LogInfo я установил для дополнительного параметра значение по умолчанию null. Когда я сделаю следующий вызов, он вызовет первую перегрузку.

val l: log = new log()
val props: Map[String, String] = Map("a" -> "1")
l.LogInfo("message", props)

Почему бы не бросить исключение? При значении по умолчанию я бы подумал, что оба определения могут выглядеть одинаково.

2 ответа

Решение

Исключение здесь не возникнет, потому что компилятор выбирает первую перегрузку как применимую. Это связано с тем, как разрешение перегрузки работает с аргументами по умолчанию. Согласно спецификации, сильный намек на то, что такие методы отбрасываются, будет следующей строкой:

В противном случае, пусть CC будет набором применимых альтернатив, которые не используют аргумент по умолчанию в приложении для e1,…,em ,

Это связано с тем, как компилятор Scala генерирует байтовый код JVM для этих двух методов. Если мы скомпилируем их и посмотрим за кулисы, то увидим (для краткости опускаем фактический байт-код):

public class testing.ReadingFile$log$1 {
  public void LogInfo(java.lang.String,
                      scala.collection.immutable.Map<java.lang.String, java.lang.String>);
    Code:

  public void LogInfo(java.lang.String,
                      scala.collection.immutable.Map<java.lang.String, java.lang.String>,
                      java.util.UUID);
    Code:

  public java.util.UUID LogInfo$default$3();
    Code:
       0: aconst_null
       1: areturn
}

Вы видите, что сгенерированный код фактически испустил два метода, один из которых принимает два аргумента, а другой - три. Дополнительно, компилятор добавил дополнительный метод LogInfo$default$3 (имя на самом деле имеет значение, где $3 означает "параметр по умолчанию для третьего аргумента), который возвращает значение по умолчанию для c переменная второй перегрузки. Если метод с аргументом по умолчанию должен быть вызван, LogInfo$default$3 будет использоваться для введения новой переменной с заданным значением.

Оба метода применимы, но перегрузка разрешения специально отбрасывает приложение, которое требует аргументов по умолчанию:

применимые альтернативы, которые не используют аргумент по умолчанию

http://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html

Что касается "почему", представьте, что перегрузка имеет много параметров по умолчанию, так что большинство ее приложений не похожи на вызовы первого метода.

Другие вопросы по тегам