13

Z tego kawałka kodu:Compiler błąd o wykres klasa jest nie finitary powodu ekspansywnie rekurencyjnego typu parametru

trait B[T] 
trait C[T] 
class A[T] extends B[A[C[T]]] 

pojawia się następujący błąd:

error: class graph is not finitary because type parameter T is expansively recursive 
     class A[T] extends B[A[C[T]]] 
      ^

Może ktoś wyjaśnić, co błąd chodzi o komunikat, dlaczego T jest nieskończenie rekursywny i dlaczego poniższy kod działa?

class A[T] extends B[A[T]] 

Odpowiedz

18

Z Scala 2.9 specification (należy pamiętać, że jest to w zmianie Zaloguj się jako zmianę, która została wprowadzona w 2.4, więc nie jest to „nowe ograniczenie” w 2.9):

The implementation of subtyping has been changed to prevent infinite recursions. Termination of subtyping is now ensured by a new restriction of class graphs to be finitary.

Kennedy and Pierce wyjaśnić dlaczego nieskończonej wykresy klasy są problemem:

Even disregarding subtyping, infinite closure presents a problem for language implementers, as they must take care not to create type representations for supertypes in an eager fashion, else non- termination is the result. For example, the .NET Common Language Runtime supports generic instantiation and generic inheritance in its intermediate language targeted by C. The class loader maintains a hash table of types currently loaded, and when loading a new type it will attempt to load its supertypes, add these to the table, and in turn load the type arguments involved in the supertype.

na szczęście, jak Kennedy i Pierce podkreślić, jest to wygodny sposób, aby sprawdzić, czy wykres jest klasa nieskończonej. Używam ich definicji w całej tej odpowiedzi.

Najpierw zrobię twoje zmienne typu odrębny dla jasności:

trait B[X] 
trait C[Y] 
class A[Z] extends B[A[C[Z]]] 

Następny skonstruować wykres zależności parametr typ korzystając Kennedy i definicję Pierce'a. Jedyną deklaracją, która doda krawędzie do wykresu, jest ostatnia deklaracja dla A. Dają następujące zasady budowania wykresu:

For each declaration C <X̄> <:: T and each subterm D<T̄> of T , if T_j = X_i add a non-expansive edge C#i → D#j ; if X_i is a proper subterm of T_j add an expansive edge C#i → D#j

Więc najpierw patrzymy na Z i C[Z], co daje nam przewagę non-ekspansywny od Z do Y. Następny Z i A[C[Z]] daje nam przewagę ekspansywny od Z do Z i Z i B[A[C[Z]]] daje nam przewagę ekspansywny od Z do X:

Graph for the bad version

Mam wskazany zakaz ekspansywne krawędzie przerywanymi strzałkami i ekspansywny krawędzie z solidnymi. Mamy cykl z ekspansywnej krawędzi, co jest problemem:

Infinitary class tables are characterized precisely by those graphs that contain a cycle with at least one expansive edge.

To nie zdarza się na class A[Z] extends B[A[Z]], który ma następujące wykresu:

Graph for the good version

widać papieru na dowodzie że stół klasy jest nieskoordynowany, ponieważ jest ekspansywny.


+3

Chciałbym móc dodać +1 do grafiki. Bardzo dobra odpowiedź. –

Powiązane problemy