Zobrazit příspěvky

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.


Příspěvky - Idris

Stran: 1 ... 143 144 [145] 146 147 ... 153
2161
Vývoj / Re:Ideálny programovací jazyk
« kdy: 12. 05. 2019, 15:40:59 »
Ano, můžeš zkoušet různé countery, vektory, předalokace, dealokace a věřit, že tím obejdeš nevýhody new/delete. Však si to někdy zkus. Můj první příspěvek byl právě o tom, že GC je v tomhle přinejmenším dobrý kompromis vzhledem k tomu, jak to usnadňuje práci programátora. Ano, namítáš, že C++ programátor si může vybrat, já říkám, že výkon tohoto mechanismu je tak mizerný, že u složitějších problémů je k tomu donucen.

Já si to zkoušel, ale přes unique_ptr. A nenamítám, že programátor v C++ si může vybrat, namítám, že GC není jednoznačnou výhodou a že ne-GC přístup má své nesporné výhody. Navíc nejprve by to chtělo specifikovat, co si představuješ pod pojmem "výkon".

GC má samozřejmě overhead, ale když na něj dojde, tak často existuje jen zlomek objektů, co prošly tím programem. Pořeší tento zlomek a je hotovo. Delete se poctivě stará o každých pár byte co si někde alokuješ, to je prostě ohromný rozdíl.
Dělal jsem spoustu měření na různě složitých algoritmech. Pro lowlevel benchmark jsem si prostě udělal pole řádově tisíce pointerů a do toho jsem alokoval stále nové objekty. Ty něco triviálního počítaly a pak je přeplácnul nový objekt. Tohle samozřejmě GC chutná nejvíc, takže se tam projeví výhody proti delete.

Obávám se, že tohle nechápu. Zaprvé pokud existuje zlomek objektů, co prošly programem, tak proč bych měl v ne-GC přístupu alokovat víc? Zadruhé ten GC se taky stará o každý byte, protože nechce mít memory-leaky (a ten delete volá taky) - hlavní rozdíl je "kdy" a "jak často".

Ad ten příklad - pokud sis udělal řádově tisíce pointerů a do nich alokoval stále nové objekty, které něco počítaly a pak je přeplácnul, tak nechápu, proč jsi volal delete. Delete voláš až na konci, proč bych dealokoval paměť, kterou budu vzápětí alokovat? To potom chápu, že to pro GC vyházelo lépe, ale v takovém případě je problém jinde... :)

Účelem toho benchmarku bylo simulovat alokace v běžném programu. Tam jsou různé třídy a dělají různé věci. Tedy dává smysl alokovat různé objekty, k něčemu je použít a zase je smazat. Pokud bych to dělal jinak, tak bych netestoval to co jsem testovat chtěl.

Když už se pouštíš do debaty o GC, tak předpokládám, že aspoň zhruba víš jak funguje. Pro představu co se běžně používá - je kus paměti vyhrazen pro nové objekty, když tam dochází místo, tak živé (ty na které existuje odkaz) se vykopírují jinam a paměť se může znovu použít. Všimni si, že jsem vůbec nezmínil mrtvé objekty, pro ty se totiž nemusí dělat vůbec nic, žádný delete. V běžném programu je těch mrtvých v každé iteraci třeba 95%, takže je to proti klasickému delete výrazná úspora za cenu toho, že se musí 5% dat kopírovat.
Ne každý tracing GC kopíruje, třeba v Go je normální alokátor a GC (tricolor) běží na pozadí a barví si objekty. A světe div se, je efektivnější než ten kopírující v Javě nebo .NET.

2162
Vývoj / Re:Ideálny programovací jazyk
« kdy: 12. 05. 2019, 12:19:08 »

Když více polygonů vlastní jeden node, tak ho nemůžou mít přes unique, to je v rozporu.
Když tam budu dávat obyčejný pointer, tak si musím někde počítat reference, což je ještě horší než sharedptr.
GC to dělá mnohem efektivněji, v tom je ten vtip a to se tady už od včerejška snažím říci. Stručně řečeno, nepočítá reference, chodí jen po přeživších a má výraznou “množstevní slevu”.

