dlaczego dokładnie robi Scala kompilator nie eksploduje z błędami?
Ponieważ ten problem nie może zostać rozwiązany w ogólnym przypadku. Czy znasz numer halting problem? Problem z zatrzymaniem mówi, że nie można napisać algorytmu, który dowiódłby, że program zostanie zatrzymany. Ponieważ problem ustalenia, czy definicja rekursywna spowodowałaby przypisanie zerowe, można zredukować do problemu zatrzymania, nie można go także rozwiązać.
Cóż, teraz jest to dość łatwe do zabronić rekurencyjne definicje w ogóle, to jest na przykład wykonywana dla wartości, które są żadne wartości klasy:
scala> def f = { val k: String = k+"abc" }
<console>:11: error: forward reference extends over definition of value k
def f = { val k: String = k+"abc" }
^
Dla wartości klasowych ta funkcja nie jest zabronione z kilku powodów :
- ich zakres nie jest ograniczony
- JVM inicjuje je z domyślnej wartości (co jest null dla typów referencyjnych).
- wartości rekurencyjne są użyteczne
Twój przypadek użycia jest trywialne, jak to:
scala> val k: String = k+"abc"
k: String = nullabc
Ale co o tym:
scala> object X { val x: Int = Y.y+1 }; object Y { val y: Int = X.x+1 }
defined object X
defined object Y
scala> X.x
res2: Int = 2
scala> Y.y
res3: Int = 1
scala> object X { val x: Int = Y.y+1 }; object Y { val y: Int = X.x+1 }
defined object X
defined object Y
scala> Y.y
res4: Int = 2
scala> X.x
res5: Int = 1
Albo to:
scala> val f: Stream[BigInt] = 1 #:: 1 #:: f.zip(f.tail).map { case (a,b) => a+b }
f: Stream[BigInt] = Stream(1, ?)
scala> f.take(10).toList
res7: List[BigInt] = List(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
Jak widać, dość łatwo jest pisać programy, w których nie jest już oczywiste, do jakiej wartości one doprowadzą. A ponieważ problemu nie można rozwiązać, nie możemy pozwolić, aby kompilator wykonał dla nas pracę w nieważnych przypadkach.
Oznacza to również, że przypadki trywialne, takie jak te przedstawione w pytaniu, mogą zostać zakodowane na stałe w kompilatorze. Ponieważ jednak nie może istnieć algorytm, który może wykryć wszystkie możliwe, trywialne przypadki, wszystkie przypadki, które kiedykolwiek zostały znalezione, muszą zostać zakodowane na stałe w kompilatorze (nie wspominając o tym, że definicja przypadku trywialnego nie istnieje). Dlatego nie byłoby rozsądnie nawet zacząć kodowanie niektórych z tych przypadków. W rezultacie spowolniłoby to kompilator i kompilator, który jest trudniejszy do utrzymania.
Można argumentować, że w przypadku użycia, który spala co sekundę użytkownika, rozsądnie jest przynajmniej zakodować tak ekstremalny scenariusz. Z drugiej strony, niektórzy ludzie muszą być spaleni, aby nauczyć się czegoś nowego. ;)
w Scala 2.11.4 Mam wojnę ning 'warning: nazwa wartości w obiekcie WTF robi nic innego, jak wywoływanie samej nazwy rekursywnie: String = name' – Brian
Używam Scala 2.11.7, i nie dostaję tego komunikatu i nie ma rekurencji, ponieważ jest to val: czy na pewno nie używasz * def *? Czy uruchamiasz go z wiersza poleceń lub z interpretera? Używam Intellij –
Właśnie zauważyłem, że nie powiedzie się w REPL z następującym komunikatem .. scala> val o: String = o: 8: ostrzeżenie: wartość o nie wywołuje sam siebie rekursywnie –