W systemie z dynamicznym typowaniem wartości mają typy w czasie wykonywania, ale zmienne i funkcje nie. W systemie o typie statycznym zmienne i funkcje mają typy znane i sprawdzane podczas kompilacji. Np. W Pythonie x
może być wszystko ; w czasie wykonywania, jeśli jest 1
to liczba, a jeśli tak "foo"
, to ciąg. Będziesz wiedział tylko, który typ x
był w czasie wykonywania, i może być inny przy każdym uruchomieniu programu. W języku takim jak Java piszesz, int x
jeśli x
ma być liczbą, i wiesz, że w czasie kompilacji x
zawsze musi to być int
.
Oba typy „jawne” i „niejawne” odnoszą się do systemów typu statycznego . Cechą charakterystyczną systemu statycznego jest to, że typy są znane w czasie kompilacji, ale niekoniecznie muszą być zapisane. W Javie typy są jawne - musisz je zapisać. W Javie metoda może wyglądać mniej więcej tak:
public int foo(String bar, Object baz) { ... }
Typy są znane zarówno w czasie kompilacji (statyczne), jak i zapisywane (jawne). Istnieją jednak języki, które nie zmuszają Cię do napisania tego typu. Mogą wywnioskować rodzaj funkcji na podstawie jej ciała i sposobu jej użycia. Przykładem może być OCaml, w którym możesz napisać coś takiego:
let foo x = x + 1
Odkąd +
używałeś, OCaml może zorientować się, że x
to int
wszystko musi być samo w sobie. Tak więc typ foo
( foo : int -> int
) jest znany w czasie kompilacji, podobnie jak przykład Java. Jest całkowicie statyczny. Ponieważ jednak kompilator może samodzielnie ustalić, jakie typy muszą być, nie musisz sam ich zapisywać: są niejawne.
W skrócie: to, czy system typów jest jawny czy niejawny, jest własnością systemów statycznych . Jest to zupełnie inne pytanie, czy system typów jest dynamiczny czy statyczny.
Często masz systemy typów, które są czasami jawne, a czasem niejawne.
Na przykład uważam, że C # pozwala wnioskować typy za pomocą var
słowa kluczowego. Zamiast pisać int x = 10
, możesz pisać, var x = 10
a kompilator odkrywa, że to x
musi być int
. C ++ robi coś podobnego z auto
. Systemy te są zwykle jawne, ale mają pewne wnioski.
Z drugiej strony istnieją systemy, które są zwykle niejawne, ale czasami zmuszają cię do napisania podpisu typu. Haskell jest świetnym przykładem. Przez większość czasu Haskell może wnioskować o typach dla Ciebie. Czasami jednak możesz napisać dwuznaczny kod show . read
, w którym Haskell nie jest w stanie samodzielnie rozróżnić typów. W tym przypadku można byłoby zmuszone do jednoznacznie określić typ albo show
albo read
. Ponadto niektóre bardziej zaawansowane funkcje systemu typów (takie jak polimorfizm rangi n) powodują, że wnioskowanie jest nierozstrzygalne - to znaczy nie ma gwarancji, że się zatrzyma. Oznacza to, że kod korzystający z tej funkcji często wymaga wyraźnych podpisów typu.