676
Vývoj / Re:Rust - std::ANY alebo lepší návrh?
« kdy: 18. 11. 2021, 11:46:41 »Jak by se to dělalo se Set-ou v C++ STL?V tomto případě stejně, insert v std::set taky indikuje, jestli se prvek přidal.
Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.
Jak by se to dělalo se Set-ou v C++ STL?V tomto případě stejně, insert v std::set taky indikuje, jestli se prvek přidal.
Můžeš rozvést, co myslíš v tomhle případě runtimem, a k čemu by měl být Rustu užitečný?Myslím to, to myslí runtimem autoři Rustu (chlubíce se, že žádný nemá). Nechci zabředávat do diskusí (osobně mě absence runtimu, autory tolik vychvalovaná, netrápí, máme přece C++, Javu, Go, .NET Core
etc., každý dle svého gusta), ale právě lidi od App Engine si stěžují na absenci alespoň elementární dynamické reflexe (statická se dá v Rustu nasimulovat a hodně modulů to dělá). Proto zatím App Engine nemá plnou podporu pro Rust, těžko se jim integruje s jejich Datastorem, Memcache apod. IMHO tohle už není pole působnosti Rustu, ale někteří rustí nadšenci by ho zřejmě chtěli vidět všude a Google neustále "otravují"
Podle jednoho jejich vývojáře chtějí přidat C++, až bude mít odsouhlasené některé TS (přesunuté do C++23), to se pak rustíci pominou, že je C++ předběhlo 
K tomu pro zajímavost - přesně takhle je v rustu implementovaná HashSet - když to zjednoduším, je to obal nad HashMapou [...] Přijde mi naprosto úžasný, že takhle definovaná HashSeta je optimálně rychlá, nemusí se znovu nic reimplementovat, unit hodnoty vnitřní hashmapy se vyoptimalizují pryč.Jo, to je známý pattern, Go to má stejně tak (ani nic nemusí optimalizovat, má struct{}).
odpadne duplicitní lookupAno, a na tohle by se mělo hledět vždy. (Zvlášť lidi od C++ tohle hned v kódu vidí a kritizují
neb STL tohle řeší hezky.)
Ne, ale je to stejně nesystémové jako Any. Jasně se ukazuje, že Rust potřebuje aspoň nějaký malý stabilní runtime, pokud chce věrohodně rozšířit pole působnosti. I když s C++ si nemá co vyčítat. (Podle interních informací z Googlu je právě tohle důvodem, proč Rust více nepodporují na App Engine a jiných cloudových službách.)Zrovna TypeId je stejně haram jako Any.Jo, já osobně TypeId taky zatím nikdy nepoužil, ale pro tohle zadání mi to přišlo jako elegantní jednoduchý řešení .. alespoň jsem nepřišel na lepší, napadá tě něco?
K tomu navrhu cez Lazy Init, super napad, rovno to pouzijem, uvazoval som ale nic lepsie ma prakticky na momentalne sksuenosti nenapada.Jde to elegantněji přes get_or_insert.
Zrovna TypeId je stejně haram jako Any.
Debilní root fórum systém, psal jsem se s tím asi půl hodiny, mezitím mě to odhlásilo a příspěvek nenávratně zmizel. Tak ještě jednou v rychlosti:
push<T: DatabaseBuilder> - dobrý.
Chtělo by to trochu učesat:
Nelíbí se mi ty Optiony v push, create_table, a možná i v Database, myslím že by bylo lepší je zrušit. Navíc bych čekal, že budou brát &mut self.
Kdyby ses chtěl zbavit těch DatabaseMembers, který jsou opravdu podivný, mohla by se třeba udělat lazy inicializace tabulek přímo v Database, např. něco jako (nevím jestli půjde přeložit)
pub struct Database {
initialized_tables: HashSet<TypeId>,
c: Connection,
}
impl Database {
fn init_table<T: DatabaseBuilder + 'static>(&mut self) {
let type_id = TypeId::of::<T>();
if !self.initialized_tables.contains(&type_id) {
T::create_table(&self.c);
self.initialized_tables.insert(type_id);
}
}
pub fn push<T: DatabaseBuilder + 'static>(&mut self, data: &T) {
self.init_table::<T>();
data.push(&self.conn)
}
}
Devirtualizovat to asi vždy půjde jen omezeněTo dá rozum, když je to heuristická optimalizace. Typicky se používá v různých JIT překladačích a runtimech à la Smalltalk. Rust prostě tuhle optimalizaci (zatim?) nemá, pro C++ existuje údajně v experimentální formě. Každopádně až v Rustu bude, enumy už nebudou mít výhodu rychlosti.
Jo, tohle je standard (nejen) v Rustu. Součtové typy (rustí enum) můžou být rychlejší (překladač Rustu traity evidentně nedevirtualizuje).fn push<T:B>(&mut self, data:T)Ano, k tomuto som sa rovnako dopracoval +- ked ste to postol.
P.S. Teď jsem se dočetl, že překladač Rustu má dostat optimalizaci devirtualizací i pro traity, prý už se na tom pracuje. Pak už zůstane jako nevýhoda jen alokace na haldě, ale to s rozumným alokátorem není problém. Dík za odkaz, donutilo mě to najít si více o interní (zamýšlené) implementaci Rustu.Pro zajímavost: https://docs.rs/enum_dispatch/0.3.7/enum_dispatch/Tohle je skutečně zajímavé, vypadá to jako nějaká sofistikovaná optimalizace.
Pro zajímavost: https://docs.rs/enum_dispatch/0.3.7/enum_dispatch/Tohle je skutečně zajímavé, vypadá to jako nějaká sofistikovaná optimalizace.
Jakkoli chápu, že při vytváření jednotlivé hodnoty je třeba explicitně uvést variantu a tudíž to je malinko ukecanější, pořád mi enum přijde jako menší zlo, než dynamický dispatch.Ani jedno není zlo. A enumy jsou taky dynamické (rezoluce za běhu, v Rustu to jsou ostatně součtové typy a interní implementace je stejným dynamickým mechanismem jako traity). Rozdíl je na úrovni syntaxe a potažmo čitelnosti, tam vedou "enumy". Jen to chce pro posouzení vědět přesněji, o co tazateli jde.
Pokud ne, asi skutečně nezbude než dělat nějaký dynamic dispatch přes např. Any. I v takovém případě bych se ovšem spíš snažil případná neznámá data co nejdřív převést na nějaký konkrétní typ a udělat push generické s trait boundem a bez Any.Přesně. Když už je nutné sáhnout po Any, je dobré jeho užití izolovat a ve zbytku kódu pracovat hezky po rustovsku s typovým systémem (ten je v Rustu ostatně poměrně silný, nově včetně GADT). Traity poskytují transparentní dynamický dispatch, Any je explicitní dynamický dispatch dělaný na koleně (dost často působí jako hack nebo antipattern).
Mozete spravit kratky snippet, pripadne upravit kod ktory som postol?Chtělo by to nejdříve úplný kód (bez /* ... */). U té generické metody by byla signatura
fn push<T:B>(&mut self, data:T) kde B je příslušný bound. Tohle ani není o Rustu, každý jazyk s typovými parametry má takovéto použití unifikace. V obecné rovině doporučuju co nejvíce modelovat typové podobnosti (a odlišnosti) přes traity, dynamický dispatch je na Rustu to zajímavé oproti C.
mate nejaky navrh na zlepsenie?Ta funkce push může být klidně generická. Nebo jde mít trait zastřešující X–Z. První řešení je více o (silných) typech, druhé o OO návrhu. Proti použití Any bych obecně nic neměl, ale typ se pak kontroluje za běhu, což nebývá úplně ideální. Navíc v Rustu má Any omezení ohledně lifetimů.