2013-08-06 10 views
6

Say mam:Dlaczego ta składnia parametru typu nie jest kompilowana?

class Class[CC[A, B]] 
class Thing[A, B <: Int] 
class Test extends Class[Thing] // compile error here 

pojawia się błąd kompilatora:

kinds of the type arguments (cspsolver.Thing) do not conform to the expected kinds of the type parameters (type CC) in class Class. cspsolver.
Thing's type parameters do not match type CC's expected parameters: type C's bounds <: Int are stricter than type B's declared bounds >: Nothing <: Any

Jednak kiedy zmodyfikować kod tak, że wygląda to tak:

class Class[CC[A, B]] 
class Thing[A, B] { 
    type B <: Int 
} 
class Test extends Class[Thing] 

kompiluje grzywny. Czy nie są one funkcjonalnie równoważne?

+5

W ostatnim przykładzie masz typ parametru 'B' i typ członka' B'. Mają takie samo imię (tak, że tylko jeden jest widoczny), bot nie są takie same. – senia

+0

@senia, czy istnieje przypadek, gdy użycie tej samej nazwy jest przydatne? – huynhjl

+0

@huynhjl: Chyba nie. Ale w niektórych przypadkach shadowing jest użyteczny: możesz ponownie użyć nazwy. W przypadku implikacji istnieją również częściowe, przydatne nadużywanie shadowingu: patrz [ta odpowiedź] (http://stackoverflow.com/a/17852226/406435). – senia

Odpowiedz

1

Przyczyna jest podana w komunikacie kompilatora. W wersji Class użytkownik oczekuje nieograniczonego numeru CC, natomiast Thing ma ograniczenie, że argumentem drugiego typu musi być <: Int. Jedną z możliwości jest dodanie samo ograniczenie do Class jak w

class Class[CC[A,B <: Int]] 
class Thing[A, B <: Int] 
class Test extends Class[Thing] 
+0

Nie jest dla mnie jasne, dlaczego to ograniczenie jest na miejscu, dlaczego kompilator nie może pogodzić tych dwóch przy dolnej granicy? –

0

Opracowanie na wyjaśnienie Petr Pudlák, oto co Zakładam dzieje: kompilator próbuje ujednolicić CC[A, B] z Thing[A, B <: Int]. Zgodnie z deklaracją B w górnej granicy typu jest Any, która jest wybierana do utworzenia B. Oczekuje się jednak, że B w Int będzie miało górny typ, a zatem kompilator nie powiedzie się z otrzymanym komunikatem o błędzie.

Jest to konieczne w celu zachowania stabilności systemu typu, jak pokazano na poniższym szkicu. Zakładamy, że Thing określa operację, która opiera się na fakcie, że jego B <: Int np

class Thing[A, B <: Int] { 
    def f(b: B) = 2 * b 
} 

Jeśli zadeklarowana Class jak

class Class[CC[A,B]] { 
    val c: CC 
} 

i Test jak

class Test extends Class[Thing] { 
    val t: Thing 
} 

bez kompilator skarży , możesz wykonać następujące połączenie:

new Test().t.f(true) 

co oczywiście nie jest bezpieczne.

+0

Nie jestem przekonany, że masz ważny przykład dlaczego "zezwalanie na takie ograniczenie typu do kompilacji" zawiedzie ... ale ponieważ nie skompilowałoby się nawet, trudno jest dokładnie określić, dlaczego jest błędne! –

+0

Ale spróbuję w każdym razie: 'def f (b: B) ...' jest w kontekście 'B <: Int'. Więc nie kupuję, że w żadnych okolicznościach 'f (true)' może ewentualnie się skompilować. –

+0

Nie jestem pewien, czy śledzę, dlaczego 'new Test(). T.f (true)' nie zostanie przechwycony podczas kompilacji. W 'Testie' nie ma parametrów typu" t "? A gdyby tak nie było, to 'nowy test(). T' return' Thing [A, B <: Int] ', tak aby kompilator wiedział,' nowy test(). Tf' pobiera 'B <: Int' i że 'Boolean' nie jest' <: Int'? – eddiemundorapundo

Powiązane problemy