Zwroty takie jak „pisanie statyczne” i „pisanie dynamiczne” są często rzucane, a ludzie używają subtelnie różnych definicji, więc zacznijmy od wyjaśnienia, co mamy na myśli.
Rozważ język, który ma typy statyczne sprawdzane podczas kompilacji. Ale powiedzmy, że błąd typu generuje tylko ostrzeżenie nie kończące się śmiercią, aw czasie wykonywania wszystko jest zapisywane na maszynie. Te typy statyczne służą wyłącznie wygodzie programisty i nie wpływają na codegen. To pokazuje, że pisanie statyczne samo w sobie nie narzuca żadnych ograniczeń i nie wyklucza się wzajemnie z pisaniem dynamicznym. (Cel C jest podobny do tego.)
Ale większość systemów typu statycznego nie zachowuje się w ten sposób. Istnieją dwie wspólne właściwości systemów typu statycznego, które mogą nakładać ograniczenia:
Kompilator może odrzucić program zawierający błąd typu statycznego.
Jest to ograniczenie, ponieważ wiele programów typu bezpiecznego musi zawierać błąd typu statycznego.
Na przykład mam skrypt w języku Python, który musi działać zarówno jako Python 2, jak i Python 3. Niektóre funkcje zmieniły typy parametrów między Python 2 i 3, więc mam taki kod:
if sys.version_info[0] == 2:
wfile.write(txt)
else:
wfile.write(bytes(txt, 'utf-8'))
Sprawdzanie statycznego typu Python 2 odrzuciłoby kod Python 3 (i odwrotnie), nawet jeśli nigdy nie zostałoby wykonane. Bezpieczny program mojego typu zawiera błąd typu statycznego.
Jako kolejny przykład rozważmy komputer Mac, który chce działać w systemie OS X 10.6, ale skorzystaj z nowych funkcji w wersji 10.7. Metody 10.7 mogą, ale nie muszą istnieć w czasie wykonywania, i wykrycie ich zależy ode mnie, programisty. Sprawdzanie typu statycznego jest zmuszone albo odrzucić mój program, aby zapewnić bezpieczeństwo typu, albo zaakceptować program, wraz z możliwością spowodowania błędu typu (brak funkcji) w czasie wykonywania.
Statyczne sprawdzanie typu zakłada, że środowisko wykonawcze jest odpowiednio opisane w informacjach o czasie kompilacji. Ale przewidywanie przyszłości jest niebezpieczne!
Oto jeszcze jedno ograniczenie:
Kompilator może generować kod, który zakłada, że typ środowiska wykonawczego jest typem statycznym.
Zakładanie, że typy statyczne są „prawidłowe”, daje wiele możliwości optymalizacji, ale te optymalizacje mogą być ograniczające. Dobrym przykładem są obiekty proxy, np. Zdalne. Załóżmy, że chcesz mieć lokalny obiekt proxy, który przekazuje wywołania metod do rzeczywistego obiektu w innym procesie. Byłoby miło, gdyby serwer proxy był ogólny (aby mógł maskować się jako dowolny obiekt) i przezroczysty (aby istniejący kod nie musiał wiedzieć, że rozmawia z serwerem proxy). Ale aby to zrobić, kompilator nie może wygenerować kodu, który zakłada, że typy statyczne są poprawne, np. Przez statyczne wstawianie wywołań metod, ponieważ to się nie powiedzie, jeśli obiekt jest proxy.
Przykłady takiego zdalnego działania w akcji to NSXPCConnection ObjC lub TransparentProxy w języku C # (którego implementacja wymagała kilku pesymizacji w środowisku wykonawczym - patrz tutaj dyskusja).
Gdy codegen nie jest zależny od typów statycznych i masz takie funkcje, jak przekazywanie wiadomości, możesz robić wiele fajnych rzeczy z obiektami proxy, debugowaniem itp.
To jest próbka niektórych rzeczy, które możesz zrobić, jeśli nie musisz spełniać wymagań sprawdzania typu. Ograniczenia nie są narzucane przez typy statyczne, ale przez wymuszone sprawdzanie typów statycznych.