Skąd kompilatorzy wiedzą o innych klasach i ich właściwościach?

14

Piszę swój pierwszy język programowania, który jest zorientowany obiektowo i do tej pory dobrze tworzy pojedynczą „klasę”. Ale powiedzmy, że chcę mieć lekcje, powiedz ClassAi ClassB. O ile ci dwaj nie mają ze sobą nic wspólnego, wszystko jest dobrze. Powiedzmy, że ClassAtworzy - ClassBto stawia 2 powiązane pytania:

-Jak to know kompilator podczas kompilacji ClassA, że ClassBw ogóle istnieje, a jeśli tak, to w jaki sposób to wie, że to właściwości?

Moje dotychczasowe przemyślenia brzmiały: zamiast kompilować każdą klasę na raz (tj. Skanować, analizować i generować kod) każdy „plik (nie tak naprawdę plik, sam w sobie, ale„ klasa ”), muszę najpierw skanować + parsować , a następnie wygenerować kod dla wszystkich?

OnResolve
źródło

Odpowiedzi:

13

Różne języki (a więc i kompilatory) podchodzą do tego inaczej.

W rodzinie C różne moduły mają odpowiedni plik nagłówka, który jest używany podczas budowania obiektu. Pliki nagłówkowe zawierają informacje o rozmiarze obiektu oraz o funkcjach i metodach, które można wywołać. Pozwala to na uzyskanie niezbędnych informacji do przydzielenia pamięci i „czy ta metoda / funkcja / procedura istnieje?” używane podczas kompilacji pojedynczej jednostki, która nie musi mieć dostępu do samego źródła.

W Javie kompilator jest świadomy rzeczy na swojej ścieżce klas i sprawdza te obiekty, aby połączyć się z nimi (sprawdzając, czy istnieją metody, mają odpowiednią liczbę argumentów itp.). Java może również dynamicznie łączyć się podczas ładowania środowiska wykonawczego z innymi klasami, o których nie wie nic, kiedy została skompilowana. Zobacz Class.forName dla jednego przykładu ładowania dynamicznego.

Obie opcje są dość aktualne i mają własny zestaw zalet i wad. Udostępnianie plików nagłówkowych może być uciążliwe i narusza DRY . Z drugiej strony, jeśli nie masz plików nagłówkowych, biblioteki muszą być sprawdzalne przez kompilator i linker - plik .so lub .dll prawdopodobnie nie będzie zawierał wystarczającej ilości informacji, aby poprawnie utworzyć instancję obiektów lub zweryfikować wywołania metod ( i zależy od maszyny).

Społeczność
źródło
0

Praktycznie rzecz biorąc, w Javie IDE patrzy na cały program jednocześnie; gdy odwołuje się do ClassB, kompilator IDE na to spojrzy. Wszystko, łącznie z bibliotekami, stanowi jedną kompletną całość. Gdy program będzie gotowy, możesz zmieniać ścieżki klas, zamieniać i zamieniać poszczególne pliki .class oraz przełączać wersje bibliotek. Możesz także skompilować pojedyncze pliki .java bez użycia IDE (lub w jakiś sposób unikając jego sprawdzania). Wynik nie musi być spójna w ogóle, a jeśli to nie ty będziesz się run-time wyjątki. (Jedną z wielu rzeczy, które IDE próbuje dla ciebie zrobić, jest przekształcenie błędów w czasie wykonywania w błędy w czasie kompilacji, a raczej w błędy w czasie edycji).

C # jest mniej więcej taki sam i nie sądzę, że C i C ++ są tak różne, ponieważ Java i C # IDE robią po prostu tworzenie nagłówków w stylu C / C ++ za kulisami.

RalphChapin
źródło
W razie potrzeby kompilatory Java również kompilują rzeczy zależne. Otrzymujesz wyjątki czasu wykonywania od tego rodzaju rzeczy tylko wtedy, gdy naprawdę bardzo próbowałeś wymusić różne rzeczy (np. Zmianę i rekompilację interfejsu API po skompilowaniu odbiorców tego interfejsu API).
Donal Fellows
@DonalFellows: W moich problemach brakuje bibliotek („Ale umieściłem ten na wszystkich moich komputerach!”) I ponownie kompilowałem działające programy (niezamierzone wymiany plików .class podczas pracy). Mogę przewidzieć aktualizację pakietów, które nie pasują już do głównego programu, chociaż jeszcze tego nie zrobiłem. I nie zrobić wiele, że z C i .dll (oraz gdyby mi zrobili) lat temu. Wierzę i mam nadzieję, że istnieje teraz wiele zabezpieczeń, których wtedy nie było.
RalphChapin
Naprawdę nie rozumiem, co IDE ma wspólnego z tym, jak kompilator / linker wie, jak rozwiązać problemy z kompilacją / linkerem. Popraw mnie, jeśli się mylę, ale IDE jest całkowicie ortogonalne w stosunku do całego problemu (z wyjątkiem tego, że ułatwia zadanie programistom). Dlaczego? Ponieważ teoretycznie IDE używa kompilatora w tle.
Thomas Eding
@ThomasEding: Masz całkowitą rację. Kiedy odpowiedziałem na to pytanie, miałem problem z oddzieleniem IDE od kompilatora / linkera. Moja wymówka: Java nie „łączy”, dopóki się nie uruchomi, więc nie może wiedzieć, że odwołanie do klasy lub wywołanie metody jest nieprawidłowe do tego czasu; IDE tak naprawdę nie „ułatwia” mojego zadania, ale umożliwia. Użyłem (w FORTRAN i C, dawno temu), aby uzyskać błędy, kiedy kompilowałem, kiedy łączyłem, a potem kiedy działałem. Teraz prawie wszystkie te błędy są poprawne, gdy je wpisuję, co sprawia, że ​​IDE jest w pewnym sensie kompilatorem, linkerem i programem wykonawczym. Obecnie wszystkie błędy niezwiązane z uruchomieniem pochodzą z IDE.
RalphChapin
0

Starsze języki są czasami bardziej surowe; zastanów się, co jest możliwe w Javie:

public interface Ifc {
    public static final Ifc MY_CONSTANT = new Implem();
}

public class Implem implements Ifc {
}

Widziałem anty-wzór powyżej i jest naprawdę brzydki (zabroniłbym go). Obie jednostki kompilacji używają się nawzajem. Ale Ifc można skompilować do kodu bez skompilowanego Implem. Skompilowany kod .class, porównywalny z C.obj, zawiera „informacje o powiązaniach:” import Implem, wywołujący konstruktor bez parametrów Implem(). Klasa Implem może być następnie skompilowana bez problemu. Częściowo ClassLoader - wykonując inicjalizację / kompilację danych klasy JVM, a częściowo samą wirtualną maszynę Java, gra trochę jako linker , integrując wszystko.

Na przykład kompilacja z jedną wersją określonej biblioteki i uruchomienie z inną wersją tej biblioteki rozpoznaje błędy w czasie wykonywania.

Tak więc odpowiedź: Kompilacja dostarcza jednostki skompilowanego kodu obiektowego, który należy traktować jako kod + dane + API do łączenia ze sobą.

Kompilator powinien potem również zrobić pakowanie razem i zweryfikować API powiązania; druga faza.

Może to irytować i wyglądać nieelegancko, ale matematyczne dowody mogą działać w ten sam sposób: dowodząc całej poprawności, można już rozważyć część, która jest prawdziwa aż do weryfikacji.

Joop Eggen
źródło