2012-02-25 3 views
2

Учитывая этот простой фрагмент кода я изумлен, чтобы вызвать переполнение стека это легко:Как предотвратить переполнение стека при использовании в Scala Predef.implicitly

implicit def foobar: Unit = implicitly[Unit] 

В моем маленьком более сложном случае использования у меня есть следующий 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]] 
} 

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

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

+0

Не мог ли компилятор Scala легко обнаружить эту ситуацию, так как определение находится в процессе определения? –

+0

Причина этой ошибки заключается в том, что вы определяете то, что хотите вернуть. Так что это довольно сложный способ записи рекурсивной функции. Кажется, вы взяли этот пример из контекста. Дополнительная информация о контенте и некоторое объяснение того, что вы действительно пытаетесь заархивировать с помощью этого кода, будут чрезвычайно полезны. – tenshi

+3

Система типа Scala полностью завершена, и эта завершающая полнота является результатом неявного вывода. Это означает, что все, что использует неявный вывод типа, в значительной степени связано с теми же правилами, что и любая запущенная программа, среди которых невозможность предсказать окончание программы - та же самая проблема, которую вы здесь имеете. Что-то можно было сделать для простейших случаев, но не для общего случая. –

ответ

0

Вы определили foobar на be неявное значение типа 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 

что-то с немного больше элегантности, я бы используйте view bound, чтобы убедиться, что тип paramater равен 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 
+0

Учитывая первые два фрагмента кода, мне становится понятен рекурсивный характер. Ваше предложение использовать параметризованные типы вместо абстрактных типов не будет работать для меня не из-за технических проблем, а из конструктивного решения. –

+0

Мое заключение состоит в том, чтобы объявить «неявные» абстрактные члены, но ** никогда ** их определения. Правильно ли я с этим предположением? –

Смежные вопросы