Jeśli używam un uszczelniony trait
lub abstract class
w Scala, a następnie użyć dopasowywania wzorców, zastanawiam się, czy kompilator nie wiedzieć w czasie kompilacji dla tego konkretnego patternmatch co możliwe implementacje tej cechy / klasy są dostępne? Więc jeśli tak, to czy nie może dać ostrzeżeń o dopasowaniu wzorca, nawet jeśli trait
/ abstract class
nie jest zapieczętowane, ponieważ wie, które typy mogą być użyte, sprawdzając wszystkie możliwe zależności / import?
Np. Jeśli mam Option[A]
i wykonuję dopasowanie wzorca tylko dla, Some[A]
ale nie dla None
, kompilator będzie narzekał, ponieważ Option
jest zapieczętowany.
Jeśli kompilator nie może tego wiedzieć / rozwiązać, dlaczego nie może? A jeśli kompilator (teoretycznie) może to zrobić, jakie są przyczyny tego, że nie jest używany w Scali? Czy istnieją inne języki, które wspierają takie zachowanie?
źródło
Foo
z podklasA
,B
iC
, i wszystkie swoje mecze wzór pasuje tylko te trzy. Nic nie powstrzymuje mnie przed dodaniem nowej podklasy,D
która wysadzi twoje pasujące wzory.java.lang.ClassLoader
.Odpowiedzi:
Wyodrębnienie wszystkich podklas klasy nazywa się analizą hierarchii klas, a wykonanie statycznego CHA w języku z dynamicznym ładowaniem kodu jest równoznaczne z rozwiązaniem problemu zatrzymania.
Ponadto jednym z celów Scali jest osobna kompilacja i wdrożenie niezależnych modułów, więc kompilator po prostu nie może wiedzieć, czy klasa jest podklasowana w innym module, ponieważ nigdy nie patrzy na więcej niż jeden moduł. (W końcu możesz skompilować moduł z interfejsem jakiegoś innego modułu, nawet jeśli ten moduł nie istnieje nawet w twoim systemie!) Dlatego właśnie
sealed
wymaga zdefiniowania wszystkich podklas w tej samej jednostce kompilacji.Jest to również jeden z powodów, dla których maszyny JVM mogą tak korzystnie konkurować z kompilatorami C ++: kompilatory C ++ są zwykle kompilatorami statycznymi, więc ogólnie nie mogą dowiedzieć się, czy metoda jest zastąpiona, czy nie, i dlatego nie mogą jej inline. JVM OTOH, zwykle są dynamicznymi kompilatorami, nie muszą przeprowadzać CHA, aby dowiedzieć się, czy metoda jest nadpisana, czy nie, mogą po prostu spojrzeć na hierarchię klas w czasie wykonywania. I nawet jeśli na późniejszym etapie wykonywania programu pojawi się nowa podklasa, której wcześniej nie było, to nic wielkiego, po prostu ponownie skompiluj ten fragment kodu bez inlinizacji.
Uwaga: wszystko to dotyczy tylko Scali. JVM nie ma pojęcia
sealed
, więc można całkowicie podklasowaćsealed
klasy z innego języka JVM, ponieważ nie ma sposobu na przekazanie tego w innym języku.sealed
Nieruchomość jest wpisana doScalaSig
adnotacji, ale kompilatory inne języki nie biorą pod uwagę te adnotacje, oczywiście.źródło
To może być wykonane (przynajmniej dla wszystkich klas znane w czasie kompilacji), to jest po prostu drogie. Całkowicie zniszczyłbyś kompilację przyrostową, ponieważ wszystko, co zawiera dopasowanie wzorca, musiałoby być skutecznie rekompilowane przy każdej zmianie innego pliku.
A co kupujesz Zapach kodowy służy do pisania dopasowań wzorców, które muszą się często zmieniać po dodaniu nowej klasy pochodnej. Jest to naruszenie zasady otwartej / zamkniętej . Używaj dziedziczenia poprawnie i nie będziesz musiał pisać tego rodzaju dopasowań wzorców. I tak, zasada otwarta / zamknięta dotyczy również języków funkcjonalnych bez dziedziczenia klasowego. W rzeczywistości między funkcjami, takimi jak klasy typów, multimetody i zwykłe funkcje wyższego rzędu, języki funkcjonalne znacznie ułatwiają rozszerzanie bez modyfikacji.
źródło
It can be done (at least for all classes known at compile time), it's just expensive.
Ale jeśli program nie jest w 100% samowystarczalny (tzn. Zależy od.jar
plików zewnętrznych ), czy nie mógłbyś wkraść się do nowej podklasy po kompilacji za pomocą jednego z nichjar
? Kompilator może więc powiedzieć „Twoje dopasowania wzorca są teraz wyczerpujące, ale może się to zmienić, jeśli zmieni się którakolwiek z twoich zależności”, co jest dość bezwartościowe, ponieważ zależność zewnętrzna ma być w stanie zaktualizować je bez ponownej kompilacji!