diff --git a/BASED.md b/BASED.md index ebb2b22..31774a0 100644 --- a/BASED.md +++ b/BASED.md @@ -132,13 +132,13 @@ A lényeg ez (kb. "kötelező" RAII + extra szabályok dangling ref / pointer el - referenciákat lehet paraméterként megadni elvárt típusnak ÉS visszatérési értékként is metódusoknál - De referenciát eltárolni handle mezőben nem lehet - sima változóban félreteheted magadnak a stack-en ha nem akarod mindig kiírni az expression-t. -- Pointerekre meg van egy ownership modell, hogy a handle-khez (class/ struct megfelelője) tartozik egy "resources" vagy "pointers" blokk... Valszeg csak külön syntax van erre, nem akarok ilyen hosszú szavakat kiírva látni, mert öli a produktivitást, hanem mint a C++ban pl van az inicializálós rész a konstruktornál, úgy a class-nál valami hasonló kis syntax erre... -- Ugye pointereket vissza tudnak adni és el tudnak fogadni paraméterként @resource-nak és @release-nek jelölt függvények (mint pl. a malloc meg a free). +- Pointerekre meg van egy ownership modell, hogy a handle-khez tartoznak a pointereik. Csak ők írhatják őket (más nem) - típus szerint ők írhatják, tehát más azonos típusú handle-nek is írhatom! +- Ugye pointereket vissza tudnak adni és el tudnak fogadni paraméterként @resource-nak és @release-nek jelölt függvények (mint pl. a malloc meg a free). Ez egyszerűen kell az alap működéshez. - Az ilyen (így jelölt) függvényeket, csak konstruktorból és destruktorból tudod meghívni!!! - De persze a konstruktor beállíthat a pointerednek valami értéket - nem kell malloc-ból inicializálja meg! és ugye nem kell free-szerű dolgokat hívnia rá... -- Meg persze a @resource nem kötelező, hogy pointer-t adjon vissza - mert adhat valami handle-t is mondjuk. Tehát ennek a "pointeres" blokknak vagy lehetnek nem pointeres változói, ami mondjuk egy integer csak, de úgy jobb, ha minden resource-t szerintem oda írsz - alternatíva, hogy tényleg csak a pointereket jelöljük külön is és akkor sima mezőnek ad értéket a konstruktorban a @resource-os függvény ami mondjuk egy adatbázis handle-t ad vissza valami hívásból és tárol el.... Lehet hogy tisztább ez így, csak így a resource handle-k nem egy helyen vannak, hanem félig a pointerek - félig a sima adatok közt. Valszeg érdemes pointer blokkot csinálni ami tényleg csak pointereket tartalmaz és ha nem használod - hát nem használod.... Egyre inkább hajlok az utóbbira, mert mégis tisztábbnak hangzik... +- Meg persze a @resource nem kötelező, hogy pointer-t adjon vissza - mert adhat valami handle-t is mondjuk. - Nyilván ezek mind privátok: de ha valaki referenciát ad paraméternek a saját típusodból egy metódusodban, az abban lévőket eléred mert van rá ugye visibility-d úgy. Meg esetleg ugye csinálhatsz friend jellegű dolgot, vagy "owner" class-t aki eléri a pointereid. Esetleg ha egymásba ágyazott class-okat csinálhatsz, akkor ez default bekerül friend-ként, hogy a class törzsében definiált másik class alapból a kintit tekinti ownernek... Ez az "owner class" jó ötletnek tűnik - el is neveztem protectornak - és így lehetnek protected pointerek - na azokat éri el az a speciális class / handler! -- A pointereknek adhatsz értéket, növelheted, csökkentheted, szorozhatod meg a faszomsetudja még mit akarsz vele. De csak a saját pointereidre van normális esetben láthatóságod... +- A pointereknek adhatsz értéket, növelheted, csökkentheted, szorozhatod meg a faszomsetudja még mit akarsz vele. De csak a saját pointereidre van normális esetben láthatóságod... Tehát más pointerei amit kapsz azokat nem tudod változtatni se értékadás jobb oldalában szerepeltetve "lementeni" magadnak. - Alapból a pointer lehet null - alapból a referencia nem lehet null! Külön kell jelezni, ha lehet null egy visszaadott referencia, vagy paraméterben leírt ref - tehát ez a típus része. Mondjuk egy &ref? jellegű syntax, vagy valami ilyesmi. ^^ez szerintem majdnem mindent kezel, de nyilvánvalóan nem mindent és pont az a célom, hogy a rust-al ellentétben NE akarjak mindent safe-en tartani, csak minél többet... @@ -163,6 +163,231 @@ Ez meg szerintem fasság - nem jó érvek: https://dept-info.labri.fr/~strandh/Teaching/MTP/Common/Strandh-Tutorial/need-for-garbage-collection.html +## Jobb pointerek 1: safety + +A pointerek ahogy fenn írtuk, alapvetően csak @resource és @release függvényekben menthetők és használhatók korlátlanul, +és persze a handle-k adattagjai is lehetnek pointerek amiket akkor kezelünk, mert saját pointer állhat értékadás bal oldalán! + +VISZONT! Kiadhatunk pointereket a user kód / caller felé, de számukra nem "menthetők" le ezek. Tehát alapból egy pointer +nem lesz "menthető", de @resource-os és @release-es függvények esetén, @unsafe kódban és a saját ownership alatt IGEN! + +Még egy fontos kivétel talán: + + for (char* c = str; *c; ++c) { + ... + } + + while (char* c = file.nextline()) { + ... + } + +^^Ennél szerintem engedni kéne, hogy a for/while használhassa talán? De ez egy nagyon jó kérdés, mert speciális eset! + Szerintem valahogy ez jó volna, mert praktikus baj nincs vele és C-interop miatt kellhet (főleg az utóbbi pl.) + +## Jobb pointerek 2: speed + +Valahogy jó lenne elérni, hogy a default a "restrict" kulcsszóhoz legyen közelebb. +Egy lehetőség, hogy tömbre (tehát ptr+méret-re)a default a restrict, de pointerre ki kell írni. + +* Talán a tömbök külön típussá emelése ebben már eleve segít - igen... legyenek továbbá mérettel is ellátva stb. lásd ott +* Mivel az ownerek kezelnek csak ptr-eket, ők adhatnk ki referenciákat és array-eket, de azok ugye nem alias-olnak be könnyen +* A restrict kulcsszó támogatása a minimum - de talán kéne gondolkozni mit lehetne még kihozni, hogy jobb legyen! +* Ugye mivel van külön "tömb" típusunk, ezért arra is lehetővé kéne tenni a restrict-et pl. paramétereknél, különben bakis lesz. + +Egy (talán elvetendő) ötlet: A pointer típusa lehessen csoportosítható: + + handle A { + int n; + }; + + A@aliasinggroup1 variable = { 1 }; + A@aligrp2 array[5] = { 1, 2, 3, 4, 5 }; + + inline int magic(A *ptr1, A *ptr2) { + ptr2->n = 42; + return ptr1->n; // return 1 when inlined + } + + magic(&variable, &array[3]); // see that it cannot alias + + Esetleg szükséges legyen ilyenkor a használati helyen is kiírni a típust? + + inline int magic(A@aliasinggroup1 *ptr1, A@aligrp2 *ptr2); + + Az a bajom ezzel... hogy "gyalázatosan ocsmány" sajnos ez mind... + +Alternatíva: + +* Tömbökről feltételezzük, hogy sosem alias-olnak be (hacsak nem "unrestrict" kulcsszavas). +* Referenciák sem alias-olódnak + +Alternatíva (all-in): + +* Mindent restrict-nek veszünk by default és az unrestrict-et be kell írni... +* Kicsit unsafe-nek hangzik és sok benne a meglepetés, de a perf jó. + +Lásd FORTRAN: https://flang.llvm.org/docs/Aliasing.html + +Alternatíva (typedef-szerű): + + restrictptr PooledPtr int*; + restrictptr RawPtr int*; + + inline int magic(PooledPtr ptr1, RawPtr ptr2) { + *ptr2 = 42; + return *ptr1; // Should optimize as: return 2 + } + + int i1 = 1; + int i2 = 2; + magic(&i1, &i2); // can optimize + + Jelenleg ez az alternatíva tetszik a legjobban + persze a restrict kulcsszó támogatása emellett még pluszban! + + Talán lehetne restrictptr PooledArr int[]; jellegű típus definíció is (tömbök alias kerülésére) + +Szemantika: + +* Ha csak különböző ilyeneket látok egy paraméterlistán, akkor restrict-et kódgenerálunk mindre. +* Ha csak különböző ilyeneket ÉS más típusú dolgokat... akkor is... +* Egy ugyan ilyen típusú és egy másik ugyan ilyen típusú restricptr között viszont kell aliasing! +* Egy (fenti példával élve) PooledPtr-es int* és egy sima int* között viszont nem kell! +* Van továbbra is restrict kulcsszó (C-s szemantikával) + +Ezekkel a szabályokkal egész jó dolgot csináltunk szerintem, mert ha valaki kiad egy pointert, akkor kiadhat +hozzá ilyen plusz infókat, ami jelzi a fordítónak, hogy mik alias-olhatnak és mik nem. Egy jó példa, ha egy +játék mondjuk ilyen memory arénákban tárol dolgokat és az "engine" tudhatja, hogy melyik arénából adjuk ki +éppen a mutatót. Gyakorlatilag ez majdnem olyan, mintha valamit restrictptr-el deklarálunk, akkor annak +az összes előfordulásánál beíródik a generált pointer elé a "restrict" - ez csak annyiban téves, hogy +ha több ilyen is van egy függvényben / scope-ban azonos típusnéven, akkor azok egymással nem restrict-elnek! +Ez utóbbit első körben implementálhatjuk úgy, hogy ilyenkor lekerül a restrict, de úgy is, hogy kódgenerálással +megoldjuk csak a kettő közötti restrict-álást és fenn hagyjuk a kulcsszót. Ez egy kicsit bonyolítja a dolgokat... + +Az ilyen pointer cast-olható az alaptípusára - de ezzel elveszítjük a speed boost lehetőségét olyankor! +Megj.: Szerintem ezzel generálható C-kód -fno-strict-aliasing mellett is akár, ha típus alapút nem akarok! + +## Jobb referenciák + +* A referenciának lehetne "értéket adni" - nem mint C++ban... +* De ahogy fentebb írtuk másolni csak lokális változóba lehet a stackre +* A referencia "lényegében egy pointer, de nincs rajta aritmetika"... szóval nem tömböt jelképez. +* Kérdőjel hozzáadásával jelölhető, hogy null lehet-e (default: nem). + +## Jobb tömbök + +Néhány dologra van szerintem szükségünk: + +* (Pointer + méret / range) jellegű tömb történet, ahol a méret / range lekérhető a típusból ADA-szerűen (.len) és az elemtípus is! +* Range subtype (ada szerűen) NEM kell külön a típusrendszerben, mert hajlok arra, hogy 0..méret lehessen csak (praktikus: dyn) +* Dinamikus esetben, hívhasd az ilyen függvény paramétert sort(array(ptr, 42)) történettel (ahol ptr egy pointer, 42 méret). + +A fordító két függvényt is generál ilyen függvényekből. A típusrendszer szerint azt a függvényt hívjuk meg, amelyik gyorsabb! +Igazából ha fordítási időben ismert méretű tömbbel hívjuk meg, akkor a "sima" függvény hívódik, kivéve, ha ez valami linkelt lib, +mert abban az esetben természetesen a "valódi" függvény fog hívódni - ezt C-re fordításnál még nem látom át hogyan kéne, de majd +meg kellene oldani... + +A lényeg, hogy a "tömb" típus az pointer + hossz minden esetben, de ahol tudja, a fordító kioptimalizálja a történetet! +Ha valami mást akar az ember, például performancia okokból, akkor simán adjon át egy pointert (és mondjuk null termináns). + +Ha az "array" második paramétere nem fordítási idejű konstans szám, akkor ott is a dinamikus függvényt hívjuk majd meg. + +A range, mint altípus megadás lehetővé tenné, hogy dolgok "osztozzanak" a méreten - pl. ECS egy játékmotorban, stb. +De mivel nem tól-ig, vagyis ADA-szerű range-jeink vannak, simán csak méret, ezért ha ilyet akarsz konstans számként tárolod. + +Emellett természetesen a standard library-ban kell "vector" típus és az tudjon array-t is adni neked. + +Szerintem az így kapott kód "már kellően biztonságos" általában. A vektorra debug build esetén legyen range check kötelezően! + +A tömböknél a restrict lehet ESETLEG a default - de ennek fényében kellene unrestrict kulcsszó rájuk! + +Lásd még: + + https://youtu.be/MUISz2qA640?t=1980 + +ui.: Ha nem lesz operátor overload, akkor szerintem legyen több dimenziós tömb (nem a tömbök tömbje, hanem: matrix[15, 10, 42] = 5; + +### restrict-ált tömbök + +A tömbökre is kell a pointerekhez hasonló restrict. + +## Típusos indexek + +Egy pointer a modern gépen 64 bit, sokszor tömörebben tudsz tárolni "referencia-szerűséget" ha indexet tárolsz rá! + + struct A { uint32_t a, b, c; }; // 3*4=12 bytes with 4 byte alignment + struct B { child *a, *b, *c; }; // 3*8=24 bytes with 8 byte alignment + + struct C { A aa; uint32_t x; }; // 4*4=16 bytes with 4 byte alignment + struct D { B bb; uint32_t x; }; // 4*8=32 bytes with 8 byte alignment (4 wasted bytes) + +Viszont! A pointerek - mint itt is látszik - típusosak, de az indexek NEM! Viszont miért ne lehetnének? + + child@uint32_t index; // Például így + +A syntax-on lehetne még variálni... + +De az a helyzet, hogy erre már van megoldás jelenleg is (sőt C-ben is, struct-al): + + record ChildIndex { + uint32_t index; + }; + + esetleg még jobb, ha "like-olást" is használunk közben: + + record child_index { + like uint32_t index; + }; + +### NonOwningPointer - smartpointer + +Ezt szerintem érdemes C++ template-el előre megcsinálni! A lényeg az, hogy kreálni lehet a dolgot - tehát van egy factory-szerű, + + class Owner { + private: + std::vector vec = {1, 2, 3}; + + // Has a vector of pointers to children + // So when this go out of scope we can set child pointers backpointers to nulls (indicating non-living) + OwnPtrFactory fac; + + public: + // or access(..) etc. + // NownPtr has a pointer to the factory's own elem and on its move assign / move constructor calls updates facs child vec's + // pointer. Caller can ask the pointer if owner is already deleted or not. Maybe should be threadsafe? + NownPtr getMid() { + return fac.create(&vec[1]); + } + }; + +Ezt követően a használati ponton olyasmi történik, hogy: + + class User { + void f(..) { + ... + // Safe használat + NownPtr mid = owner.getMid(); + mid.if_exists([](int &i) { + ... i is accessible ... + }); + + // Unsafe használat (esetleg nálam @unsafe és konstruktor/destruktor esetben?) + int j = *mid + 40; + + // Unsage-nél is lehessen kérdezni + if(mid) { + int k = *mid; + } + + ... + } + } + +Ez tehát úgy látom C++ nyelven is lehetséges, egyedül mozgatáskor tűnik kicsit is "lassabbnak" meg ugye ez egy "fat" pointer, ami +2x pointernyi méretet használ fel... az egyik maga a mutatott terület címe, a másik a "factory"-ban lévő vektor megfelelő elemére +mutat rá - itt vigyázni kell: a vektor resize esetén invalidálódik ez! Kéne valami "stabil-vektor" ami blokkos és a resize-nál NEM +invalidálódik, de nem is egyesével, hanem blokkosával láncolt lista! + +Ezt esetleg nem is nyelvi elemként tennénk be, hanem library-ként a BASED-be is, az talán jobb? + ## Custom allokátorok / arénák A go-hoz újabban ajánlott "arénás" modell-t is lehet hogy valahogy alkalmazhatnánk - tehát hogy azzal oldjuk meg a custom allokátor kérdést... De szerintem egyszerűen úgy kell kialakítani a standard libet / kódokat, hogy template paraméter szerűen átvegye milyen @resource és @release függvényeket használ - tehát nem konkrétan malloc-ot, meg free-t mondjuk hanem csak azoknak megfelelő deklarációs függvényeket... Ezt C-ben is szoktam csinálni (pl. a kismap-ban van ilyen), de ugye ott függvény pointerekkel, amiket vagy eltárolok (de akkor runtime költsége van), vagy ha a perf fontos, akkor pl. a kismap esetén azt szoktam, hogy ezeket nem csak konstruálásnál, hanem minden hívásnál át kell adni ami használja - azért mert látom, hogy a compiler be tudja inline-olni, ha egy static inline force-inline stb. függvényt adok át neki function pointernek... De ez ugye "trükközgetés" feleslegesen és jó lenne, ha nyelvi elemként tudnánk ezt. Esetleg érdemes a hagyományos generik / template témától ezt különszedni? Nem biztos, lehet hogy azzal kezelendő. Cpp esetén template-ekkel szoktam ezt csinálni... @@ -294,209 +519,6 @@ Lásd: Ez szerintem low-level helyekre jó lehet... Ha jól definiálom mi történik, akkor padding / align helyett (mellett) is talán. -## Jobb pointerek - -Valahogy jó lenne elérni, hogy a default a "restrict" kulcsszóhoz legyen közelebb. -Egy lehetőség, hogy tömbre (tehát ptr+méret-re)a default a restrict, de pointerre ki kell írni. - -* Talán a tömbök külön típussá emelése ebben már eleve segít - igen... legyenek továbbá mérettel is ellátva stb. lásd ott -* Mivel az ownerek kezelnek csak ptr-eket, ők adhatnk ki referenciákat és array-eket, de azok ugye nem alias-olnak be könnyen -* A restrict kulcsszó támogatása a minimum - de talán kéne gondolkozni mit lehetne még kihozni, hogy jobb legyen! -* Ugye mivel van külön "tömb" típusunk, ezért arra is lehetővé kéne tenni a restrict-et pl. paramétereknél, különben bakis lesz. - -Egy (talán elvetendő) ötlet: A pointer típusa lehessen csoportosítható: - - handle A { - int n; - }; - - A@aliasinggroup1 variable = { 1 }; - A@aligrp2 array[5] = { 1, 2, 3, 4, 5 }; - - inline int magic(A *ptr1, A *ptr2) { - ptr2->n = 42; - return ptr1->n; // return 1 when inlined - } - - magic(&variable, &array[3]); // see that it cannot alias - - Esetleg szükséges legyen ilyenkor a használati helyen is kiírni a típust? - - inline int magic(A@aliasinggroup1 *ptr1, A@aligrp2 *ptr2); - - Az a bajom ezzel... hogy "gyalázatosan ocsmány" sajnos ez mind... - -Alternatíva: - -* Tömbökről feltételezzük, hogy sosem alias-olnak be (hacsak nem "unrestrict" kulcsszavas). -* Referenciák sem alias-olódnak - -Alternatíva (all-in): - -* Mindent restrict-nek veszünk by default és az unrestrict-et be kell írni... -* Kicsit unsafe-nek hangzik és sok benne a meglepetés, de a perf jó. - -Lásd FORTRAN: https://flang.llvm.org/docs/Aliasing.html - -Alternatíva (typedef-szerű): - - restrictptr PooledPtr int*; - restrictptr RawPtr int*; - - inline int magic(PooledPtr ptr1, RawPtr ptr2) { - *ptr2 = 42; - return *ptr1; // Should optimize as: return 2 - } - - int i1 = 1; - int i2 = 2; - magic(&i1, &i2); // can optimize - - Jelenleg ez az alternatíva tetszik a legjobban + persze a restrict kulcsszó támogatása emellett még pluszban! - + Talán lehetne restrictptr PooledArr int[]; jellegű típus definíció is (tömbök alias kerülésére) - -Szemantika: - -* Ha csak különböző ilyeneket látok egy paraméterlistán, akkor restrict-et kódgenerálunk mindre. -* Ha csak különböző ilyeneket ÉS más típusú dolgokat... akkor is... -* Egy ugyan ilyen típusú és egy másik ugyan ilyen típusú restricptr között viszont kell aliasing! -* Egy (fenti példával élve) PooledPtr-es int* és egy sima int* között viszont nem kell! -* Van továbbra is restrict kulcsszó (C-s szemantikával) - -Ezekkel a szabályokkal egész jó dolgot csináltunk szerintem, mert ha valaki kiad egy pointert, akkor kiadhat -hozzá ilyen plusz infókat, ami jelzi a fordítónak, hogy mik alias-olhatnak és mik nem. Egy jó példa, ha egy -játék mondjuk ilyen memory arénákban tárol dolgokat és az "engine" tudhatja, hogy melyik arénából adjuk ki -éppen a mutatót. Gyakorlatilag ez majdnem olyan, mintha valamit restrictptr-el deklarálunk, akkor annak -az összes előfordulásánál beíródik a generált pointer elé a "restrict" - ez csak annyiban téves, hogy -ha több ilyen is van egy függvényben / scope-ban azonos típusnéven, akkor azok egymással nem restrict-elnek! -Ez utóbbit első körben implementálhatjuk úgy, hogy ilyenkor lekerül a restrict, de úgy is, hogy kódgenerálással -megoldjuk csak a kettő közötti restrict-álást és fenn hagyjuk a kulcsszót. Ez egy kicsit bonyolítja a dolgokat... - -Az ilyen pointer cast-olható az alaptípusára - de ezzel elveszítjük a speed boost lehetőségét olyankor! -Megj.: Szerintem ezzel generálható C-kód -fno-strict-aliasing mellett is akár, ha típus alapút nem akarok! - -## Jobb referenciák - -* A referenciának lehetne "értéket adni" - nem mint C++ban... -* A referencia "lényegében egy pointer, de nincs rajta aritmetika"... -* Kérdőjel hozzáadásával jelölhető, hogy null lehet-e (default: nem). - -## Jobb tömbök - -Néhány dologra van szerintem szükségünk: - -* (Pointer + méret / range) jellegű tömb történet, ahol a méret / range lekérhető a típusból ADA-szerűen (.len) és az elemtípus is! -* Range subtype (ada szerűen) NEM kell külön a típusrendszerben, mert hajlok arra, hogy 0..méret lehessen csak (praktikus: dyn) -* Dinamikus esetben, hívhasd az ilyen függvény paramétert sort(array(ptr, 42)) történettel (ahol ptr egy pointer, 42 méret). - -A fordító két függvényt is generál ilyen függvényekből. A típusrendszer szerint azt a függvényt hívjuk meg, amelyik gyorsabb! -Igazából ha fordítási időben ismert méretű tömbbel hívjuk meg, akkor a "sima" függvény hívódik, kivéve, ha ez valami linkelt lib, -mert abban az esetben természetesen a "valódi" függvény fog hívódni - ezt C-re fordításnál még nem látom át hogyan kéne, de majd -meg kellene oldani... - -A lényeg, hogy a "tömb" típus az pointer + hossz minden esetben, de ahol tudja, a fordító kioptimalizálja a történetet! -Ha valami mást akar az ember, például performancia okokból, akkor simán adjon át egy pointert (és mondjuk null termináns). - -Ha az "array" második paramétere nem fordítási idejű konstans szám, akkor ott is a dinamikus függvényt hívjuk majd meg. - -A range, mint altípus megadás lehetővé tenné, hogy dolgok "osztozzanak" a méreten - pl. ECS egy játékmotorban, stb. -De mivel nem tól-ig, vagyis ADA-szerű range-jeink vannak, simán csak méret, ezért ha ilyet akarsz konstans számként tárolod. - -Emellett természetesen a standard library-ban kell "vector" típus és az tudjon array-t is adni neked. - -Szerintem az így kapott kód "már kellően biztonságos" általában. A vektorra debug build esetén legyen range check kötelezően! - -A tömböknél a restrict lehet ESETLEG a default - de ennek fényében kellene unrestrict kulcsszó rájuk! - -Lásd még: - - https://youtu.be/MUISz2qA640?t=1980 - -ui.: Ha nem lesz operátor overload, akkor szerintem legyen több dimenziós tömb (nem a tömbök tömbje, hanem: matrix[15, 10, 42] = 5; - -### restrict-ált tömbök - -A tömbökre is kell a pointerekhez hasonló restrict. - -## Típusos indexek - -Egy pointer a modern gépen 64 bit, sokszor tömörebben tudsz tárolni "referencia-szerűséget" ha indexet tárolsz rá! - - struct A { uint32_t a, b, c; }; // 3*4=12 bytes with 4 byte alignment - struct B { child *a, *b, *c; }; // 3*8=24 bytes with 8 byte alignment - - struct C { A aa; uint32_t x; }; // 4*4=16 bytes with 4 byte alignment - struct D { B bb; uint32_t x; }; // 4*8=32 bytes with 8 byte alignment (4 wasted bytes) - -Viszont! A pointerek - mint itt is látszik - típusosak, de az indexek NEM! Viszont miért ne lehetnének? - - child@uint32_t index; // Például így - -A syntax-on lehetne még variálni... - -De az a helyzet, hogy erre már van megoldás jelenleg is (sőt C-ben is, struct-al): - - record ChildIndex { - uint32_t index; - }; - - esetleg még jobb, ha "like-olást" is használunk közben: - - record child_index { - like uint32_t index; - }; - -### NonOwningPointer - smartpointer - -Ezt szerintem érdemes C++ template-el előre megcsinálni! A lényeg az, hogy kreálni lehet a dolgot - tehát van egy factory-szerű, - - class Owner { - private: - std::vector vec = {1, 2, 3}; - - // Has a vector of pointers to children - // So when this go out of scope we can set child pointers backpointers to nulls (indicating non-living) - OwnPtrFactory fac; - - public: - // or access(..) etc. - // NownPtr has a pointer to the factory's own elem and on its move assign / move constructor calls updates facs child vec's - // pointer. Caller can ask the pointer if owner is already deleted or not. Maybe should be threadsafe? - NownPtr getMid() { - return fac.create(&vec[1]); - } - }; - -Ezt követően a használati ponton olyasmi történik, hogy: - - class User { - void f(..) { - ... - // Safe használat - NownPtr mid = owner.getMid(); - mid.if_exists([](int &i) { - ... i is accessible ... - }); - - // Unsafe használat (esetleg nálam @unsafe és konstruktor/destruktor esetben?) - int j = *mid + 40; - - // Unsage-nél is lehessen kérdezni - if(mid) { - int k = *mid; - } - - ... - } - } - -Ez tehát úgy látom C++ nyelven is lehetséges, egyedül mozgatáskor tűnik kicsit is "lassabbnak" meg ugye ez egy "fat" pointer, ami -2x pointernyi méretet használ fel... az egyik maga a mutatott terület címe, a másik a "factory"-ban lévő vektor megfelelő elemére -mutat rá - itt vigyázni kell: a vektor resize esetén invalidálódik ez! Kéne valami "stabil-vektor" ami blokkos és a resize-nál NEM -invalidálódik, de nem is egyesével, hanem blokkosával láncolt lista! - -Ezt esetleg nem is nyelvi elemként tennénk be, hanem library-ként a BASED-be is, az talán jobb? - ## Holy-C féle kiegészítések a switch statement-hez Erről még nem vagyok meggyőzve, de néha hasznosnak tűnnek: