Typový systém lze v informatice definovat jako „tvárný syntaktický rámec pro klasifikování výrazů podle toho, jaký druh hodnoty vypočítávají“. Typový systém porovnává datové typy a výpočty ve výrazech a tím umožňuje zajistit, že nedojde k typovým chybám. Různé operace očekávají různé datové typy a typový systém zajišťuje, aby nebyly použity hodnoty, pro které nemá operace smysl.
Kompilátor může k uložení hodnoty použít staticky definovaný datový typ a pak na ni aplikovat příslušný typ výpočtu. Například kompilátor jazyka C používá datový typ float, který je podle IEEE 754 reprezentován jako 32bitové číslo, a používá pro něj speciální strojové instrukce určené pro výpočty s pohyblivou řádovou čárkou.
Úroveň typových omezení a způsob jejich posuzování mají vliv na typování daného programovacího jazyka. Programovací jazyk může v případě typového polymorfizmu přiřadit každému typu další operace s různými konkrétními algoritmy. Teorie typů řeší typové systémy, i když konkrétní typové systémy vycházejí z praktických otázek jako je architektura počítače, implementace překladače a konstrukce programovacího jazyka.
Základy Přiřazování datových typů (tj. typování) dává význam sekvencím bitů. Typy se obvykle asociují s hodnotami v paměti nebo objekty jako jsou proměnné. Jelikož je každá hodnota v počítači pouze sekvence bitů, hardware proto nedokáže na tomto základě sám rozlišovat mezi adresou v paměti, kódem instrukce, znakem, celým číslem, číslem s plovoucí řádovou čárkou atd. Jak má sekvence bitů chápat, určuje programátor v programu prostřednictvím datových typů.
V dnešních jazycích programátor pracuje s abstraktnějšími typy než je bit a konkrétní implementace pomocí (ne nutně sekvence) bitů ho zpravidla nezajímá. Tu určuje tvůrce kompilátoru. Pro programátora je podstatné, že z bitové reprezentace lze jednoznačně rekonstruovat původní hodnotu. Samozřejmě konkrétní implementace se projevuje, např. v rozsahu čísel a znaků, nepřenositelnosti programů apod.
Mezi hlavní funkce poskytované typovým systémem patří: Bezpečnost Použití typů dovoluje kompilátoru detekovat nesmyslný nebo pravděpodobně neplatný kód. Například, můžeme identifikovat výraz 3/„Hello World“ jako neplatný, protože aritmetická pravidla nespecifikují, jak dělit celé číslo řetězcem. Silná typová kontrola nabízí větší bezpečnost, nezaručuje však úplnou bezpečnost (více informací viz typová bezpečnost). Optimalizace Statická typová kontrola může poskytovat důležité kompilační informace. Například, když typ vyžaduje, že hodnota musí být násobkem 4 bajtů, může kompilátor použít efektivnější strojovou instrukci. Dokumentace Ve více expresivních typových systémech mohou typy sloužit i jako určitá forma dokumentace, neboť mohou ilustrovat záměry programátora. Například časová razítka mohou být reprezentována jako celá čísla – ale když programátor deklaruje funkci, která vrací hodnotu typu časové razítko (timestamp), místo celého čísla (integer), pak tato část informuje o významu funkce. Abstrakce (nebo modularita) Typy dovolují programátorům přemýšlet o programech na vyšší úrovni, než jsou bity nebo bajty a nemusí se obtěžovat s nízkoúrovňovou implementací. Například umožňuje programátorovi dívat se na řetězce jako na soubor znaků a ne jako na pouhé pole bajtů nebo umožňuje vyjádřit rozhraní mezi dvěma subsystémy. To pomáhá lokalizovat definice potřebné pro interoperabilitu subsystémů a zabraňuje nesrovnatelnostem při komunikaci těchto subsystémů.
Program obvykle sdružuje jednotlivé hodnoty s jedním konkrétním typem (i když typ může mít víc než jeden podtyp). Jiné entity, jako jsou objekty, moduly, komunikační kanály, závislosti nebo dokonce samy typy se mohou spojit s typem. Některé implementace se označují následujícími označeními (i když se jedná o technicky odlišné pojmy): datový typ – typ hodnoty třída – typ objektu kind – typ typu
Typový systém, který je stanovený pro každý programovací jazyk, hlídá chování napsaných programů a zakazuje chování mimo tato pravidla. Účinný systém obvykle poskytuje jemnější ovládání než je typový systém.
Formálně teorie typů studuje typové systémy. Komplikovanější systémy (např. závislé typy), umožňují pro jemněji zrnité programové specifikace ověření typovou kontrolou, za cenu toho, že typ nebo jiné vlastnosti budou nerozhodnutelné a kontrola typu je závislá na uživateli dodaných důkazech. Je náročné najít dostatečně expresivní typový systém, který splňuje bezpečným způsobem všechny programové praktiky v typové bezpečnosti, jak výstižně řekl Mark Manasse:Pierce, Benjamin C. (2002), p. 208
Tento zásadní problém řešíme pomocí teorie typů, abychom se ujistili, že programy mají smysl. Zásadním problémem této teorie je, že programy nemusí mít význam, který je jim připisován. Z toho vyplývá, že se snažíme hledat bohatší typové systémy.
Typy a správnost
Typová kontrola přispívá k správnosti programu (správnosti programu), ale nemůže ji zaručit, protože kontroluje „pouze“ typy. V závislosti na konkrétním typovém systému může vydat program špatný výsledek, i když je správně napsaný (asi myšleno typově správně) a kompilátor nehlásí žádné chyby. Například dělení nulou u většiny programovacích jazyků nespadá do typové kontroly, ale je to běhová chyba. Pokud chceme dokázat, že je program bez obecnějších vad, použijeme k tomu jiné druhy formálních metod známé jako analýza programu. Formální metody jsou při vývoji a testování softwaru široce používanou empirickou metodou pro zjištění chyb, které typová kontrola nemůže odhalit.
Některé úlohy typového odvozování jsou i nerozhodnutelný problém.
Typová kontrola K ověřování a omezování typů – typové kontrole – dochází buď při kompilaci (statická kontrola) nebo za běhu (dynamická kontrola). Pokud specifikace jazyka vyžaduje silnou typovou kontrolu (to zn. více či méně umožňuje pouze automatické typové konverze, které neztrácí informace), můžeme říct, že je proces silně typovaný, pokud ne, pak je slabě typovaný. Tyto pojmy však nejsou používány v striktním slova smyslu.
Statická typová kontrola Programovací jazyk používá statickou typovou kontrolu, když se typová kontrola provádí při kompilaci na rozdíl od běhu. Mezi staticky typované jazyky patří ActionScript 3, Ada, C, C++, C#, D, Eiffel, F#, Fortran, Go, Haskell, JADE, Java, ML, Objective-C, OCaml, Pascal, Perl (s ohledem na rozlišení skalárů, polí, hashí a subrutin) a Scala. Statická typová kontrola je omezená forma ověření správnosti programu (viz typová bezpečnost), protože umožňuje zachytit mnoho chyb typů už v rané fázi vývoje. Statická typová kontrola vyhodnotí informace o typech, které budou stanoveny při kompilaci a navíc je schopná ověřit, že podmínky budou platit pro všechna spuštění programu a tím se eliminuje potřeba provádět typovou kontrolu při každém spuštění. Tím, že vynecháme typovou kontrolu při běhu, může být běh programu efektivnější (tj. rychlejší nebo se sníží nároky na paměť) a umožní to další optimalizace.
Jelikož se určují informace o typu už při kompilaci, nemají statické kontroly typu informace o typech, které jsou k dispozici jen při běhu programu, proto musí být kontrola opatrná. Musí odmítnout programy, které se správně chovají až při běhu, protože správné typy nelze určit staticky. Například máme výraz <complex test>, který je při běhu vždy vyhodnocen jako true, program obsahuje kód
if <complex test> then 42 else <type error>
bude zamítnuto jako špatný typ, protože statická analýza nemůže určit jestli nebude vybrán příkaz else. Konzervativní chování statických kontrol je výhodné, jestliže <complex test> bude vyhodnocen jako false jen zřídka: Statická typová kontrola dokáže detekovat chybu typu v málo používaných větvích programu. Bez statické kontroly se ani u kódu, který je na 100% pokryt testy nemusí povést takovou chybu objevit. Testy mohou mít problémy s rozpoznáním tohoto druhu chyb, protože musíme brát v úvahu kombinace všech míst, kde jsou hodnoty vytvořeny a kde jsou používány.
Nejpoužívanější staticky typované jazyky nejsou formálně typově bezpečné. Mají „mezery“ ve specifikaci programovacího jazyka, které umožňují programátorům psát kód, který obchází statickou kontrolu typů, a tak může nastat další škála problémů. Například většina C jazyků obsahuje type punning a Haskell má vlastnosti jako unsafedPerformIO: takové operace mohou být nebezpečné za běhu tím, že mohou způsobit nežádoucí chování způsobené nesprávným zadáním hodnot.
Pro statickou typovou kontrolu není rozhodující, zda a jak často programátor musí do zdrojového kódu typy psát. Podstatné je, že se typy dají určit během kompilace. Pokud je píše, kompilátor má jednodušší práci a vystačí si s typovou kontrolou, jinak musí využít typové odvozování (jinde řčeno typové usuzování).
Dynamická typová kontrola O programovacím jazyce řekneme, že je dynamicky typovaný, když je většina typové kontroly prováděna za běhu, místo při kompilaci. Při dynamické typové kontrole mají typy hodnoty, ale ne proměnné a to znamená, že proměnná může ukazovat na hodnotu jakéhokoli typu. Jazyky s dynamickou typovou kontrolou jsou například APL, Erlang, Groovy, JavaScript, Lisp, Lua, Matlab/GNU Octave, Perl (pro uživatelsky definované typy, ne však pro vestavěné typy), PHP, Prolog, Python, Ruby, Smalltalk, Tcl a Clojure.
Implementace dynamicky typovaných jazyků obyčejně spojuje run-time objekty s „tagy“, které obsahují informace o jejich typu. Tyto run-time klasifikace se používají k implementaci typových kontrol a expedují přetížené funkce, ale můžeme také využít dynamické ovládání, pozdní vazbu a podobné styly, které by byly ve staticky typovaném jazyce přinejmenším těžkopádné, protože vyžadují použití variantních typů nebo podobných vlastností.
Obecněji, jak je vysvětleno níže, může dynamická typová kontrola vylepšit podporu dynamických vlastností programovacího jazyka jako jsou generování typů a funkce založené na run-time datech. (Přesto dynamicky typované jazyky nemusí podporovat některé nebo dokonce žádné tyto funkce a některé dynamické programovací jazyky jsou dokonce staticky typované). Na druhou stranu dynamické typování poskytuje a priori záruk: dynamicky typovaný jazyk přijímá a pokouší se spustit i programy, které by byly při statické kontrole posouzeny jako neplatné a to buď kvůli chybě v programu nebo kvůli tomu, že statická typová kontrola je příliš konzervativní.
Dynamická typová kontrola může vést na runtime chyby, to znamená že hodnota může mít za běhu nečekaný typ a je na ní aplikována neplatná operace. Takové chyby se mohou vyskytnout až daleko za místem, kde je programovací chyba, neboli místa, kde dostala data nesprávný datový typ. Chyby tohoto typu se většinou špatně objevují.
Runtime kontroly dynamických jazykových systémů mohou být potenciálně složitější než kontroly staticky typovaných jazyků, jelikož mohou použít dynamické informace i veškeré informace ze zdrojového kódu. Nicméně runtime kontrola uplatňuje podmínky jen při konkrétním spuštění a kontroly se opakují při každém spuštění programu.
Při vývoji v dynamicky typovaných jazycích se často používají nejrůznější programovací praktiky, jako například testování. Testování je klíčové při profesionálním vývoji softwaru a je zejména důležité právě v dynamicky typovaných jazycích. V praxi se testování provádí kvůli zajištění správného fungování programu, přičemž lze odhalit mnohem širší rozsah chyb než statickou typovou kontrolou, ale naopak nelze souhrnně najít chyby, které detekuje statická typová kontrola.
Kombinace dynamické a statické typové kontroly