Jak efektivně studovat programování?

Re:Jak efektivně studovat programování?
« Odpověď #90 kdy: 02. 11. 2020, 22:27:20 »
Což je si ale, přiznejme si, nic moc.

Kód: [Vybrat]
# Python
with open('dog_breeds.txt') as src, threading.Lock(), db.connection() as con:
    con.insert(src.readlines())

(GoLang má defer, což je něco podobného ale hnusnějšího.)

Řekl bych, ty tak docela nepotřebuješ rozlišovat co může selhat a co ne. Jako spíše zajistit tu atomicitu.

Ten with řeší dvě věci, automaticky uzavřít zdroj, když něco selže, a rollback při chybě v bloku.

Tohle je zatím nejhezčí s čím jsem se setkal.
Já teď opravdu neřeším atomicitu, ale kusy kódu co zaručeně nemůžou selhat. I v jednom vlákně se ta transakčnost nedá zaručit pomocí with a podobných.
With, defer, tryWithResource a podobně umí jen to, co destruktory v c++ - zavolat kus kódu na konci bloku. (Taky se pomocí destruktorů dají celkem snadno implementovat). Pro tu transakci to nestačí. Např to with ještě potřebuje aby _každý_ resource uměl zaručeně neházející rollback (pomocí __exit__).

Svým kódem jsem se snažil ilustrovat tohle : Mám několik resourců, update každého může selhat a chci updatovat všechno nebo nic. Buďto můžu spočítat nový stav všech a pak je bez házení prohodit. Nebo můžu updatovat jeden po druhém, ale potřebuju možnost jak je bez házení vrátit zpět. Nevím, jak to udělat bez kusu kódu co zaručeně neselže.

Jádro je ten kus kódu co zaručeně nehází. Bez něho to AFAIK nejde. Destruktory, with, defer a podobné jsou jen bonus co ušetří mechanické bušení try-finally a podobného boilerplate kódu.


BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Jak efektivně studovat programování?
« Odpověď #91 kdy: 03. 11. 2020, 01:58:40 »
Kód: [Vybrat]
# Python
with open('dog_breeds.txt') as src, threading.Lock(), db.connection() as con:
    con.insert(src.readlines())

(GoLang má defer, což je něco podobného ale hnusnějšího.)

Řekl bych, ty tak docela nepotřebuješ rozlišovat co může selhat a co ne. Jako spíše zajistit tu atomicitu.

Ten with řeší dvě věci, automaticky uzavřít zdroj, když něco selže, a rollback při chybě v bloku.

Tohle je zatím nejhezčí s čím jsem se setkal.

Teď se Ti myslím povedla demonstrace jedné ze skutečných výhod výjimek, která ale může fungovat asi jenom v dynamických jazycích typu Pythonu - ten context manager pozná výjimku podle parametru, který ji identifikuje.

Jinak je to věc, která se dá řešit destruktorem při výstupu z rozsahu platnosti proměnné - třeba v Rustu se udělá drop v opačném pořadí (vzhledem k pořadí definice proměnné) automaticky a je vymalováno taky.

Obávám se, že rozhodně nemohu souhlasit. Už jsem tu toto téma někdy rozebíral, žel neúspěšně. Má aktuální úroveň poznání mi říká, že dynamické jazyky nepřináší nic co by principielně nešlo ve statických jazycích (a stáli bychom o to). Každopádně, asi zůstaňme u tématu.



Já teď opravdu neřeším atomicitu, ale kusy kódu co zaručeně nemůžou selhat. I v jednom vlákně se ta transakčnost nedá zaručit pomocí with a podobných.
With, defer, tryWithResource a podobně umí jen to, co destruktory v c++ - zavolat kus kódu na konci bloku. (Taky se pomocí destruktorů dají celkem snadno implementovat). Pro tu transakci to nestačí. Např to with ještě potřebuje aby _každý_ resource uměl zaručeně neházející rollback (pomocí __exit__).

Svým kódem jsem se snažil ilustrovat tohle : Mám několik resourců, update každého může selhat a chci updatovat všechno nebo nic. Buďto můžu spočítat nový stav všech a pak je bez házení prohodit. Nebo můžu updatovat jeden po druhém, ale potřebuju možnost jak je bez házení vrátit zpět. Nevím, jak to udělat bez kusu kódu co zaručeně neselže.