Pokud více polygonů vlastní jeden node, tak už nejsou jeho, ale všech. Tj. to úplně neodpovídá tomu, co jsi na začátku psal. Takže ano, pak není shared_ptr od věci. Nebo se to taky dá udělat tak, jak jsem psal předtím - vlastnit to bude nějaká nadstruktura nad tím, která to v případě potřeby uklidí.
S tou efektivitou GC bych byl opatrný, protože hodně také záleží, jak funguje vevnitř. V čem přesně myslíš, že má "množstevní slevu"?

Když to bude vlastnit nadstruktura, tak jak pozná, že může vyhodit nepoužívané nody? Jasně, řešení známe, ptám se spíš proto aby sis rozmyslel, jestli to opravdu dovedeš řešit lépe než těmi sdílenými pointery.

Tak tam záleží, jak to bude navrhnuto. Ale typicky přes counter, nebo nějaký vektor. Myslím, že rychlostně by si člověk mohl pomoct.

Typický GC má "množstevní slevu" proto, že se nestará o nedosažitelné objekty, řeší jen živé. To znamená, že čím déle vydrží neběžet, tím víc bude těch mrtvých a tím víc na tom ušetří. V důsledku toho je velmi levné dělat krátce žijící objekty, což má spoustu dalších pozitivních důsledků. Naopak new/delete se poctivě stará o každý objekt, což je dost neefektivní a v důsledku nutí programátora, aby se krátkodobým objektům vyhnul.

Jak se stará jen o živé? Ten overhead u GC nevadí? A proč by v C++ mělo být velmi drahé dělat krátce žijící objekty? Copak si nemůžu naalokovat paměť, kterou pak budu předávat, abych nemusel pořád alokovat a dealokovat?

Kdysi jsem si potřeboval ověřit, jak moc v javě můžu prasit a bezohledně alokovat nové a vyšlo mi, že má asi desetinásobnou průchodnost proti MS C++. Čili za daný čas dokáže alokovat a zahodit 10x víc objektů než C++.

Tak zrovna MS C++ není úplně vypovídající. Také by mě zajímalo, jak jsi to měřil. :)
Pro lowlevel benchmark jsem si prostě udělal pole řádově tisíce pointerů a do toho jsem alokoval stále nové objekty. Ty něco triviálního počítaly a pak je přeplácnul nový objekt. Tohle samozřejmě GC chutná nejvíc, takže se tam projeví výhody proti delete.
To je teda hodně debilní benchmark.

2163
Vývoj / Re:Ideálny programovací jazyk
« kdy: 11. 05. 2019, 20:32:44 »

Představ si to třeba jako když polygony vlastní své nody (a ty jsou sdíleny mezi sousedními polygony). Pokud bych měl evidenci (a tím i životnost) nodů řešit bokem tak to je přesně ten argument, který jsem dal na začátku.

No nevím, proč  pořád používat shared_ptr, když je vlastní polygony. :)

Promiň, ale začíná mi připadat, že se nějak zásadně nechápeme ohledně využití shared_ptr.

Když je objekt "rovnocenně" vlastněn několika jinými, tak potřebuju evidovat, že ho stále někdo drží a až zmizí poslední vlastník, tak musí být uvolněn i ten objekt. Pokud mám GC, tak mi tuto evidenci pořeší a mám to bez práce. Pokud ne, tak se přímo k tomu nabízí shared_ptr, protože přesně tohle dělá, akorát je to dost drahé. Mohl bych si to dělat ručně někde bokem, ale v zásadě bych jen simuloval to počítadlo referencí co už je v tom shared, takže by to nejspíš bylo ještě dražší.

