Как предотвратить переполнение стека при использовании Scala Predef.implicitly - PullRequest
2 голосов
/ 25 февраля 2012

Принимая во внимание этот простой фрагмент кода, я удивляюсь, как легко вызвать переполнение стека:

implicit def foobar: Unit = implicitly[Unit]

В моем немного более сложном сценарии использования у меня следующая ситуация:

abstract class Foo {
  type Repr_Tpe
  protected implicit def repr2Ordered: Repr_Tpe => Ordered[Repr_Tpe]
}

class Bar extends Foo {
  type Repr_Tpe = Long
  protected implicit def repr2Ordered = implicitly[Repr_Tpe => Ordered[Repr_Tpe]]
}

Определение метода repr2Ordered в классе Foo не работает, поскольку тип Repr_Tpe является абстрактным.Поэтому я решил скопировать и вставить декларацию и сделать из нее определение; очевидно приводит к переполнению стека сверху. Только удалив модификатор implicit из определения в классе Bar решает эту проблему.

Нет ли элегантного решения, обходящего этоловушка?

1 Ответ

0 голосов
/ 26 февраля 2012

Вы определили от foobar до быть неявным значением типа Unit. Затем вы определили это как неявное значение типа Unit. Думая об этом так:

implicit def foobar: Unit = implicitly[Unit]
// you've defined foobar as the implicit value for Unit.
// so implicitly[Unit] is the same as calling foobar
// which is the same as:
implicit def foobar: Unit = foobar

Вы не должны быть более удивлены, что это вызывает переполнение стека, чем вы были бы с этим оператором:

def tharSheBlows: Unit = tharSheBlows

Для чего-то с немного большей элегантностью, я бы использовал границы представления , чтобы гарантировать, что тип параметра равен Ordered.

scala> abstract class Foo[Repr_Tpe <% Ordered[Repr_Tpe]] {}
defined class Foo

scala> class Bar extends Foo[Long] {}
defined class Bar

scala> case class Unordered(data: String)
defined class Unordered

scala> class Bam extends Foo[Unordered] {}
<console>:10: error: No implicit view available from Unordered => Ordered[Unordered].
       class Bam extends Foo[Unordered] {}
                 ^

scala> implicit def bringOrder(u: Unordered) = new Ordered[Unordered] { def compare(that: Unordered) = u.data.compareTo(that.data) }
bringOrder: (u: Unordered)java.lang.Object with Ordered[Unordered]

scala> class Bam extends Foo[Unordered] {}
defined class Bam
...