Nigdy nie rozumiałem takich stwierdzeń. Szczerze mówiąc, nawet jeśli zadeklarujesz typ zwracany przez funkcję, możesz i zapomnisz ją po napisaniu wielu wierszy kodu, i nadal będziesz musiał wrócić do wiersza, w którym został zadeklarowany za pomocą funkcji wyszukiwania edytor tekstu, aby to sprawdzić.
Nie chodzi o to, że zapomnisz o typie zwrotu - zawsze tak się stanie. Chodzi o to, że narzędzie może poinformować, że zapomniałeś typu zwrotu.
Dodatkowo, ponieważ funkcje są zadeklarowane za pomocą typu funcname()...
, bez znajomości typu będziesz musiał przeszukać każdą linię, w której funkcja jest wywoływana, ponieważ wiesz tylko, że funcname
w Pythonie i tym podobnych można po prostu wyszukać def funcname
lub function funcname
co dzieje się tylko raz , w deklaracji.
Jest to kwestia składni, która jest całkowicie niezwiązana ze statycznym pisaniem.
Składnia rodziny C jest rzeczywiście nieprzyjazna, gdy chcesz wyszukać deklarację bez posiadania specjalistycznych narzędzi. Inne języki nie mają tego problemu. Zobacz składnię deklaracji Rust:
fn funcname(a: i32) -> i32
Co więcej, w REPLs testowanie funkcji pod kątem typu zwracanego przy użyciu różnych danych wejściowych jest banalne, podczas gdy w przypadku języków o typie statycznym należy dodać kilka wierszy kodu i ponownie skompilować wszystko, aby poznać zadeklarowany typ.
Każdy język może być interpretowany, a każdy język może mieć REPL.
Więc poza znajomością typu zwracanego przez funkcję, która wyraźnie nie jest mocną stroną języków o typie statycznym, w jaki sposób pisanie statyczne jest naprawdę pomocne w większych projektach?
Odpowiem w sposób abstrakcyjny.
Program składa się z różnych operacji, które są ułożone tak, jak są, z powodu pewnych założeń programisty.
Niektóre założenia są dorozumiane, a niektóre jawne. Niektóre założenia dotyczą operacji w pobliżu, inne dotyczą operacji poza nimi. Założenie jest łatwiejsze do zidentyfikowania, gdy jest wyrażone wprost i jak najbliżej miejsc, w których liczy się jego wartość prawdy.
Błąd jest manifestacją założenia, które istnieje w programie, ale w niektórych przypadkach nie obowiązuje. Aby wyśledzić błąd, musimy zidentyfikować błędne założenie. Aby usunąć błąd, musimy albo usunąć to założenie z programu, albo zmienić coś, aby założenie faktycznie się utrzymało.
Chciałbym podzielić założenia na dwa rodzaje.
Pierwszy rodzaj to założenia, które mogą, ale nie muszą, zależeć od danych wejściowych programu. Aby zidentyfikować błędne założenie tego rodzaju, musimy szukać w przestrzeni wszystkich możliwych danych wejściowych programu. Stosując wyrafinowane domysły i racjonalne myślenie, możemy zawęzić problem i szukać w znacznie mniejszej przestrzeni. Ale mimo to, gdy program rośnie jeszcze trochę, jego początkowa przestrzeń wejściowa rośnie w ogromnym tempie - do tego stopnia, że można go uznać za nieskończony dla wszystkich praktycznych celów.
Drugi rodzaj to założenia, które zdecydowanie obowiązują dla wszystkich danych wejściowych lub są zdecydowanie błędne dla wszystkich danych wejściowych. Kiedy stwierdzimy, że tego rodzaju założenie jest błędne, nie musimy nawet uruchamiać programu ani testować żadnych danych wejściowych. Kiedy stwierdzimy, że tego rodzaju założenie jest prawidłowe, mamy jednego podejrzanego o mniejszą wagę, gdy będziemy śledzić błąd ( dowolny błąd). Dlatego warto mieć tyle założeń, ile to możliwe, należy do tego rodzaju.
Aby umieścić założenie w drugiej kategorii (zawsze prawdziwe lub zawsze fałszywe, niezależne od danych wejściowych), potrzebujemy minimalnej ilości informacji, aby były dostępne w miejscu, w którym dokonano założenia. W całym kodzie źródłowym informacje dość szybko stają się nieaktualne (na przykład wiele kompilatorów nie przeprowadza analizy międzyproceduralnej, co sprawia, że każde wywołanie stanowi twardą granicę dla większości informacji). Potrzebujemy sposobu, aby zachować wymagane informacje (aktualne i dostępne w pobliżu).
Jednym ze sposobów jest umieszczenie źródła tych informacji jak najbliżej miejsca, w którym ma zostać wykorzystany, ale w większości przypadków może to być niepraktyczne. Innym sposobem jest częste powtarzanie informacji, odnawianie ich znaczenia w kodzie źródłowym.
Jak już można się domyślić, typy statyczne są dokładnie takie - sygnały nawigacyjne informacji o typie rozproszone w kodzie źródłowym. Informacje te można wykorzystać do umieszczenia większości założeń dotyczących poprawności typu w drugiej kategorii, co oznacza, że prawie każdą operację można zaklasyfikować jako zawsze poprawną lub zawsze niepoprawną pod względem zgodności typu.
Gdy nasze typy są niepoprawne, analiza oszczędza nam czas, zwracając uwagę na błąd wcześniej, niż późno. Gdy nasze typy są poprawne, analiza oszczędza nam czas, zapewniając, że gdy wystąpi błąd, możemy natychmiast wykluczyć błędy typu.