Ano, ale pokud polygony vlastní své nody, tak proč by je neměly vlastnit přes unique_ptr a ostatním dávat obyčejný pointer?
Ano, GC to za tebe pořeší a ty to máš bez práce... ale jak to ten GC pod kapotou asi dělá...? :)
tak si musím někde počítat reference, což je ještě horší než sharedptr.
GC to dělá mnohem efektivněji
Optimalizované počítání referencí bývá efektivnější, jednak se nic nepočítá, když čítač nepřekročí 1 (objekty s krátkou životností, obdoba nejnižší generace v tracing GC), a za druhé statická analýza odhalí případy, kdy není nutné čítač upravovat, i když by to dávalo smysl, například při návratu z funkce, kde se typicky dělá retain a následný (auto)release hned po sobě, což překladač odhalí a vyhodí. Kupříkladu Swift takto funguje a je to efektivnější než tracing GC. C++ má úplně jiný přístup s move sémantikou, ale to už tu psali jiní.

2164
Vývoj / Re:Ideálny programovací jazyk
« kdy: 11. 05. 2019, 12:41:07 »
Makra jsou na některé specialitky velice užitečný nástroj. Zároveň jsou ale nebezpečná v tom, že běžný Franta programátor bude jejich silou tak omámen, že je začne používat na věci, kde reálně potřeba nejsou, a kód se tím objektivně strašně znečitelní a zprasí (odstrašující příklad je Ruby).


už ti tu několikrát vysvětlili, že v Ruby makra nejsou*. Proč to pořád opakuješ?

* teoreticky AST makra jsou možná, ale nikdo je nepoužívá. Narozdíl od Crystalu nebo Elixiru.
“Narozdíl” se píše “na rozdíl”, když už chceš machrovat.

2165
Vývoj / Re:Ideálny programovací jazyk
« kdy: 11. 05. 2019, 12:39:25 »
Nevím o vážně míněné oprávněné kritice.
Já za nejpádnější považuju tohle: https://codegolf.stackexchange.com/questions/1956/generate-the-longest-error-message-in-c :))

...ale nechci se do C++ moc navážet, jak říkám, rozešli jsme se před nejmíň deseti lety a nepotřebuju se k téhle epizodě  z mládí vracet :)
Fakt sorry, ale koukni na datum. Clang (a pod tlakem konkurence pak i GCC) mají normální chybové hlášky. MSVC moc ne, no, ale to je Microsoft...

2166
Vývoj / Re:Ideálny programovací jazyk
« kdy: 11. 05. 2019, 11:47:28 »
Na šablony v C++ nikdo nenadává.
To je velice smělé tvrzení! ;)
Nevím o vážně míněné oprávněné kritice. Neberu argument, že jsou pro BF moc složité ;)

2167
Vývoj / Re:Ideálny programovací jazyk
« kdy: 11. 05. 2019, 11:31:31 »
Ad 2: Při překladu nebo za běhu?
Ideálně kompletně už při překladu. Ale neumím od stolu tvrdit, že nejsou nějaká zákoutí, která je potřeba aspoň částečně řešit za běhu. Pokud by nebyla, byl by to z mýho pohledu ideální stav.
Jsou taková zákoutí, ale IMHO v běžném kódu to jde řešit při překladu. Na šablony v C++ nikdo nenadává.

2168
Vývoj / Re:Ideálny programovací jazyk
« kdy: 11. 05. 2019, 10:38:58 »
ale to, co jsi psal, prostě celkem přesně sedí :)
P.S. já osobně bych od moderního jazyka chtěl spíš věci jako:

1. má dobře vyřešenou správu balíčků a jejich závislostí
2. má aspoň nějakou formu generik nebo jiný mocný mechanismus psaní abstraktního kódu
3. má homoikonická makra (ale v dokumentaci je palcovým písmem napsáno, že se nemají zneužívat tam, kde opravdu nejsou potřeba)
4. má pattern matching
5. překladač se snaží seč může odhalit chyby při překladu (a jazyk mu v tom jde naproti)
6. vůbec nemá null, místo něj je Option
7. má alespoň jednoduché algebraické typy

...což jsou přesně painpointy Gočka...

