How to prevent stack overflow when using Scala'

2019-07-14 14:23发布

问题:

Given this simple code snippet I am astounded to provoke a stack overflow this easy:

implicit def foobar: Unit = implicitly[Unit]

In my little more complex use case I have the following situtation:

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]]
}

Defining method repr2Ordered in class Foo does not work because type Repr_Tpe is abstract. So I decided to copy & paste the declaration and make a definition out of it; apparently leading to the stack overflow from above. Only by removing the modifier implicit from the definition in class Bar solves this problem.

Isn't there an elegant solution circumventing this pitfall?

回答1:

You've defined foobar to be the implicit value of type Unit. Then you've defined it as the implicit value of type Unit. Thinking of it this way:

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

You should be no more surprised that this causes a stack overflow than you would be by this statement:

def tharSheBlows: Unit = tharSheBlows

For something with a bit more elegance, I would use a view bound to ensure that the type paramater is Ordered instead.

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