Jádro je ten kus kódu co zaručeně nehází. Bez něho to AFAIK nejde. Destruktory, with, defer a podobné jsou jen bonus co ušetří mechanické bušení try-finally a podobného boilerplate kódu.

Kus kódu, který zaručeně nemůže selhat IMHO není problém. Třeba pomocí typů toho lze dosáhnout velice snadno (jsem ze světa Haskell, Rust, etc C++ je samozřejmě jinej případ). FP taky udělají hodně práce. Všechny tyhle požadované záruky ti kvalitní typový systém může dát (neříkám, že na 100%, ale nenechme se rozptylovat podrobnostmi). Chápu, proč to tak komentuješ. Protože C++. Typy C++ a typy v Rust, to je jako mít a nemít.

Já jsem řešil syntax. Ta mě zajímá. Zdá se, že v tomto se trochu míjíme, protože ty se zahrabáváš do implementačních detailů a ještě navíc v C++.

Ink

  • *****
  • 655
    • Zobrazit profil
    • E-mail
Re:Jak efektivně studovat programování?
« Odpověď #92 kdy: 03. 11. 2020, 07:54:35 »
Teď se Ti myslím povedla demonstrace jedné ze skutečných výhod výjimek, která ale může fungovat asi jenom v dynamických jazycích typu Pythonu - ten context manager pozná výjimku podle parametru, který ji identifikuje.

Jinak je to věc, která se dá řešit destruktorem při výstupu z rozsahu platnosti proměnné - třeba v Rustu se udělá drop v opačném pořadí (vzhledem k pořadí definice proměnné) automaticky a je vymalováno taky.

Obávám se, že rozhodně nemohu souhlasit. Už jsem tu toto téma někdy rozebíral, žel neúspěšně. Má aktuální úroveň poznání mi říká, že dynamické jazyky nepřináší nic co by principielně nešlo ve statických jazycích (a stáli bychom o to). Každopádně, asi zůstaňme u tématu.

Principiálně ano. Přemýšlím, jak by se to dělalo v C++. Pokud si pamatuju dobře, můžeš jako výjimku házet leccos, takže by maximálně šlo do exit metody poslat info, jestli výjimka byla nebo ne. U dynamických jazyků typu Pythonu je hodnota proměnné libovolná.

No ale zase, kdybychom měli k dispozici jenom bool, šlo by něco podobného i bez výjimek - třeba v Rustu. Tam se mi dokonce rýsuje i řešení s identifikací typu Erroru - pomocí downcastu by to mělo být možné vydolovat i z wrapperu, jaký dělá třeba anyhow! Tudíž asi musím vzít zpět svoje tvrzení o výhodě výjimky, protože podle všeho by to mělo jít postavit i nad Resultem - musel by se udělat příslušný trait (nebo změnit protokol Dropu) a jazyk by tomu musel vyjít vstříc.

Re:Jak efektivně studovat programování?
« Odpověď #93 kdy: 03. 11. 2020, 09:18:31 »
Kus kódu, který zaručeně nemůže selhat IMHO není problém. Třeba pomocí typů toho lze dosáhnout velice snadno (jsem ze světa Haskell, Rust, etc C++ je samozřejmě jinej případ). FP taky udělají hodně práce. Všechny tyhle požadované záruky ti kvalitní typový systém může dát (neříkám, že na 100%, ale nenechme se rozptylovat podrobnostmi). Chápu, proč to tak komentuješ. Protože C++. Typy C++ a typy v Rust, to je jako mít a nemít.

Já jsem řešil syntax. Ta mě zajímá. Zdá se, že v tomto se trochu míjíme, protože ty se zahrabáváš do implementačních detailů a ještě navíc v C++.
Jo míjíme se. _Explicitně_ tu píšu o podobnostech mezi různými jazyky. Kus c++ jsem tu hodil jen proto, že sis několikrát psal o příklad syntaxe. Nikde tu IMO neřeším implementační detaily. c++ je to jen proto, že ho umím nejlíp a neřeším konkrétní jazyk ale principy.

Typy v Haskellu tohle moc neřeší. Jestli kus kódu může selhat nezávisí na jazyce, ale na tom, co ten kus kódu dělá. V Haskellu jsem toho napsal taky dost. Monáda ti ten "fail" bude propagovat nahoru úplně stejně neviditelně jako výjimky v c++. A v haskellu taky IMO nejde zaručit že kus monadického kódu ten fail nezavolá. A pure věci nakonec stejně musíš protlačit do toho stavového světa (nebo ten vnější RealWorld něčím prohnat ;) ).