Příklad pokročílé vlastnosti ad 1: Elm umí sám detekovat změnu API a vynutí povýšení sémantické verze při pushnutí balíčku.

ad 5: například relativně jednoduchá, ale strašně užitečná featura překladače, je kontrola vyčerpávajícnosti pattern matchingu (např. když matchuju enum, musím pokrýt všechny zadefinované varianty).

ad 6: Option "navíc", jako možnost, což u některých jazyků je, je k ničemu - pokud je null "občas někde", musím ho čekat všude a tímpádem Option ztrácí význam.

ad 7: stačí jednoduché sum a product types (sorry, nevím, jak se "product type" překládá do češtiny). Praktické hlavně pro jednoduché použití silně typovaných tuples. Praktičnost vylítne do nebes ve spojení s pattern matchingem.


...takže mi do toho sedí spíš Rust než Go ;)
Ad 2: Při překladu nebo za běhu?

2169
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 17:34:05 »
Rozhodně musí mít GC, ruční správa paměti je ve většině případů špatná věc.
Fakt?
Ano. U jednoduchých algoritmů to moc nevadí, ale jakmile je to složitější, tak v konečném důsledku ten GC programátor píše pokaždé znova. Je to v tom algoritmu skryto, zbytečně ho to zesložiťuje a v kombinaci s případnými smartptr to nakonec může být i pomalejší.
Čili otázka není zda GC ano či ne, ale zda má být jednou v runtime nebo ho má psát programátor.
GC (tracing) dává smysl ve spojení s kvalitní escape analýzou, pokud všechno, kde to je technicky možné, alokuju na zásobníku, nemusím toho moc na haldě alokovat a běh GC se pak znatelně neprojeví. Nicméně správa paměti v C++ je taky dost dobře promyšlená.

2170
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 17:11:07 »
Syntaxe by se měla držet osvědčených zvyků ohledně operátorů, závorek atd., některé nové jazyky to zbytečně prohazují. Dál základní OOP, funkcionální prvky, aby stačilo říct "co" místo "jak". Takže streamy (ale jednodušší než v javě), lambdy, konstantní objekty...

Rozhodně musí mít GC, ruční správa paměti je ve většině případů špatná věc. Stejně tak by se programátor neměl starat o to, zda budou data na stacku nebo heapu, tohle zvládne překladač či runtime dost dobře sám. C++11 jasně ukazuje, že je špatný nápad tím prasit jazyk a že z toho cesta nevede. Smart pointery, move semantika atd. to ve výsledku ještě zhorší.

A bylo by hezké, kdyby měl nějak snadno zvládnuto ORM, JSON, HTTP, prostě napojení na běžné okolní prostředí.
Skoro přesně jsi popsal Go :)
  ;D

2171
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 17:08:09 »
Rozhodně musí mít GC, ruční správa paměti je ve většině případů špatná věc.
Fakt?

2172
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 13:08:05 »
Měl jsem na mysli hlavně velikost známou až v runtimu. Jedna věc jsou dočasné proměnné. Ty jsou v pohodě, i když najednou nutně potřebujeme registr pro frame pointer. Druhá věc je ale vracení objektu neznámé velikosti hodnotou. Volající neví kolik paměti vyhradit a volaný to taky nezvládne alokovat bez větších problémů. Musel by ten zásobník přeskládat. Neznám žádné volací konvence, které by něco takového uměly.
Já ty lowlevel detaily dobře neznám a C++ jsem viděl naposledy tak před deseti lety, takže mi asi spousta věcí uniká, ale čistě od stolu mě překvapuje, že je to problém. Přijde mi, že by stačily dvě čísla na začátku: velikost Derived a offset Base v rámci Derived. Pokud potřebuju Derived někam zkopírovat, vím jeho velikost a víc nepotřebuju. Pokud potřebuju šahat do Base, vím jeho offset, což je taky všechno, co potřebuju.
Polymorfismus na zásobníku principiálně řešit nejde. Proto je jediný obecně použitelný způsob dělat to, co dělá Go a některé jiné překladače/runtimy: escape analýza a na zásobniku jen to, co nezpůsobí problém. Ono, upřímně, alokací na haldě, které tam skutečně být musí, bývá typicky hodně málo a alokátory jsou natolik efektivní (včetně tracing GC), že autorům překladačů/runtimů nestojí za to se nějakým zásobníkem zabývat. Občas někdo uprasí nějaký šílený hack (nový runtime pro ObjC má intrinziky kolem správy paměti až na úroveň asembleru), ale v 99% případů se to nevyplatí.

