Scala объединяет несколько параметров вызова функции в Tuple - это можно отключить? - PullRequest
7 голосов
/ 17 мая 2010

Это серьезное нарушение безопасности типов в моем проекте, поэтому я ищу способ его отключить. Похоже, что если функция принимает AnyRef (или java.lang.Object), вы можете вызвать функцию с любой комбинацией параметров, и Scala объединит параметры в объект Tuple и вызовет функцию.

В моем случае функция не ожидает кортеж и не работает во время выполнения. Я ожидаю, что эта ситуация будет обнаружена во время компиляции.

object WhyTuple {
 def main(args: Array[String]): Unit = {
  fooIt("foo", "bar")
 }
 def fooIt(o: AnyRef) {
  println(o.toString)
 }
}

Выход:

(foo,bar)

Ответы [ 6 ]

7 голосов
/ 17 мая 2010

Никаких намеков или Predef на игру здесь вообще - просто старая добрая магия компилятора. Вы можете найти его в type checker . Я не могу найти его в спецификации прямо сейчас.

Если вы достаточно мотивированы, вы можете добавить опцию -X к компилятору, чтобы предотвратить это.

Кроме того, вы можете избежать написания методов arity-1, которые принимают супертип TupleN.

4 голосов
/ 17 мая 2010

Что-то вроде этого:

object Qx2 {
    @deprecated def callingWithATupleProducesAWarning(a: Product) = 2
    def callingWithATupleProducesAWarning(a: Any) = 3
}

У кортежей есть свойство Product, поэтому любой вызов callWithATupleProducesAWarning, передающий кортеж, вызовет предупреждение об устаревании.

4 голосов
/ 17 мая 2010

Редактировать : По словам людей, лучше информированных, чем я, следующий ответ на самом деле неверен: см. этот ответ . Спасибо Аарону Новструпу за указание на это.

Это на самом деле причуда парсера , а не системы типов или компилятора. Scala позволяет вызывать функции с нулевым или одним аргументом без скобок, но не с функциями с более чем одним аргументом. Так как Фред Хаслам говорит , то, что вы написали , не является вызовом с двумя аргументами, это вызов с одним аргументом с кортежем. Однако, если метод действительно принимает два аргумента, вызов будет вызовом из двух аргументов. Кажется, что смысл кода влияет на то, как он анализирует (что немного неприятно).

Что касается того, что вы на самом деле можете сделать, это сложно. Если метод действительно требует двух аргументов, эта проблема исчезнет (то есть, если кто-то по ошибке попытается вызвать его с одним или тремя аргументами, он получит ошибку компиляции, как вы ожидаете). Не думаете ли вы, что добавили в этот метод какой-то дополнительный параметр? :)

1 голос
/ 17 мая 2010

Компиляция способна интерпретировать методы без круглых скобок. Таким образом, для обозначения кортежа нужны круглые скобки. Ваш звонок такой же как:

fooIt( ("foo","bar") )

При этом вы можете заставить метод исключить вызов, и получить значение, если вы используете какую-нибудь оболочку, например Some (AnyRef) или Tuple1 (AnyRef).

0 голосов
/ 18 мая 2010

Не могли бы вы также добавить двухпараметрическое переопределение, которое помешало бы компилятору применять синтаксический сахар? Делая так, чтобы шрифты выглядели соответственно, вы вряд ли получите ложные срабатывания. Например:

object WhyTuple {

  ...

  class DummyType

  def fooIt(a: DummyType, b: DummyType) {
    throw new UnsupportedOperationException("Dummy function - should not be called")
  }
}
0 голосов
/ 17 мая 2010

Я думаю, что определение (x, y) в Predef является ответственным. Флаг компилятора "-Yno-prefs" может быть полезен, если вы готовы вручную импортировать любые последствия, которые вам необходимы. Я имею в виду, что вам нужно будет добавить импорт scala.Predef._ повсюду.

...