Typy v C++ jsou hrubé, syntaxe je ošklivá, ale co do schopností jsou velmi mocné. C++ má jeden z nejsilnějších typových systémů ze všech mainstreamových jazyků. Kód ení moc hezký, ale principy jsou tam stejné jako ve zbytku světa. Takže prosím ignoruj jazyk a soustřeď se na principy. Ty jsou to o co mi jde.
« Poslední změna: 03. 11. 2020, 09:21:26 od Jiří Havel »

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Jak efektivně studovat programování?
« Odpověď #94 kdy: 03. 11. 2020, 14:00:31 »
Typy v C++ jsou hrubé, syntaxe je ošklivá, ale co do schopností jsou velmi mocné. C++ má jeden z nejsilnějších typových systémů ze všech mainstreamových jazyků. Kód ení moc hezký, ale principy jsou tam stejné jako ve zbytku světa. Takže prosím ignoruj jazyk a soustřeď se na principy. Ty jsou to o co mi jde.

Nenech se znérvóznit mou antipatií k C++. Je to přeci jen už dlouho, co jsem v něm dělal. :-)

Typy v Haskellu tohle moc neřeší. Jestli kus kódu může selhat nezávisí na jazyce, ale na tom, co ten kus kódu dělá. V Haskellu jsem toho napsal taky dost. Monáda ti ten "fail" bude propagovat nahoru úplně stejně neviditelně jako výjimky v c++. A v haskellu taky IMO nejde zaručit že kus monadického kódu ten fail nezavolá. A pure věci nakonec stejně musíš protlačit do toho stavového světa (nebo ten vnější RealWorld něčím prohnat ;) ).
Předpokládejme, že máme nějakou strukturu, jako to __exit__ u Pythoního with. Tvrdíš (a já nemám důvod nesouhlasit), že musíme zajistit, aby to __exit__ nevyhazovalo výjimku. OK. Co brání, aby v případě, že kompiler zjistí, že v něm je výraz, který výjimku 1) vyhazuje odmítl kód přeložit? (Odmysleme si, že teď lepím syntaxi z Pythonu, na typované myšlení z Haskellu.)

Tudíž nemohu souhlasit, že to Typy v Haskellu neřeší. Domnívám se, že naopak. Naopak!

Monáda ti ten "fail" bude propagovat nahoru úplně stejně neviditelně jako výjimky v c++.
Jak neviditelně?! Vždyť naopak, ty monády jsou v Haskellu největší pruda, protože jdou vidět moc.


A v haskellu taky IMO nejde zaručit že kus monadického kódu ten fail nezavolá.

Tady je nějaký zmatek v názvosloví.
Monáda nemůže selhat. Monáda nemůže zavolat fail. Monáda má množinu stavů, jeden z nich může být klasifikován jako chyba. Zaručený je tam všude všechno.

Moc ti teď bohužel nerozumím.



1) Výjimkou myslím klidně i Monádu, IOMonádu, Effects, cokoliv co bychom potřebovali.


Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Jak efektivně studovat programování?
« Odpověď #95 kdy: 03. 11. 2020, 14:11:12 »
ty monády jsou v Haskellu největší pruda, protože jdou vidět moc.
Protože monáda je skoro všechno užitečné, optional, seznam, množina, futures :)
Nicméně otázka výjimek a transakčnosti s tím nijak nesouvisí. Ve FP jde něco jako noexcept udělat jednoduše.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Jak efektivně studovat programování?
« Odpověď #96 kdy: 03. 11. 2020, 14:11:49 »
Teď se Ti myslím povedla demonstrace jedné ze skutečných výhod výjimek, která ale může fungovat asi jenom v dynamických jazycích typu Pythonu - ten context manager pozná výjimku podle parametru, který ji identifikuje.

Jinak je to věc, která se dá řešit destruktorem při výstupu z rozsahu platnosti proměnné - třeba v Rustu se udělá drop v opačném pořadí (vzhledem k pořadí definice proměnné) automaticky a je vymalováno taky.