2173
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 10:00:52 »
taky nebudu kritizovat Porsche Carrera, že s ním nemůžu orat pole, na základě toho, že jsem si myslel, že to jde.
Janže ono to jde a není to žádná obezlička, je to jasná součást jazyka - Derived můžu předat do funkce, která očekává Base. Nepředávám d.Base, předávám d. Je to nejspíš jediná situace, kde se v Go může předávat jiný typ než očekávaný.

A protože to není intuitivní, vyžaduje to explicitní vysvětlení:
Citace
There's an important way in which embedding differs from subclassing. When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one. In our example, when the Read method of a bufio.ReadWriter is invoked, it has exactly the same effect as the forwarding method written out above; the receiver is the reader field of the ReadWriter, not the ReadWriter itself.
https://golang.org/doc/effective_go.html#embedding

Není to ani čisté skládání (jako v C), ani subtyping. Je to takové divné "něco mezi" s vlastnostmi, které si člověk musí pamatovat, protože nikde jinde to tak nefunguje (naštěstí jich není moc).
Jo, je nutné si to pamatovat. Toho je v Go víc. Pak je otázka, jestli se taky člověk bez takovéhoto embeddingu obejde.

2174
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 09:42:51 »
Když takhle napíšu Base, jde o kompozici. Jak jinak by to asi mělo fungovat?
Problém je v tom, že se to na první pohled tváří jako subtypový polymorfismus (Derived můžu předat do funkce, která očekává Base), ale ve skutečnosti to tak není. Protože to může běžného frantu programátora zmást, možná by neškodilo víc explicitnosti:

Kód: [Vybrat]
func f(b Base) {
 ...
}

...

d := Derived{...}

// ok
f(d.Base)
// err
f(d)
- pokud by to bylo takhle, bylo by na první pohled jasné, že do f předávám jenom část d.

...ale nechci autorům Go radit, chtěl jsem jenom říct, že taková nepříjemná zákoutí nejsou jenom v C++, ale bohužel i v Go, které jinak lidi mají za dost čistý a konzistentní jazyk.
Go zrovna moc konzistentní není. Ale ta implicitní kompozice dává smysl. Že si někdo myslí, že Go má podtypový polymorfismus, to už je jiná věc, taky nebudu kritizovat Porsche Carrera, že s ním nemůžu orat pole, na základě toho, že jsem si myslel, že to jde.

2175
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 09:29:28 »
Navíc ten kód není zrovna idiomatický.
Ten kód jenom ukazuje, co se tam děje. Jinak to ukázat najde (AFAIK), takže tuhle výhradu neberu.

Jedním slovem: non-issue.
Může to být issue pro lidi, kteří mají subtypový polymorfismus pod kůží, chtějí nadesignovat kód tak, jak jsou zvyklí (předám někam Derived jako Base, něco se s tím děje, pak to dostanu zpátky a přetypuju si zase na Derived), a ejhle: ono to v Go takhle nejde :)

Jasně, správný Go řešení je použít interfaces, o tom se nehádám, jenom říkám, že to může být pro někoho docela překvapení. Mně osobně tenhle "supersilnej nominalismus" ("objekt" se chová ne podle toho čím je, ale podle toho, jaký typ je v kódu u něj napsaný) mně osobně moc nevyhovuje.
Když takhle napíšu Base, jde o kompozici. Jak jinak by to asi mělo fungovat?

Stran: 1 ... 143 144 [145] 146 147 ... 153