(Dis-) zalety typowania strukturalnego

15

Właśnie obejrzałem tę rozmowę Daniela Spiewaka, w której mówi on o zaletach pisania strukturalnego w porównaniu do nominalnego pisania Scali i Java . Przykładem tej różnicy może być następujący kod Java

public interface Foo {
  public int length();
}
public interface Bar {
  public int length();
}

Foo f = ...;
Bar b = f;

które oczywiście nie skompilowałyby się, ponieważ zgodność typu pomiędzy FooiBar jest określana przez nazwę.

Z drugiej strony system typów strukturalnych może zadeklarować, że oba typy są równe lub kompatybilne, a zatem między innymi umożliwiać sprawdzanie typowania kaczek.

Teraz myślę, że rozumiem większość zalet systemu typów strukturalnych, ale zastanawiam się, czy nie unieważniłoby to bezpieczeństwa typu z przykładów takich jak poniżej

class Foo {
  class Bar { /* ... */ }
  def takeBar(b: Bar) = { /* ... */ }
  def getBar: Bar = new Bar
}

val foo1 = new Foo
val foo2 = new Foo
foo1.takeBar(foo1.getBar) // should compile
foo1.takeBar(foo2.getBar) // should not compile

Czy dobrze rozumiem, że w systemie typu strukturalnego kompiluje się również ostatnia linia, a jeśli tak, to czy nie byłoby to niekorzystne z punktu widzenia bezpieczeństwa typu?

Debilski
źródło
3
Czy możesz wyjaśnić, dlaczego ostatnia linia nie powinna się skompilować? Nie widzę niezgodności typu.
Sam Goldberg,
2
Jest to typ zależny od ścieżki Scala .
Debilski,
Właściwie chciałem to omówić z punktu widzenia systemu typu Scala. Tak się złożyło, że jedynym przykładem podanym w wykładzie była Java.
Dębilski,

Odpowiedzi:

12

W rzeczywistości typy zależne od ścieżki są prostopadłe do strukturalnego vs. nominalne. Nie jest do końca jasne, co oznacza klasa wewnętrzna w kontekście prostego języka o typie strukturalnym. Jest jednak bardzo możliwe do zdefiniowania to . Jeśli miałbyś zdefiniować klasy wewnętrzne w kontekście strukturalnie typowanym, musisz upewnić się, że przypadki takie jak ta, którą wymieniłeś, zostaną odrzucone (z dokładnie tych samych powodów, dla których Scala je odrzuca).

Odrzuciłbyś takie przypadki, robiąc to samo, co robi Scala: zamodeluj typ zależny od ścieżki jako typ egzystencjalny. Ta sama procedura pakowania / rozpakowywania otaczająca dostęp do obiektów byłaby wstrzymana, a wyniki wyglądałyby prawie identycznie jak robi Scala. Wyniki mogą wydawać się nominalną równością typów, ale nadal byłby to strukturalny system typów, ponieważ kwestia zgodności typów będzie nadal rozstrzygana raczej na podstawie interfejsu niż nazwy.

Typowanie strukturalne ma wiele implikacji, ale (być może zaskakujące) większość tych samych pojęć, które wszyscy znamy i uwielbiamy z systemów typu nominalnego, przechodzi w strukturę. Pisanie strukturalne jest niczym innym jak innym sposobem definiowania zgodności typów.

Daniel Spiewak
źródło
0

Wpisywanie strukturalne ułatwia pisanie ogólnego kodu bibliotecznego. Głównym powodem, dla którego ekosystem Java jest tak rozdęty, jest to, że trudno jest łatwo pisać małe biblioteki. Gdyby Java była strukturalnie wpisana, myślę, że byłaby to inna historia i znacznie lepsza sytuacja.

Jedyną wadą, jaką mogę wymyślić przy typowaniu strukturalnym, jest możliwość wolniejszej kompilacji. Nie jestem pewien, czy języki strukturalne generalnie kompilują się wolniej niż te nominalne, czy nie, ale na przykład Golang jest strukturalnie pisany i bardzo szybki w kompilacji.

Alexander Mills
źródło