Obávám se, že rozhodně nemohu souhlasit. Už jsem tu toto téma někdy rozebíral, žel neúspěšně. Má aktuální úroveň poznání mi říká, že dynamické jazyky nepřináší nic co by principielně nešlo ve statických jazycích (a stáli bychom o to). Každopádně, asi zůstaňme u tématu.

Principiálně ano. Přemýšlím, jak by se to dělalo v C++. Pokud si pamatuju dobře, můžeš jako výjimku házet leccos, takže by maximálně šlo do exit metody poslat info, jestli výjimka byla nebo ne. U dynamických jazyků typu Pythonu je hodnota proměnné libovolná.

No ale zase, kdybychom měli k dispozici jenom bool, šlo by něco podobného i bez výjimek - třeba v Rustu. Tam se mi dokonce rýsuje i řešení s identifikací typu Erroru - pomocí downcastu by to mělo být možné vydolovat i z wrapperu, jaký dělá třeba anyhow! Tudíž asi musím vzít zpět svoje tvrzení o výhodě výjimky, protože podle všeho by to mělo jít postavit i nad Resultem - musel by se udělat příslušný trait (nebo změnit protokol Dropu) a jazyk by tomu musel vyjít vstříc.
Mnou poklamovaná jediná výhoda výjimek, ale zato zásadní - je čitelnost. Na úrovni kompileru a možností, a logiky, a bezpečnosti v následujících dvou příkladech není rozdíl:

Kód: [Vybrat]
fn div (a: Int, b: Int) -> Result Int String
if b == 0 then
Fail ("Dělení nulou")
end
Succes (a / b)

match a <- div(42, a):
Fail msg -> print(msg)
_ -> print(a)



Kód: [Vybrat]
fn div (a: Int, b: Int) -> throw Int
if b == 0 then
throw Error ("Dělení nulou")
end
a / b

try:
print(div(42, a))
catch e:
print(e)
« Poslední změna: 03. 11. 2020, 14:14:06 od BoneFlute »

Re:Jak efektivně studovat programování?
« Odpověď #97 kdy: 03. 11. 2020, 14:25:06 »
Kód: [Vybrat]
fn div (a: Int, b: Int) -> Result Int String
if b == 0 then
Fail ("Dělení nulou")
end
Succes (a / b)

match a <- div(42, a):
Fail msg -> print(msg)
_ -> print(a)



Kód: [Vybrat]
fn div (a: Int, b: Int) -> throw Int
if b == 0 then
throw Error ("Dělení nulou")
end
a / b

try:
print(div(42, a))
catch e:
print(e)

To je skutečný jazyk nebo nějaký funkcionální pseudokód?

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Jak efektivně studovat programování?
« Odpověď #98 kdy: 03. 11. 2020, 14:42:52 »
Kód: [Vybrat]
fn div (a: Int, b: Int) -> Result Int String
if b == 0 then
Fail ("Dělení nulou")
end
Succes (a / b)

match a <- div(42, a):
Fail msg -> print(msg)
_ -> print(a)



Kód: [Vybrat]
fn div (a: Int, b: Int) -> throw Int
if b == 0 then
throw Error ("Dělení nulou")
end
a / b

try:
print(div(42, a))
catch e:
print(e)

To je skutečný jazyk nebo nějaký funkcionální pseudokód?

Pseudokód. Mix Swiftu, Rustu a TypeScriptu.

Re:Jak efektivně studovat programování?
« Odpověď #99 kdy: 03. 11. 2020, 15:03:37 »
Pseudokód. Mix Swiftu, Rustu a TypeScriptu.

S tím by jste udělal díru do světa. Ještě přidat CSP.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:Jak efektivně studovat programování?
« Odpověď #100 kdy: 04. 11. 2020, 12:57:46 »
Kód: [Vybrat]
fn div (a: Int, b: Int) -> Result Int String
if b == 0 then
Fail ("Dělení nulou")
end
Succes (a / b)

match a <- div(42, a):
Fail msg -> print(msg)
_ -> print(a)



Kód: [Vybrat]
fn div (a: Int, b: Int) -> throw Int
if b == 0 then
throw Error ("Dělení nulou")
end
a / b

try:
print(div(42, a))
catch e:
print(e)

To je skutečný jazyk nebo nějaký funkcionální pseudokód?

Pseudokód. Mix Swiftu, Rustu a TypeScriptu.
Hezký mix, to by si zasloužilo parser a přinejmenším transpiler ;)