Není podstatné, že Lua je dynamický jazyk. Chtěl jsem tím uvést, že když jsem se kouknul do toho zdrojáku, tak tam žádné typové informace, které tvrdíš, že tam musí zůstat aby něco, nebyly.
Jak jsi poznal, že tam nebyly typové informace? V jazyce jako Lua má každá hodnota runtime typovou informaci, tak fungují dynamicky typované jazyky, tzn. ty typy tam nemohly nebýt
Na vstupu bylo x = Red. V lue bylo x = 1. To považuji, že tam ten Red není.
Aby tohle fungovalo, musí být ta hodnota boxovaná (na-alokovaná na heapu a schovaná za, efektivně, pointer) a operace na ní se provádí přes dynamic dispatch (bude tam nějaký ekvivalent v-table), jinak by nebylo možné provést type erasure.
Teda, já jsem to vždycky chápal tak, že type erasure je způsob, jak typy odrbat. Kde by tam jako měla být schovaná vtable? A proč? Ve skutečnosti tam tu vtable potřebuješ v případě, kdy nechceš dělat type erasure...
Dobře, tak mějme ten příklad s maticí. Dejme tomu, že od nějaké velikosti Thr (jako threshold) používá implementace matice nějakou vymakanou reprezentaci v paměti kvůli ušetření místa pro velké matice. Ok? Teď dejme tomu, že máme operaci `col` na matici, která vrátí daný sloupec jako vektor. Tahle operace bude muset fungovat různě v závislosti na Thr, z úsporné reprezentace se čte sloupec jinak než z jednoduché.
Tak, a teď, ty napíšeš program, který načte matici ze souboru a bude chtít číst sloupce. Pokud by ta typová informace - v tomto případě velikost matice - byla komplet odstraněna, metoda `col` by neměla jak poznat, jak je konkrétní matice v paměti reprezentována, a tedy jak extrahovat sloupec. Proto bude muset ta matice si s sebou tu informaci vzít a držet si ji během runtime, buďto to může být nějaký tag, podle kterého udělá ta metoda `col` vidličku, anebo si s sebout vezme vtable, která bude u různých konkrétních hodnoty ukazovat na různé implementace `col`. Řešení s vtable je obecnější - těch typových parametrů může být více, chování se může v závislosti na nich více lišit.
V jazyce jako Rust nebo C++ tohle není potřeba, protože kompilátor zná dopředu všechny instanciace a provede monomofrizaci, ie. v podstatě z toho udělá různé typy s různými metodami, ale cena za to je, že není možné vytvořit tu hodnotu at runtime.
Načtu matici ze souboru.
Zjistím velikost matice, podle toho vyberu buď reprezentaci (nikoliv typ) A, nebo reprezentaci B.
Pokud je to A pošlu to "uličkou" A. Pokud je to B pošlu to uličkou B.
V tomto případě tam nikde není třeba uchovávat informaci o typu, ani v tagu, ani nikde.
Ale budiž, blbej případ.
Problém není v tom, že by informace nemohla být v runtimu, že by tam nemohl být nějaký tag, nebo co já vím. Ty tvrdíž, že tam být musí, zatímco v Rustu být nemusí. Ale vůbec mi nedochází, kde to musení vidíš.
Představ si lepší překlad:
type Matice a = GenericMatice a | OptimalizedMatice a
let xs : [Matice] = parseFromFile(f)
out = map format xs
where
format x = case (type x):
GenericMatice m -> formatGenericMatice m
OptimalizedMatice m -> formatOptimalizedMatice m
Toto je první příklad, kde by mě napadlo, že by se hodilo type erasured nemít. A určitě se shodnem, že to některé jazyky takto můžou, přidat tam ty tagy, použít. Jiné jazyky něco takové zakážou. A některé jazyky (nebo ty samé, ale prostě si usmysleli) to zoptimalizují tak, že tam budou dvě "uličky" (v tomto případě si to nedokážu úplně představit, ale to není argument - stejně tak nedokážu najít "důkaz", proč by to nemělo jít). Pak tam v rámci optimalizace nebude vůbec žádná informace o typu.