2012-07-13 10 views
7

Wydaje się, że najbardziej powszechne stosowanie Scala explicitly-typed self references jest w „Cake pattern”, w którym zależności modułu są zadeklarowane jak:Przydatność wyraźnie wpisany odniesienia własnych w strukturze ciasto

class Foo { this: A with B with C => 
    // ... 
} 

W ogóle, ignorując wzór ciasto przez chwilę, A, B i C może odnosić się do niczego typ poziomu, takich jak parametr typu:

class Outer[A, B, C] { 
    class Inner { this: A with B with C => 
    // ... 
    } 
} 

... lub abstrakcyjne członkiem typ:

class Outer { 
    type A 
    type B 
    type C 
    class Inner { this: A with B with C => 
    // ... 
    } 
} 

W żadnym z tych przypadków nie mogliśmy zostać napisany abstract class Inner extends A with B with C, ponieważ A, B i C nie są znane jako cechy. W tym miejscu konieczne jest jawne wpisanie własnych odniesień. Jednak mam tylko widział wzór ciasto zrobione z cech:

trait A { def a } 
trait B { def b } 
trait C { def c } 
class Foo { this: A with B with C => 
    // ... 
} 

w tym przypadku, możemy zamiast pisać abstract class Foo extends A with B with C bezpośrednio, które, jeśli się nie mylę ma takie samo znaczenie. Mam rację? Jeśli nie, to jak się różnią; a jeśli tak, to dlaczego wszyscy wydają się używać samodzielnie wpisanego samo-odniesienia?

+0

możliwe duplikat [Jaka jest różnica między Scala samodzielnych typów i podklasy cecha?] (Http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self -types-and-trait-subclasses) – sschaef

+1

@sschaef inne pytanie, ale jeden z komentarzy Daniela pod jego odpowiedzią może być odpowiedzią, której szukam ... Wydaje się być analogicznym do "publicznego" dziedziczenia vs. dziedziczenie w C++? – mergeconflict

+0

Dla mnie oba pytania wydają się chcieć znać to samo - różnią się między sobą klasami abstrakcyjnymi a cechami, które mają ten sam kierunek. Czy też zasadniczo zrozumiałem, że coś jest nie tak? – sschaef

Odpowiedz

6

Wydaje się, że istnieją dwie główne różnice przeoczyłem:

  1. Chociaż zarówno jawne własny typ adnotacji i prosty extends kluczowe opisują „is-a” związek pomiędzy dwoma rodzajami, że związek jest nie widoczne z zewnątrz, w pierwszym przypadku:

    scala> trait T 
    defined trait T 
    
    scala> class C { this: T => } 
    defined class C 
    
    scala> implicitly[C <:< T] 
    <console>:10: error: Cannot prove that C <:< T. 
    

    to jest dobra rzecz, ponieważ w strukturze ciasto ty nie chcesz „moduł” obiekt będzie nieumyślnie polimorficznie wykorzystywane jako jedna z cech, na których zależy.

  2. As noted explicitly by Mushtaq i indirectly by Daniel, zależności mogą być cykliczne podczas używania adnotacji typu własnego. Zależności cykliczne są bardzo powszechne i niekoniecznie złe (zakładając, że współzależne komponenty nie wymagają wzajemnej inicjacji lub, że możemy między nimi być w jakiś sposób tie the knot), więc jest to kolejna wyraźna korzyść z adnotacji typu self nad dziedziczeniem.

1

Podczas korzystania z dziedziczenia podejmowane są decyzje dotyczące kolejności inicjowania. Kiedy używasz self typów, pozostawiasz to otwarte.

Istnieją inne różnice, ale myślę, że większość z nich to szczegóły implementacji i mogą zniknąć. I wiem, niektóre z nich są.

+1

Wolałbym "kiedy używasz dziedzictwa, Bóg zabija kotka". – mergeconflict

+0

Poważniejsza uwaga ... Nie rozumiem, dlaczego wspomniałeś tutaj o typach zależnych od ścieżki; czy robią różnicę w wyborze pomiędzy 'extends' vs. self types? – mergeconflict

+0

@mergeconflict Wracając myślami, rozszerzane klasy są często na najwyższym poziomie - te zagnieżdżone są zwykle nazywane w nich. Myślę, że odrzucę to z odpowiedzi, ale kolejność inicjowania jest problemem. Są inne różnice, ale wcześniej zostały skorygowane przez wyższe moce, że wiele z nich to szczegóły implementacji, a nie projektu. –