Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: BoneFlute 17. 06. 2018, 23:39:32
-
Zdravím.
Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
(Teď samozřejmě neřeším který jazyk a zda něco takového má.)
Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?
Díky.
-
Kéž by toto vlákno skončilo konstatováním, že typový systém nemůže nahradit unit testy...
-
To je hodně nezdravé přesvědčení :-D Je pravda, že jednotkové testy se často přeceňují, ale tak daleko bych nešel. Spíš bych to formuloval:
jednotkové testy nejsou tolik potřeba máte-li kvalitní typový systém
Metody/funkce ale nemají jen rozhraní (vstup-výstup, definiční obor, obor hodnot), ale (a to hlavně) nějakou logiku uvnitř, nějaký algoritmus. A ten potřebuješ otestovat. Neznám typový systém, který by dokázal deklarativně popsat i tu logiku uvnitř a nahradit testy.
-
Ono záleží na tom, jak jsou ty typy definované. Jeden ze způsobů (v Haskellu hodně využívaný) JSON serializace (aeson) jsou instance FromJSON a ToJSON. Mělo by platit
fromJSON . toJSON = Just
Což jinak než jednotkovými testy zkontrolovat nejde (kontroluje se to typicky přes QuickCheck property). Na druhou stranu je pravda, že lze ten typ serializace vyrobit tak, že se popíše způsob té serializace a ta možnost, že by bylo možné vyrobit vzájemně nekompatibilní FromJSON/ToJSON prostě nebude. I tak je ale typicky potřeba nějak otestovat, že alespoň ta knihovna je korektní.
Jednotkové testy prostě typicky píšu pro parsery. Ono se dost blbě typově popisuje, co má ten parser dělat. Pak třeba pro různé výpočty - jestli to počítá fakt správně. Pak třeba pro nějaké multi-threadované problémy (messagebus), jestli to dělá to, co to má dělat.
Metody/funkce ale nemají jen rozhraní (vstup-výstup, definiční obor, obor hodnot), ale (a to hlavně) nějakou logiku uvnitř, nějaký algoritmus. A ten potřebuješ otestovat. Neznám typový systém, který by dokázal deklarativně popsat i tu logiku uvnitř a nahradit testy.
No... dependent types dokážou hodně. https://www.youtube.com/watch?v=n-b1PYbRUOY (https://www.youtube.com/watch?v=n-b1PYbRUOY) - ukázka implementace red-black tree. Ono je to v podstatě takový model checker.... Ono se v typových systémech dá popsat docela hodně, ale je to někdy takové práce, že je rychlejší napsat si ty unit testy (nebo ještě líp quickcheck property testy)
-
Ono záleží na tom, jak jsou ty typy definované. Jeden ze způsobů (v Haskellu hodně využívaný) JSON serializace (aeson) jsou instance FromJSON a ToJSON. Mělo by platit
fromJSON . toJSON = Just
Což jinak než jednotkovými testy zkontrolovat nejde (kontroluje se to typicky přes QuickCheck property). Na druhou stranu je pravda, že lze ten typ serializace vyrobit tak, že se popíše způsob té serializace a ta možnost, že by bylo možné vyrobit vzájemně nekompatibilní FromJSON/ToJSON prostě nebude. I tak je ale typicky potřeba nějak otestovat, že alespoň ta knihovna je korektní.
Jednotkové testy prostě typicky píšu pro parsery. Ono se dost blbě typově popisuje, co má ten parser dělat. Pak třeba pro různé výpočty - jestli to počítá fakt správně. Pak třeba pro nějaké multi-threadované problémy (messagebus), jestli to dělá to, co to má dělat.
Tento příklad mi zrovna přijde celkem na pohodu. Nadefinuju si jednotlivé elementy jsonu, serialize to string. Že to dává smysl zkouknu okem, a pak zafixuju ala Elm.
-
jednotkové testy nejsou tolik potřeba máte-li kvalitní typový systém
Prosím, toto není námětem mé otázky.
-
jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
Jednotkové testy a typový systém řeší ortogonální problémy. Je ale pravda, že závislostní typy jsou nesmírně mocný nástroj a odchytí neuvěřitelné množství chyb. I tak je ale vhodné použít unit testy pro otestování logiky kódu (to typově dost dobře nejde).
-
I tak je ale vhodné použít unit testy pro otestování logiky kódu (to typově dost dobře nejde).
Proč?
-
I tak je ale vhodné použít unit testy pro otestování logiky kódu (to typově dost dobře nejde).
Proč?
Jak typy zajistis, ze tvoje metoda sum(a,b) vraci pro int a a int b spravny int soucet? Jako alternativu k primitivnimu assertEquals(3, sum(1,2)) ?
-
Kéž by toto vlákno skončilo konstatováním, že typový systém nemůže nahradit unit testy...
...a naopak.
-
Kéž by toto vlákno skončilo konstatováním, že typový systém nemůže nahradit unit testy...
...a naopak.
A naopak: kez by to vlakno zacalo konstatovanim.....
-
Kéž by toto vlákno skončilo konstatováním, že typový systém nemůže nahradit unit testy...
...a naopak.
Prosil bych ukázku použití typového systému, ve které není možné provést náhradu jednotkovými testy.
-
Prosil bych ukázku použití typového systému, ve které není možné provést náhradu jednotkovými testy.
Jedna věc je, zda je to teoreticky možné, druhá věc je, zda opravdu ručně psanými jednotkovými testy pokryjete všechny možnosti.
A snad ještě podstatnější je to, že typový systém používá programátor přímo při psaní (jako dokumentaci) – což je úplně něco jiného, než když bude zkoušet náhodně psát kód a zkoušet, jestli to projde jednotkovými testy.
-
Zdravím.
Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
(Teď samozřejmě neřeším který jazyk a zda něco takového má.)
Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?
Díky.
Je to kacir. Upalte ho!
A ted vazne. Budeme povazovat napriklad clojure.spec za soucast typoveho systemu, nebo nastroj pro testovani?
A co generativni property based testing (napr. QuickCheck)? Je definice vlastnosti funkce typova zalezitost nebo testovaci?
Btw. diky za to otazku. Samotneho by me ani nenapadlo o tom premyslet a ted mam pocit ze jsem dosahl dilciho osviceni.
-
Tento příklad mi zrovna přijde celkem na pohodu. Nadefinuju si jednotlivé elementy jsonu, serialize to string. Že to dává smysl zkouknu okem, a pak zafixuju ala Elm.
Tomu asi nerozumím - je poměrně jednoduché vytvořit ToJSON a FromJSON tak, aby to navzájem kompatibilní nebylo. Tak, jak jsou ty typeclassy oddělené, nejde typově zajistit, že to kompatibilní je. Je možné vyrobit ty typy jinak. Nicméně parsing obecně typově kontrolovat nejde - ten soulad se specifikací prostě do typu té funkce Text -> ParsedValue
nenakóduju.
Jak typy zajistis, ze tvoje metoda sum(a,b) vraci pro int a a int b spravny int soucet? Jako alternativu k primitivnimu assertEquals(3, sum(1,2)) ?
No já bych řekl, že to pude ;) (nejsem teda vůbec expert na dependent types), ale Nat (natural number) jako typ existuje, udělat součet v peanově algebře (fakt nevim o čem mluvim) jde taky a dopsat k tomu ty důkazy do těl funkcí je poměrně primitivní záležitost. Ale pravda, je to trošku cvičení o ničem...
A co generativni property based testing (napr. QuickCheck)? Je definice vlastnosti funkce typova zalezitost nebo testovaci?
IMO testovací.
-
Prosil bych ukázku použití typového systému, ve které není možné provést náhradu jednotkovými testy.
Jedna věc je, zda je to teoreticky možné, druhá věc je, zda opravdu ručně psanými jednotkovými testy pokryjete všechny možnosti.
A snad ještě podstatnější je to, že typový systém používá programátor přímo při psaní (jako dokumentaci) – což je úplně něco jiného, než když bude zkoušet náhodně psát kód a zkoušet, jestli to projde jednotkovými testy.
Ručně psanými testy (resp. generovanými) podchytím nejen typovost, což obslouží jeden test, ale i spoustu dalších možností, například reakce na nevalidní vstupy.
Jednotkové testy jsou součástí dokumentace. Jsou zárukou, že jednotka funguje jak má. Tohle typy nedokáží.
-
Jednotkové testy jsou součástí dokumentace. Jsou zárukou, že jednotka funguje jak má. Tohle typy nedokáží.
Naopak: http://elm-lang.org - elm-package diff elm-lang/core 3.0.0 4.0.0
-
Prosil bych ukázku použití typového systému, ve které není možné provést náhradu jednotkovými testy.
Jak to souvisí s mojí otázkou?
-
Ručně psanými testy (resp. generovanými) podchytím nejen typovost, což obslouží jeden test, ale i spoustu dalších možností, například reakce na nevalidní vstupy.
Jednotkové testy jsou součástí dokumentace. Jsou zárukou, že jednotka funguje jak má. Tohle typy nedokáží.
S tím, že jsou testy součástí dokumentace, nesouhlasím. Ano, typy nedokáží to, co dokáží testy – to navrhoval jen BoneFlute a myslím, že už to bylo vyvráceno.
Já bych pod klasickou testovací pyramidu přidal další vrstvu – typový systém. Platí pro to pak stále to, co pro samotnou pyramidu – to, co je vespod, je nejjednodušší, je toho tudíž nejvíc a nejrychleji to odhalí chybu. Takže co jde, pokryje se typovým systémem, když to nejde pokrýt typy, napíšou se na to jednotkové testy, když to nejde řešit jednotkovými testy, napíšou se funkční testy atd.
-
Ano, typy nedokáží to, co dokáží testy – to navrhoval jen BoneFlute a myslím, že už to bylo vyvráceno.
Kde?
Jsem doufal, že se dozvím nějaké inspirativní podněty. Ne, že to prostě jen smeteš ze stolu.
-
Ano, typy nedokáží to, co dokáží testy – to navrhoval jen BoneFlute a myslím, že už to bylo vyvráceno.
Kde?
Jsem doufal, že se dozvím nějaké inspirativní podněty. Ne, že to prostě jen smeteš ze stolu.
Tak ono jaksi uz v principu typy resi (ne nutne dost zevrubnou) kontrolu pro vsechny mozne hodnoty, zatimco testy jenom pro nejake konkretni (at uz zadane nebo v pripade property based testu generovane) hodnoty.
Tohle samozrejme neni realny produkcni kod, ale jenom vydestilovany jeden z moznych problemu (misto toho random si predstav trebas neco, co zavisi na stavu konkretniho stroje, na kterem to bezi, neco, co zavisi na case atp.):
foo(i):
if (Random.double(0, 1) > 0.0000001:
return i + 1
else
return "Life suckz!"
print(1 + foo(1))
V testovani na to nejspis neprijdes, typova kontrola to da na prvni dobrou...
-
Kde?
Hned v komentáři #6 (https://forum.root.cz/index.php?topic=18804.msg270115#msg270115).
Jsem doufal, že se dozvím nějaké inspirativní podněty. Ne, že to prostě jen smeteš ze stolu.
Nesmetl jsem to ze stolu, jenom mi připadá zbytečné opakovat, co už bylo řečeno a je triviální.
-
foo(i):
if (Random.double(0, 1) > 0.0000001:
return i + 1
else
return "Life suckz!"
print(1 + foo(1))
V testovani na to nejspis neprijdes, typova kontrola to da na prvni dobrou...
Když tam místo "Life suckz!" dáš třeba 0, což bývá častý případ, tak to typová kontrola také nedá.
-
Ano, typy nedokáží to, co dokáží testy – to navrhoval jen BoneFlute a myslím, že už to bylo vyvráceno.
Kde?
Jsem doufal, že se dozvím nějaké inspirativní podněty. Ne, že to prostě jen smeteš ze stolu.
Tak ono jaksi uz v principu typy resi (ne nutne dost zevrubnou) kontrolu pro vsechny mozne hodnoty, zatimco testy jenom pro nejake konkretni (at uz zadane nebo v pripade property based testu generovane) hodnoty.
Tohle samozrejme neni realny produkcni kod, ale jenom vydestilovany jeden z moznych problemu (misto toho random si predstav trebas neco, co zavisi na stavu konkretniho stroje, na kterem to bezi, neco, co zavisi na case atp.):
foo(i):
if (Random.double(0, 1) > 0.0000001:
return i + 1
else
return "Life suckz!"
print(1 + foo(1))
V testovani na to nejspis neprijdes, typova kontrola to da na prvni dobrou...
Ah, tak teď jsem si naběhl. Jsem tu větu pochopil přesně naopak, že Filip Jirsák tvrdí, že bylo vyvráceno, že by typová kontrola nedokázala plně nahradit testy.
-
foo(i):
if (Random.double(0, 1) > 0.0000001:
return i + 1
else
return "Life suckz!"
print(1 + foo(1))
V testovani na to nejspis neprijdes, typova kontrola to da na prvni dobrou...
Když tam místo "Life suckz!" dáš třeba 0, což bývá častý případ, tak to typová kontrola také nedá.
To by nebyl problém. Typy by vyžadovali nějakou monádu, nebo effect, a podle toho pokračovali s tím, zda se to počítá dobře.
-
Kde?
Hned v komentáři #6 (https://forum.root.cz/index.php?topic=18804.msg270115#msg270115).
To těžko. Je tam tvrzení, ne vysvětlení. Viz následující komentáře.
Jsem doufal, že se dozvím nějaké inspirativní podněty. Ne, že to prostě jen smeteš ze stolu.
Nesmetl jsem to ze stolu, jenom mi připadá zbytečné opakovat, co už bylo řečeno a je triviální.
Ano, neboli žádné argumenty, jen tvrzení, a smetení ze stolu.
Když by to bylo triviální, tak předvedeš nějaký pěkný kód. Chci snad tak moc?
-
Ah, tak teď jsem si naběhl. Jsem tu větu pochopil přesně naopak, že Filip Jirsák tvrdí, že bylo vyvráceno, že by typová kontrola nedokázala plně nahradit testy.
Pro pořádek, tvrdím, že typová kontrola nedokáže plně nahradit jednotkové testy (např. nedokáže zkontrolovat algoritmy). Dále jsem reagoval na Kita, že jednotkové testy sice teoreticky mohou nahradit typovou kontrolu (a dělá se to tak u jazyků bez typů), ale prakticky to nikdy nebude úplná kontrola, protože psát jednotkové testy je podstatně náročnější, než používat typy.
-
Tento příklad mi zrovna přijde celkem na pohodu. Nadefinuju si jednotlivé elementy jsonu, serialize to string. Že to dává smysl zkouknu okem, a pak zafixuju ala Elm.
Tomu asi nerozumím - je poměrně jednoduché vytvořit ToJSON a FromJSON tak, aby to navzájem kompatibilní nebylo. Tak, jak jsou ty typeclassy oddělené, nejde typově zajistit, že to kompatibilní je. Je možné vyrobit ty typy jinak. Nicméně parsing obecně typově kontrolovat nejde - ten soulad se specifikací prostě do typu té funkce Text -> ParsedValue
nenakóduju.
Rozumím.
(toJSON json) -> str == (fromJSON str) -> json
by nešlo? Kompiler by musel ověřit, zda všechny varianty stromu, když se vygenerují do stringu a pak následně naparsují jsou shodné.
-
To těžko. Je tam tvrzení, ne vysvětlení. Viz následující komentáře.
Následující komentář je váš dotaz na vysvětlení a hned následující komentář je vysvětlení.
Když by to bylo triviální, tak předvedeš nějaký pěkný kód. Chci snad tak moc?
Vždyť ten kód byl v komentáři odpovídajícím na vaše „Proč?“ Já bych tu funkci akorát jinak nazval, jinak je kód stejný, protože to je první, co každého napadne:
//sečte dvě čísla
int add(int x, int y) {
return x - y;
}
-
To těžko. Je tam tvrzení, ne vysvětlení. Viz následující komentáře.
Následující komentář je váš dotaz na vysvětlení a hned následující komentář je vysvětlení.
Když by to bylo triviální, tak předvedeš nějaký pěkný kód. Chci snad tak moc?
Vždyť ten kód byl v komentáři odpovídajícím na vaše „Proč?“ Já bych tu funkci akorát jinak nazval, jinak je kód stejný, protože to je první, co každého napadne:
//sečte dvě čísla
int add(int x, int y) {
return x - y;
}
A následně bylo poukázáno, že toto by šlo: https://forum.root.cz/index.php?topic=18804.msg270160#msg270160
Prosím něco lepšího :-)
-
I tak je ale vhodné použít unit testy pro otestování logiky kódu (to typově dost dobře nejde).
Proč?
Protože třeba funkce vracející k n n-té prvočíslo. Prostě logika se typovým systémem v obecnosti otestovat nedá. Se závislostním typovým systémem jde ale podchytit mnoho věcí již během překladu, což je jeho největší výhoda. Čistě teoreticky kontrolu za běhu nelze zcela vyloučit, protože halting problem. Nicméně některé jazyky zaručují i totalitu funkcí.
-
I tak je ale vhodné použít unit testy pro otestování logiky kódu (to typově dost dobře nejde).
Proč?
Protože třeba funkce vracející k n n-té prvočíslo. Prostě logika se typovým systémem v obecnosti otestovat nedá. Se závislostním typovým systémem jde ale podchytit mnoho věcí již během překladu, což je jeho největší výhoda. Čistě teoreticky kontrolu za běhu nelze zcela vyloučit, protože halting problem. Nicméně některé jazyky zaručují i totalitu funkcí.
Rozumím. Prvočísla sou svině.
Ale pokud to chápu dobře, tak zde je problém v tom, že prvočísla se nedají ani otestovat. U typů zase narazím na to, že typ se snaží být ultimátní. Takže bych se přimlouval za plichtu :-) V tomto případě.
-
foo(i):
if (Random.double(0, 1) > 0.0000001:
return i + 1
else
return "Life suckz!"
print(1 + foo(1))
V testovani na to nejspis neprijdes, typova kontrola to da na prvni dobrou...
Když tam místo "Life suckz!" dáš třeba 0, což bývá častý případ, tak to typová kontrola také nedá.
On taky nikdo nerika, ze typova kontrola da vsechno....
-
Statický typový systém nemá s testováním nic společného. Historicky vznikl kvůli tomu, aby kompilátor mohl generovat rychlý kompaktní kód. Na návrh programu má poněkud komplikační dopad - návrh musí být podřízen statickému typování, ale bez něj by byl jednodušší.
Unit testy píšu kvůli testování funkčnosti, ne kvůli ověřování typů. Pokud budu mít kupř. za úkol napsat nějaký grafový algoritmus, tak unit testem zkouším, zda funguje tak jak má, a ne jestli tam jdou "správné" typy. Statická typová kontrola, jak se zdá, v někom vzbuzuje falešný pocit, že je to nějaký test navíc. Ale to není! Statická typová kontrola mi hází při kompilaci chyby, které tam jsou, jen protože se vyžaduje statická typovost. Je to tak trochu začarovaný kruh. Na jednu stranu mě sice zarazí, pokud omylem použiju nějakou proměnnou na něco jiného (samozřejmě tedy jen pokud to má náhodou i jiný typ), ale na druhou stranu mi zase komplikuje práci, když by ta jedna proměnná klidně mohla obsahovat různorodá data.
Nechci hodnotit, co je lepší nebo horší, obojí má podle mě své místo a opodstatnění. Ale statické typování rozhodně žádné unit testování nenahrazuje.
(osobně mi statické typování překáží tím více, na čím vyšší úrovni abstrakce se pohybuji; na low-level záležitosti mi připadá jako naprosto perfektní)
-
I tak je ale vhodné použít unit testy pro otestování logiky kódu (to typově dost dobře nejde).
Proč?
Protože třeba funkce vracející k n n-té prvočíslo. Prostě logika se typovým systémem v obecnosti otestovat nedá. Se závislostním typovým systémem jde ale podchytit mnoho věcí již během překladu, což je jeho největší výhoda. Čistě teoreticky kontrolu za běhu nelze zcela vyloučit, protože halting problem. Nicméně některé jazyky zaručují i totalitu funkcí.
Rozumím. Prvočísla sou svině.
Ale pokud to chápu dobře, tak zde je problém v tom, že prvočísla se nedají ani otestovat. U typů zase narazím na to, že typ se snaží být ultimátní. Takže bych se přimlouval za plichtu :-) V tomto případě.
Obecně platí, že typová kontrola zajistí korektnost vstupu a správný typ výstupu a že všechny funkce na sebe bezchybně navazují. Zároveň zajistí přesměrování chyb za běhu. Nemůže ovšem garantovat správnost výsledků (v některých případech ano, ale obecně ne).
-
Ale pokud to chápu dobře, tak zde je problém v tom, že prvočísla se nedají ani otestovat. U typů zase narazím na to, že typ se snaží být ultimátní. Takže bych se přimlouval za plichtu :-) V tomto případě.
Prvočíslo se dá otestovat velmi snadno.
-
Nemůže ovšem garantovat správnost výsledků (v některých případech ano, ale obecně ne).
Dobře. Ale já se táži proč.
-
Statický typový systém nemá s testováním nic společného. Historicky vznikl kvůli tomu, aby kompilátor mohl generovat rychlý kompaktní kód. Na návrh programu má poněkud komplikační dopad - návrh musí být podřízen statickému typování, ale bez něj by byl jednodušší.
Unit testy píšu kvůli testování funkčnosti, ne kvůli ověřování typů. Pokud budu mít kupř. za úkol napsat nějaký grafový algoritmus, tak unit testem zkouším, zda funguje tak jak má, a ne jestli tam jdou "správné" typy. Statická typová kontrola, jak se zdá, v někom vzbuzuje falešný pocit, že je to nějaký test navíc. Ale to není! Statická typová kontrola mi hází při kompilaci chyby, které tam jsou, jen protože se vyžaduje statická typovost. Je to tak trochu začarovaný kruh. Na jednu stranu mě sice zarazí, pokud omylem použiju nějakou proměnnou na něco jiného (samozřejmě tedy jen pokud to má náhodou i jiný typ), ale na druhou stranu mi zase komplikuje práci, když by ta jedna proměnná klidně mohla obsahovat různorodá data.
Nechci hodnotit, co je lepší nebo horší, obojí má podle mě své místo a opodstatnění. Ale statické typování rozhodně žádné unit testování nenahrazuje.
(osobně mi statické typování překáží tím více, na čím vyšší úrovni abstrakce se pohybáváuji; na low-level záležitosti mi připadá jako naprosto perfektní)
Obávám se, že žijem každý úplně v jiném světě.
-
Stalo se mi, že:
Psal jsem kód, kde se řadil strom (uzel, mající n potomků). Každý prvek v seznamu potomků měl být seřazen. Psal jsem na to testy asi tejden. Vždycky všechno prošlo, dal jsem na review, a poslali mi to zpět, že za těchto a těchto okolností to padá.
Pak jsem se dožral a napsal jsem si generátor všech možností - tedy dle mého chápání něco jako statický typ. Pak to půl hodiny chroupalo, vyhodilo pět chybujících scénářů, ty jsem zohlednil a byl klid.
Psal jsem parser. Unittesty jsou samozřejmě na to jak stvořené. Všechno krásně přímočaré, supr. Pochvaloval jsem si, jak umím krásně psát testy. A pak jsem si uvědomil, že jsem idiot. Kdyžbych napsal jen specifikaci toho formátu, a napsal na to generátor, tak se s tím nemusím tak patlat.
Tak jasně, u typů se musí víc přemýšlet. Ale nerad bych odbočoval do těchto bažin.
Rád bych v tomto vláknu ještě pár ukázek nějakého kódu, kde si typy nabijou hubu. Zatím uvedl Gödel uvedl ty prvočísla. To máme jeden. Napadá vás něco dalšího?
-
Pak jsem se dožral a napsal jsem si generátor všech možností - tedy dle mého chápání něco jako statický typ.
Tak to je nejake divne chapani...
-
Celé mi to připadá jako souboj mezi funkcionálním a objektovým programováním. Zatímco funkcionální jazyky se opírají zejména o typy a dokazování správnosti, objektové jazyky se opírají zejména o testy. V tomto kontextu se nedá rozhodnout, co z nich je lepší.
Otázku bych tedy rozdělil na dvě:
- Myslíte si, že ve funkcionálním jazyce, ve kterém máte kvalitní typový systém, jsou potřebné jednotkové testy?
- Myslíte si, že v objektovém jazyce, ve kterém máte jednotkové testy, je potřebný typový systém?
-
Zatímco funkcionální jazyky se opírají zejména o typy a dokazování správnosti
Napriklad lisp nebo lambda calculus, co?
- Myslíte si, že ve funkcionálním jazyce, ve kterém máte kvalitní typový systém, jsou potřebné jednotkové testy?
- Myslíte si, že v objektovém jazyce, ve kterém máte jednotkové testy, je potřebný typový systém?
Ano a ano. Protoze jedno umi snadno resit problemy, ktere to druhe nezvladne nebo zvladne bolestive.
-
Tak ono jaksi uz v principu typy resi (ne nutne dost zevrubnou) kontrolu pro vsechny mozne hodnoty, zatimco testy jenom pro nejake konkretni (at uz zadane nebo v pripade property based testu generovane) hodnoty.
ta kontrola může být dost komplikovaná. Samotnou definici typu potom musíte testovat na nějakých konkrétních hodnotách. Napadá mě třeba typ reprezentující číslo kreditní karty. Je docela jedno, jestli je validace součástí typu nebo v samostatné funkci.
-
Pak jsem se dožral a napsal jsem si generátor všech možností - tedy dle mého chápání něco jako statický typ.
Tak to je nejake divne chapani...
Tak samozřejmě :-) Ber to prosím s rezervou.
Já si z typů beru to, že
- jsou deklarativní (a ideálně expresivní) - deklarativní s důrazem na "popisné"
- jsou ultimátní, tedy pokrývají všechny scénáře
- počítá to stroj
- a samozřejmě nesmíme zapomenout na záruky
Dále jsem se poučil studiem nějakých věcí, že typy jsou mnohem víc, než to, co nám ukazuje Java. A snažím se zchladit své nadšení hledáním, kde to má hranice. Protože zatím všechny případy nějaké logiky, které mě napadali tak se při troše fantazie dali typy popsat.
-
Tak ono jaksi uz v principu typy resi (ne nutne dost zevrubnou) kontrolu pro vsechny mozne hodnoty, zatimco testy jenom pro nejake konkretni (at uz zadane nebo v pripade property based testu generovane) hodnoty.
ta kontrola může být dost komplikovaná. Samotnou definici typu potom musíte testovat na nějakých konkrétních hodnotách. Napadá mě třeba typ reprezentující číslo kreditní karty. Je docela jedno, jestli je validace součástí typu nebo v samostatné funkci.
Co na té kartě chceš testovat?
-
Tak ono jaksi uz v principu typy resi (ne nutne dost zevrubnou) kontrolu pro vsechny mozne hodnoty, zatimco testy jenom pro nejake konkretni (at uz zadane nebo v pripade property based testu generovane) hodnoty.
ta kontrola může být dost komplikovaná. Samotnou definici typu potom musíte testovat na nějakých konkrétních hodnotách. Napadá mě třeba typ reprezentující číslo kreditní karty. Je docela jedno, jestli je validace součástí typu nebo v samostatné funkci.
Co na té kartě chceš testovat?
https://en.wikipedia.org/wiki/Luhn_algorithm
-
Tak ono jaksi uz v principu typy resi (ne nutne dost zevrubnou) kontrolu pro vsechny mozne hodnoty, zatimco testy jenom pro nejake konkretni (at uz zadane nebo v pripade property based testu generovane) hodnoty.
ta kontrola může být dost komplikovaná. Samotnou definici typu potom musíte testovat na nějakých konkrétních hodnotách. Napadá mě třeba typ reprezentující číslo kreditní karty. Je docela jedno, jestli je validace součástí typu nebo v samostatné funkci.
Co na té kartě chceš testovat?
https://en.wikipedia.org/wiki/Luhn_algorithm
Díky. V tomto případě mi stále ještě fantazie neselhává. Ale díky.
-
A následně bylo poukázáno, že toto by šlo: https://forum.root.cz/index.php?topic=18804.msg270160#msg270160
Nikoli, bylo poukázáno, že by šlo něco jiného. Sčítání i odčítání dvou čísel jsou legitimní operace a záleží na použití, kdy použiju tu a kdy onu.
Ale pokud si myslíte, že je to řešitelné typovým systémem, ukažte váš kód. Ukažte, jak byste navrhl typový systém, který by u následujícího kódu odhalil chybu.
int add(int x, int y) {
return x - y;
}
int sub(int x, int y) {
return x - y;
}
Mně připadá, že je triviálně vidět, že ta funkce add() je špatně pojmenovaná (a případně má špatnou dokumentaci), což nevyřeší žádný typový systém. Ale budu rád, když mne vyvedete z omylu.
-
Mně připadá, že je triviálně vidět, že ta funkce add() je špatně pojmenovaná (a případně má špatnou dokumentaci), což nevyřeší žádný typový systém. Ale budu rád, když mne vyvedete z omylu.
Ukaž mi unittest s témže.
Bavíme se (doufám) o tvrzení, že typy plně nahradí unittesty. Nic víc neřeším.
-
Mně připadá, že je triviálně vidět, že ta funkce add() je špatně pojmenovaná (a případně má špatnou dokumentaci), což nevyřeší žádný typový systém. Ale budu rád, když mne vyvedete z omylu.
Ukaž mi unittest s témže.
Bavíme se (doufám) o tvrzení, že typy plně nahradí unittesty. Nic víc neřeším.
def add(x: int, y: int) -> int:
"""
>>> add(1, 1)
2
"""
return x - y
-
Bavíme se (doufám) o tvrzení, že typy plně nahradí unittesty. Nic víc neřeším.
Bavíme se o vašem tvrzení, že by unittesty byly plně nahrazeny typy.
Ukaž mi unittest s témže.
To opravdu takovou trivialitu neodkážete napsat sám? Tu chybu odhalí už takhle primitivní test, který nezkoumá žádné mezní stavy, ale prostě jen otestuje jeden jednoduchý nezajímavý případ.
int add(int x, int y) {
return x - y
}
int sub(int x, int y) {
return x - y
}
assert add(3, 2) == 5
assert sub(3, 2) == 1
-
Jsem nečetl celé vlákno, ale jednotkové testy jsem viděl na projektu v bance a je nutné si ujasnit, o co jde. Jednotkový test je myšleno otestování metod třídy izolovaně od ostatních tříd, tedy zahrnuje intenzivní mockování.
Když píšu nějakou metodu, tak si zároveň k ní udělám jednotkový test. Pokud dělám velký projekt, který bude v budoucnu velice složitý, udělám ten jendotkový test zpravidla vždy, i pro jednoduchou metodu. Zároveň to udělat muséím, protože se na takovém projektu měří test coverage. Zároveň si jednotkový test napíšu i v menším projektu ze svobodné vůle, protože mi šetří čas pro teď a i pro budoucnost: otestuju si tam, že metoda, kterou jsem právě napsal, nebo nějaká posloupnost metod, dělá to, co chci, aby dělala - tzn. místo abych otrocky pouštěl aplikaci, přihlašoval se do ní a zkoušel nově napsanou ufnkcionalitu, testuju si to tím unit testem a zároveń vyvíjím - je to značně rychlejší. Konrétní příklad: používám v metodě nějakou knihovnu a nejsem si jistý, jak funguje - např. knihovna pro parsování vstupních parametrů z konzole - udělám si proto k tomu unit test, ve kterém si ověřím, jak se vlastně ta knihovna chová.
Když někdo tvrdí, že Unit testy nejsou potřeba, když je silný typový systém, tak si myslím, že dotyčný dělá zřejmě v nějakém Pythonu nebo Javascriptu. Já dělám v javě, která silný typový systém má, a přesto se unit testy dělají, protože jejich primární goal je zafixovat chování kódu proti překlepům (někdo prostě napíš nechtěně něco do kódu, nevšimne si toho a pak to commitne, no a produkní incient e na světě), proti nevhodným změnám (někdo v kódu neotestuje na null něco, co null být může, a unit test to může podchytit), ba či přímo proti zásadním změnám funkce kódu. Unit testem taky můžu upozornit kolegy na to, že metoda, nebo její část, se opravdu musí chovat tak, jak je to v kódu - z různých důvodů.
-
Bavíme se (doufám) o tvrzení, že typy plně nahradí unittesty. Nic víc neřeším.
Bavíme se o vašem tvrzení, že by unittesty byly plně nahrazeny typy.
Ukaž mi unittest s témže.
To opravdu takovou trivialitu neodkážete napsat sám? Tu chybu odhalí už takhle primitivní test, který nezkoumá žádné mezní stavy, ale prostě jen otestuje jeden jednoduchý nezajímavý případ.
int add(int x, int y) {
return x - y
}
int sub(int x, int y) {
return x - y
}
assert add(3, 2) == 5
assert sub(3, 2) == 1
To není to co tvrdíš.
Sorry, tvé příspěvky nejsou vůbec inspirativní. Nebudu se tedy tebou již zabejvat.
-
Bavíme se (doufám) o tvrzení, že typy plně nahradí unittesty. Nic víc neřeším.
Bavíme se o vašem tvrzení, že by unittesty byly plně nahrazeny typy.
Ukaž mi unittest s témže.
To opravdu takovou trivialitu neodkážete napsat sám? Tu chybu odhalí už takhle primitivní test, který nezkoumá žádné mezní stavy, ale prostě jen otestuje jeden jednoduchý nezajímavý případ.
int add(int x, int y) {
return x - y
}
int sub(int x, int y) {
return x - y
}
assert add(3, 2) == 5
assert sub(3, 2) == 1
To není to co tvrdíš.
Sorry, tvé příspěvky nejsou vůbec inspirativní. Nebudu se tedy tebou již zabejvat.
Chces inspiraci nebo jednoduchou a celkem rozumnou odpoved?
-
To není to co tvrdíš.
vyvrací to co tvrdíš ty.
-
Já dělám v javě, která silný typový systém má,
Tak ano, Java silný typový systém má, ale co si budem povídat, stojí za starou belu. V porovnáním s takovou Scalou, a to přitom ani ta nevyužívá všeho, co se dá typy udělat.
Jinak k příkladům, které jsi uvedl: null, změna signatury, změna chování, překlep, dokumentace chování - to všechno typy zvládnou (zvládli by).
-
Jirsák by musel udělat tu stejnou chybu na dvou místech nezávisle, aby ji neodhalil. Tobě stačí překlep na jednom místě ve znaménku.
-
Já dělám v javě, která silný typový systém má, a přesto se unit testy dělají, protože jejich primární goal je zafixovat chování kódu (...)
Akorát nevím jestli je v původním dotazu míněn typový systém javy - hádám že jsou míněny mnohem silnější typové systémy, které toho garantují mnohem víc. Možná by mohl BoneFlute upřesnit?
Jinak taky záleží, jak kdo unit testy používá, někdo testuje skutečně izolovanou funkčnost, někdo to spíš používá jako integrační testy (testuje spolupráci více jednotek a třeba ani tolik nemockuje).
-
(toJSON json) -> str == (fromJSON str) -> json
by nešlo? Kompiler by musel ověřit, zda všechny varianty stromu, když se vygenerují do stringu a pak následně naparsují jsou shodné.
No, obvávám se, že to je ale obecně vzato nerozhodnutelný problém... (i.e. halting problem). tímpádem to řešit typy nejde. Těch "všech variant stromu" může být nekonečno, takže to nejde ani po jednom projít.
-
Celé mi to připadá jako souboj mezi funkcionálním a objektovým programováním. Zatímco funkcionální jazyky se opírají zejména o typy a dokazování správnosti, objektové jazyky se opírají zejména o testy. V tomto kontextu se nedá rozhodnout, co z nich je lepší.
Otázku bych tedy rozdělil na dvě:
- Myslíte si, že ve funkcionálním jazyce, ve kterém máte kvalitní typový systém, jsou potřebné jednotkové testy?
- Myslíte si, že v objektovém jazyce, ve kterém máte jednotkové testy, je potřebný typový systém?
Je to ortogonální, i v λ-kalkulu se striktní typovou kontrolou (takovému formalismu se ostatně říká “jednoduchá teorie typů”) se hodí testy.
-
Mně připadá, že je triviálně vidět, že ta funkce add() je špatně pojmenovaná (a případně má špatnou dokumentaci), což nevyřeší žádný typový systém. Ale budu rád, když mne vyvedete z omylu.
Ukaž mi unittest s témže.
Bavíme se (doufám) o tvrzení, že typy plně nahradí unittesty. Nic víc neřeším.
def add(x: int, y: int) -> int:
"""
>>> add(1, 1)
2
"""
return x - y
Stejně tak může být:
def add(x: int, y: int) -> int:
"""
>>> add(1, 1)
3
"""
return x + y
Každopádně toto by měli řešit závislostní typy. Já jsem si to přeložil jako:
add x y == y * succ x
-
(toJSON json) -> str == (fromJSON str) -> json
by nešlo? Kompiler by musel ověřit, zda všechny varianty stromu, když se vygenerují do stringu a pak následně naparsují jsou shodné.
No, obvávám se, že to je ale obecně vzato nerozhodnutelný problém... (i.e. halting problem). tímpádem to řešit typy nejde. Těch "všech variant stromu" může být nekonečno, takže to nejde ani po jednom projít.
S timhle opatrne...
Halting problem je, kdyz ti nekdo (nepritel...) prinese program a ty mas rozhodovat o nem. Ty jsi v situaci, kdy sam pises program a typovy system ti na nej klade nejake omezeni. Takze ten zkoumany program neni libovolny, ale vznikly nejakym zpusobem (trebas tak, ze spolu s nim vznika "dukaz" jeho korektnosti).
-
Chces inspiraci nebo jednoduchou a celkem rozumnou odpoved?
Tak ideálně to druhé. Ale spokojím se i s tím prvním.
-
Jirsák by musel udělat tu stejnou chybu na dvou místech nezávisle, aby ji neodhalil. Tobě stačí překlep na jednom místě ve znaménku.
Křížová kontrola, tomu rozumím. Mám výhrady, ale beru :-) Takže to máme dva.
-
(toJSON json) -> str == (fromJSON str) -> json
by nešlo? Kompiler by musel ověřit, zda všechny varianty stromu, když se vygenerují do stringu a pak následně naparsují jsou shodné.
No, obvávám se, že to je ale obecně vzato nerozhodnutelný problém... (i.e. halting problem). tímpádem to řešit typy nejde. Těch "všech variant stromu" může být nekonečno, takže to nejde ani po jednom projít.
S timhle opatrne...
Halting problem je, kdyz ti nekdo (nepritel...) prinese program a ty mas rozhodovat o nem. Ty jsi v situaci, kdy sam pises program a typovy system ti na nej klade nejake omezeni. Takze ten zkoumany program neni libovolny, ale vznikly nejakym zpusobem (trebas tak, ze spolu s nim vznika "dukaz" jeho korektnosti).
Já to tak myslel - ty typeclassy jsou interface, nepřítel přinese program a kompilere rozhodni, zda to platí. No a protože možných vstupů je nekonečno, tak to nejde projít, tak by připadalo v úvahu nějaké rozhodnutí na jiné úrovni - ale to je halting problém. Takže s takto definovanými typy (FromJSON, ToJSON) nejde typově ošetřit, že ty instance jsou navzájem kompatibilní. (s jinak definovanými instancemi by to samozřejmě jít mohlo)
-
Stejně tak může být:
def add(x: int, y: int) -> int:
"""
>>> add(1, 1)
3
"""
return x + y
Každopádně toto by měli řešit závislostní typy. Já jsem si to přeložil jako:
add x y == y * succ x
když udělám chybu v testu, tak test neprojde a chybu odhalím. Je nepravděpodobné, že bude stejná chyba v testu i v kódu.
-
To není to co tvrdíš.
Jak to, že ne? Je to chyba v kódu, jednotkový test tu chybu odhalí, žádný použitelný typový systém jí nezabrání ani neodhalí. Je to tedy vyvrácení vašeho tvrzení, že by bylo možné všechny jednotkové testy nahradit typovým systémem.
Sorry, tvé příspěvky nejsou vůbec inspirativní. Nebudu se tedy tebou již zabejvat.
Ona vůbec inspirativní není vaše otázka, protože je triviální přijít na to, že existují algoritmy, které jsou platné a legitimní, a které je možné zaměnit za jiné platné a legitimní algoritmy. To typový systém nemůže zachytit, protože musí povolit oba dva algoritmy, ale nedokáže rozlišit, že jste chtěl použít jiný algoritmus. Sčítání a odčítání jsou ty nejjednodušší případy (někdy potřebujete sčítat, někdy odčítat, a žádný typový systém nezajistí, abyste nemohl použít odčítání tam, kde správně má být sčítání).
Spíš to vypadá, že jste z toho zmatený a není vám moc jasné, co zajišťuje typový systém a k čemu slouží jednotkové testy.
Tak snad pro vás bude inspirativní alespoň to, že největší slabinou jednotkových testů je to, že testují jenom případy, u kterých autor testů předpokládá, že by u nich mohl nastat problém. A dále to, že jedna z nejpodstatnějších dovedností programátora je právě schopnost odhalit ty problematické situace.
-
Dále jsem se poučil studiem nějakých věcí, že typy jsou mnohem víc, než to, co nám ukazuje Java.
To rozhodně, v Javě je typový systém dost primitivní. Na druhou stranu čím mocnější typový systém, tím delší doba překladu, na jedné přednášce o Coqu si pochvalovali, jak jim překladač dokazuje korektnost, ale překlad trval hodiny kvůli závislostním typům.
-
Akorát nevím jestli je v původním dotazu míněn typový systém javy - hádám že jsou míněny mnohem silnější typové systémy, které toho garantují mnohem víc. Možná by mohl BoneFlute upřesnit?
Úplně ten nejlepší (Agda, Idris, Eff) a ještě o kousek dál. Bavím se čistě na poli teorie. Takže to, že to bude nepraktické nevadí. Nerozhodnutelnost už samozřejmě ano. Přičemž zase ne zas tak teorie, abych třeba nemohl prohlásit, že "typový systém má omezení, že dokáže rozhodnout jen pro prvních milión prvočísel", třeba.
-
(toJSON json) -> str == (fromJSON str) -> json
by nešlo? Kompiler by musel ověřit, zda všechny varianty stromu, když se vygenerují do stringu a pak následně naparsují jsou shodné.
No, obvávám se, že to je ale obecně vzato nerozhodnutelný problém... (i.e. halting problem). tímpádem to řešit typy nejde. Těch "všech variant stromu" může být nekonečno, takže to nejde ani po jednom projít.
S timhle opatrne...
Halting problem je, kdyz ti nekdo (nepritel...) prinese program a ty mas rozhodovat o nem. Ty jsi v situaci, kdy sam pises program a typovy system ti na nej klade nejake omezeni. Takze ten zkoumany program neni libovolny, ale vznikly nejakym zpusobem (trebas tak, ze spolu s nim vznika "dukaz" jeho korektnosti).
Já to tak myslel - ty typeclassy jsou interface, nepřítel přinese program a kompilere rozhodni, zda to platí. No a protože možných vstupů je nekonečno, tak to nejde projít, tak by připadalo v úvahu nějaké rozhodnutí na jiné úrovni - ale to je halting problém. Takže s takto definovanými typy (FromJSON, ToJSON) nejde typově ošetřit, že ty instance jsou navzájem kompatibilní. (s jinak definovanými instancemi by to samozřejmě jít mohlo)
Ale u typoveho systemu nutis nepritele, aby prinesl program s dalsimi (strojove overitelnymi) castmi...
-
To není to co tvrdíš.
Jak to, že ne? Je to chyba v kódu, jednotkový test tu chybu odhalí, žádný použitelný typový systém jí nezabrání ani neodhalí. Je to tedy vyvrácení vašeho tvrzení, že by bylo možné všechny jednotkové testy nahradit typovým systémem.
elm-package odhalí
Tak snad pro vás bude inspirativní alespoň to, že největší slabinou jednotkových testů je to, že testují jenom případy, u kterých autor testů předpokládá, že by u nich mohl nastat problém. A dále to, že jedna z nejpodstatnějších dovedností programátora je právě schopnost odhalit ty problematické situace.
Je mi líto, to moc dobře vím. Je to jeden z důvodů proč typy mám rád.
-
Dále jsem se poučil studiem nějakých věcí, že typy jsou mnohem víc, než to, co nám ukazuje Java.
To rozhodně, v Javě je typový systém dost primitivní. Na druhou stranu čím mocnější typový systém, tím delší doba překladu, na jedné přednášce o Coqu si pochvalovali, jak jim překladač dokazuje korektnost, ale překlad trval hodiny kvůli závislostním typům.
Jsem si toho vědom. Na druhou stranu se to dá (snad) obejít. Třeba tím (naivně), že při dev procesu ty typy mám vypnuté, a teprve při releasu tomu dám nažrat.
-
Chjo, tak jinak.
Předpokládejme, že Pepa píše program a nechce v něm mít chyby. A chce využít všechny možnosti, ale co nejjednodušším způsobem. A co nejrychlej. Takže:
- Je lepší při chybě program nepřeložit a dostat rovnou hlášku "type mismatch @ line 256", než týden procházet logy
- Je lepší, pokud má funkci
speed_t avgSpeed( distance_t distance, time_t time) { ... }
a vyběhne na něj při překladu rovnou varování, že prohodil argumenty, než když na to přijde tesťák náhodou
- A chce mít podchyceno, že se opravdu implementuje správný vzorec, takže dá i unit test, který ho upoyorní, že ten výpočet je blbě.
- A protože chce vědět, jestli větší celek programu běhá správně, hodít am i integrační testy.
Takže s čím se to dělá efektivně ohlídá datový typ (bez práce a před commitem), co se dělá ohlídá unit test.
Pokud se i "s čím to dělám" musí (v základu) hlídat unit testem, tak je něco blbě (= jazyk stojí za starou bačkoru)
-
Chjo, tak jinak.
Předpokládejme, že Pepa píše program a nechce v něm mít chyby. A chce využít všechny možnosti, ale co nejjednodušším způsobem. A co nejrychlej. Takže:
- Je lepší při chybě program nepřeložit a dostat rovnou hlášku "type mismatch @ line 256", než týden procházet logy
- Je lepší, pokud má funkci
speed_t avgSpeed( distance_t distance, time_t time) { ... }
a vyběhne na něj při překladu rovnou varování, že prohodil argumenty, než když na to přijde tesťák náhodou
- A chce mít podchyceno, že se opravdu implementuje správný vzorec, takže dá i unit test, který ho upoyorní, že ten výpočet je blbě.
- A protože chce vědět, jestli větší celek programu běhá správně, hodít am i integrační testy.
Takže s čím se to dělá efektivně ohlídá datový typ (bez práce a před commitem), co se dělá ohlídá unit test.
Pokud se i "s čím to dělám" musí (v základu) hlídat unit testem, tak je něco blbě (= jazyk stojí za starou bačkoru)
Integrační testy sem prosím netahat.
-
Ale pokud si myslíte, že je to řešitelné typovým systémem, ukažte váš kód. Ukažte, jak byste navrhl typový systém, který by u následujícího kódu odhalil chybu.
int add(int x, int y) {
return x - y;
}
int sub(int x, int y) {
return x - y;
}
Psal jsem, že v tom nejsem expert...ale ta idea je něco ve stylu
(ty typy musí být nějak jinak, ale nedám to dohromady)
add :: (HNat a, HNat b, HAdd a b c) => a -> b -> c
add ... následuje přičítání jedničky, pokud první argument není 0...
Je to dost zbytečné cvičení, a tak trošku to přesměrovává problém od "spletl jsem se v pojmenování" na "spletl jsem se v typu". Ale svým způsobem to je třeba odpověď na autorovu otázku - ano, typový systém odhalí chyby v kódu, ale jak odhalí chyby v typech?
Ale u typoveho systemu nutis nepritele, aby prinesl program s dalsimi (strojove overitelnymi) castmi...
Teď nerozumím - typový systém třeba Javy umí rozhodnout Null/NonNull (někdy...) bez ohledu na to, že to vlastně v tom typovém systému "není". Ty typeclassy FromJSON/ToJSON jsou udělány tak, že kompiler kompatibilitu prostě rozhodnout nemůže. Halting problém byl v tom smyslu, že i kdyby na to kompiler šel analýzou kódu jako Java, tak tu property "fromJSON . toJson = Just" stejně nemůže (obecně) rozhodnout.
-
Psal jsem, že v tom nejsem expert...ale ta idea je něco ve stylu
(ty typy musí být nějak jinak, ale nedám to dohromady)
add :: (HNat a, HNat b, HAdd a b c) => a -> b -> c
add ... následuje přičítání jedničky, pokud první argument není 0...
Je to dost zbytečné cvičení, a tak trošku to přesměrovává problém od "spletl jsem se v pojmenování" na "spletl jsem se v typu". Ale svým způsobem to je třeba odpověď na autorovu otázku - ano, typový systém odhalí chyby v kódu, ale jak odhalí chyby v typech?
Ano, křížová kontrola. Přiznávám unittestům bod :-)
Stejně jako se můžeš splést v typu, můžeš se splést v testu. Jenže jako v testu kontroluješ, zda to testuje co má pohledem, stejně tak můžeš u typu. Jako v testu kontroluješ změnu oproti předchozímu, stejně tak to umí elm u typů.
Takže zůstává jen ta křížová kontrola, kdy u testů to píšu dvakrát. Jenže, stejně tak může kompilátor generovat usecase, a ty ukazovat... No ale to už jsme zase trochu jinde.
Ale u typoveho systemu nutis nepritele, aby prinesl program s dalsimi (strojove overitelnymi) castmi...
Teď nerozumím - typový systém třeba Javy umí rozhodnout Null/NonNull (někdy...) bez ohledu na to, že to vlastně v tom typovém systému "není". Ty typeclassy FromJSON/ToJSON jsou udělány tak, že kompiler kompatibilitu prostě rozhodnout nemůže. Halting problém byl v tom smyslu, že i kdyby na to kompiler šel analýzou kódu jako Java, tak tu property "fromJSON . toJson = Just" stejně nemůže (obecně) rozhodnout.
Předpokládám, že kompiler:
Mám json element číslo, převést na string a zpět. Element string, detto. Element Struct obsahující číslo, na string a zpět. Dále je to rekursivní, takže to už nemusím.
Asi by se našlo něco, kde by to začalo být hodně divoké. Jenže pak je otázka, zda v takovém případě by si nevylámal zuby i unittest. Nevím.
-
elm-package odhalí
Cože? elm-package odhalí, že jste se překlepl v operátoru? Řekl bych, že nastal čas pro to, abyste také vy ukázal svůj kód.
Je to dost zbytečné cvičení, a tak trošku to přesměrovává problém od "spletl jsem se v pojmenování" na "spletl jsem se v typu". Ale svým způsobem to je třeba odpověď na autorovu otázku - ano, typový systém odhalí chyby v kódu, ale jak odhalí chyby v typech?
Ono by to vůbec bylo schování všech možných algoritmů do typů. Typy jsou ale součástí kódu, takže tím si nijak nepomůžeme.
-
Jenže pak je otázka, zda v takovém případě by si nevylámal zuby i unittest. Nevím.
Jednotkový test testuje jenom to, co do testu napíše programátor. A spousta jednotkových testů se píše jednoduše tak, že kontrolují, zda pro zadané vstupní hodnoty dává jednotka očekávaný výstup. Není to nic světoborného, ale praxe ukazuje, že i hloupé třídění není snadné napsat na první pokus správně, takže i testy, které z miliard možných vstupů otestují těch pět správných dokážou odhalit většinu chyb, které v praxi nastávají.
-
Chjo, tak jinak.
Předpokládejme, že Pepa píše program a nechce v něm mít chyby. A chce využít všechny možnosti, ale co nejjednodušším způsobem. A co nejrychlej. Takže:
- Je lepší při chybě program nepřeložit a dostat rovnou hlášku "type mismatch @ line 256", než týden procházet logy
- Je lepší, pokud má funkci
speed_t avgSpeed( distance_t distance, time_t time) { ... }
a vyběhne na něj při překladu rovnou varování, že prohodil argumenty, než když na to přijde tesťák náhodou
- A chce mít podchyceno, že se opravdu implementuje správný vzorec, takže dá i unit test, který ho upoyorní, že ten výpočet je blbě.
- A protože chce vědět, jestli větší celek programu běhá správně, hodít am i integrační testy.
Takže s čím se to dělá efektivně ohlídá datový typ (bez práce a před commitem), co se dělá ohlídá unit test.
Pokud se i "s čím to dělám" musí (v základu) hlídat unit testem, tak je něco blbě (= jazyk stojí za starou bačkoru)
Jestli to má být v C a jestli to jsou všechno ve skutečnosti jen doubly, tak na něj nevyběhne nic, protože všechny tři typy jsou kompatibilní. Pokud by kompilátor hlásil varování v každé takové situaci, tak by v programech rozsahem i jen málo nad rámec učebnicových příkladů vyhazoval tolik varování, že by se v nich ta relevantní ztratila, protože většina by byla planými poplachy. Další možností by bylo všude přetypovávat, což by zase vedlo k nepřehlednosti programu.
-
A zatímco úzká skupinka akademiků si posilovala své ego a pocit nadřazenosti teoretizováním o abstraktních problémech, někdo reálný napsal reálný program, který pomohl vyřešit konkrétní problém.
Nic proti akademikům, ale pokud chybí alespoň elementární porce pokory, zbude jen prázdnota a nadutost.
/* Možná je hodnocení moc příkré, ale po přečtení vlákna si nemohu pomoct. */
-
Jestli to má být v C a jestli to jsou všechno ve skutečnosti jen doubly, tak na něj nevyběhne nic, protože všechny tři typy jsou kompatibilní. Pokud by kompilátor hlásil varování v každé takové situaci, tak by v programech rozsahem i jen málo nad rámec učebnicových příkladů vyhazoval tolik varování, že by se v nich ta relevantní ztratila, protože většina by byla planými poplachy. Další možností by bylo všude přetypovávat, což by zase vedlo k nepřehlednosti programu.
C nepatří mezi silně typové jazyky a pokud si na to člověk zvykne, má pocit, že to přece nemůže být jinak. Ale velké množství chyb a zkušenosti z takovýchto jazyků ukazují, že při správném návrhu to s tím přetypováváním není tak žhavé a vývoj to naopak značně zrychlí.
-
A zatímco úzká skupinka akademiků si posilovala své ego a pocit nadřazenosti teoretizováním o abstraktních problémech, někdo reálný napsal reálný program, který pomohl vyřešit konkrétní problém.
Nic proti akademikům, ale pokud chybí alespoň elementární porce pokory, zbude jen prázdnota a nadutost.
/* Možná je hodnocení moc příkré, ale po přečtení vlákna si nemohu pomoct. */
Tak já mám k papírovým akademikům dost daleko. Ale to, že jsem přičichl k statickým typům, dokonce i nedobrovolně nakouklu do teorie typů (grupy axiomy a tyhlencty vymyšlenosti) mi dost otevřelo oči. A začal jsem se i u pitomejch jazyků jako je php, java, javascript, nebo python uvažovat jinak. Snad ku prospěchu věci.
Třeba u mě se opakuje scénář: píšu v Javě, načichnu tím stylem. Po nějaké době mě to začne rozčilovat. Pak zkouším nějaký projekt a tak si řeknu, že to tentokrát zkusím v Pythonu. Nejdřív nadšení, jak jde všechno snadno a krásně, a pak když navzdory incrementálnímu vývoji už třetí den nedělám nic jiného než že spouštím aplikaci a opravuju chyby mě to začne štvát z druhé strany. Tak se vrátím zpět k Javě. Tam mě začne štvát, že žádné typy neumí, tak zkusím Scalu, Haskell...
U Haskellu to byla zatím největší spokojenost. Poněkud náročné na hlavu, ale jinak se dá. Nejvíc mě zatím vadilo, když mi totálně vyhnil cabal. Tak ale za to jazyk nemůže.
-
elm-package odhalí
Cože? elm-package odhalí, že jste se překlepl v operátoru?
Ne. Překlep pozná už kompilátor. Že se změnila signatura oproti minule (tedy, to co dělají testy) odhalí elm-package.
-
A zatímco úzká skupinka akademiků si posilovala své ego a pocit nadřazenosti teoretizováním o abstraktních problémech, někdo reálný napsal reálný program
Ti akademici jsou taky reální ;) A museli tomu tvůrci "reálného programu" vymyslet a implementovat překladač nebo interpretr, aby to svoje veledílo mohl napsat a pustit ;)
-
Tak já mám k papírovým akademikům dost daleko. Ale to, že jsem přičichl k statickým typům, dokonce i nedobrovolně nakouklu do teorie typů (grupy axiomy a tyhlencty vymyšlenosti) mi dost otevřelo oči. A začal jsem se i u pitomejch jazyků jako je php, java, javascript, nebo python uvažovat jinak.
Gratuluju. To je normální vývoj u člověka, co se chce zdokonalovat a je schopen pochopit mírně abstraktní poznatky. V IT bohužel převažují zakrnělí pologramoti...
-
U Haskellu to byla zatím největší spokojenost. Poněkud náročné na hlavu
Co tam je tak náročného?
-
Ne. Překlep pozná už kompilátor.
Jak? Můžete to konkrétně ukázat na těch funkcích add() a sub().
Že se změnila signatura oproti minule (tedy, to co dělají testy) odhalí elm-package.
Ne, testy dělají něco jiného, svým způsobem přesný opak. Kdybyste si chtěl kód jenom vyzkoušet, nepotřebujete celou infrastrukturu kolem testů – prostě byste si to jednou zkusil, a kdyby to fungovalo, testovací kód byste smazal. Celá ta infrastruktura kolem testů a jejich pravidelné spouštění ale slouží právě k tomu, abyste odhalil chyby při změnách kódu. Takže test nemůže záviset na signatuře implementace, protože celý smysl testu je v tom, že implementace dává pro zadaný vstup očekávaný výstup bez ohledu na to, jaká je zrovna použitá implementace.
-
U Haskellu to byla zatím největší spokojenost. Poněkud náročné na hlavu
Co tam je tak náročného?
Aktuálně se peru s existencionálními typy aka forall. Už mi to nějaký chlápek vysvětloval, ale nedostatečně jsem si to zažil, a zase zapoměl.
-
Takže test nemůže záviset na signatuře implementace, protože celý smysl testu je v tom, že implementace dává pro zadaný vstup očekávaný výstup bez ohledu na to, jaká je zrovna použitá implementace.
Právě jsi popsal, co dělají typy. Je-li typem definováno, že výsledek funkce má být ytý succ x, tak to vždycky pozná, že je implementace správně (budeme-li o odvozování kompilátorem mluvit jako o jeho implementaci).
-
Hrál jsem si typem Date, jen pro ukázku:
Naivní implementace, naprosto nedostatečná (a v reálu nejpoužívanější):
type Data = {year: Int, month: Int, day: Int}
O něco málo lepší:
type Data = {year: Int, month: Int 1 12, day: Int 1 31}
elm-package* zařve, protože se změnila logika
Už použitelná:
type Data = {year: Int, month: 1|3|5|7|8|10|12, day: Int 1 31}
| {year: Int, month: 4|6|9|11, day: Int 1 30}
| {year: Int, month: 2, day: Int 1 28}
elm-package zařve, protože se změnila logika
A mohl bych pokračovat dál a dál, zohlednit rok nula, zohledňovat přestupné roky, ...
Každopádně ta elegance se s ukecanýmy a nedostatečnými testy nedá srovnat.
Nevěřím, že by ty typy skutečně dokázali popsat všechno. Ale těch hranic se nedokážu dopátrat :-)
* elm-package ve skutečnosti samozřejmě nezařve, protože Elm neumí závislostní typy, ale jde o princip, kdy nějaký nástroj typů dokáže vykrást doménu testů.
-
Takže test nemůže záviset na signatuře implementace, protože celý smysl testu je v tom, že implementace dává pro zadaný vstup očekávaný výstup bez ohledu na to, jaká je zrovna použitá implementace.
Právě jsi popsal, co dělají typy. Je-li typem definováno, že výsledek funkce má být ytý succ x, tak to vždycky pozná, že je implementace správně (budeme-li o odvozování kompilátorem mluvit jako o jeho implementaci).
Máte v tom pěkný hokej.
Zkuste si představit, že ta funkce v liché týdny přičítá a v sudé týdny odčítá. Budete definovat typ y-tý_následník_x_v_liché_ týdny_union_y-tý_předchůdce_v_sudé_týdny? Celou bankovní aplikaci pak navrhnete jako funkci main vracející ten správný datový typ™ a kompilátor už to nějak vyřeší?
Ano, mezi typy a algoritmy není úplně pevná hranice, do určité míry mezi nimi lze přecházet, ale ta pružnost není nekonečná. Nezapomínejte na to, že nakonec to stejně někdo musí převést do strojových instrukcí procesoru. A že většinu věcí lidé snáze vyjádří algoritmem, než aby definovali složitou hierarchii typů.
-
Ale těch hranic se nedokážu dopátrat :-)
Tak si zkuste nadefinovat typ pro datum používané v Evropě a Severní Americe v období uplynulých pěti set let. Ne nějakou abstrakci, ale typ, který bude odpovídat tomu, co se v různých dobách a na různých územích skutečně používalo.
-
Právě jsi popsal, co dělají typy. Je-li typem definováno, že výsledek funkce má být ytý succ x, tak to vždycky pozná, že je implementace správně (budeme-li o odvozování kompilátorem mluvit jako o jeho implementaci).
Úžasné. Takže abych se vyhnul unittestům, tak si musím tu funkčnost naimplementovat ještě jednou, akorát bez pokročilé matematiky typu součet dvou čísel. ::)
Implementoval už jsi někdy nějakou netriviální logiku? Fakt bych chtěl vidět podobný typ pro funkci co počítá třeba daň z úroku.
Sice jsem bývalý akademik se závislostí na silném typování, ale co je moc, to je moc.
-
Právě jsi popsal, co dělají typy. Je-li typem definováno, že výsledek funkce má být ytý succ x, tak to vždycky pozná, že je implementace správně (budeme-li o odvozování kompilátorem mluvit jako o jeho implementaci).
Úžasné. Takže abych se vyhnul unittestům, tak si musím tu funkčnost naimplementovat ještě jednou, akorát bez pokročilé matematiky typu součet dvou čísel. ::)
Tak za prvé, pomocí unittestů to taky implementuju ještě jednou.
A za druhé, nikde jsem nepsal, že se to tak má dělat, nebo tak něco. Je to jen úvaha. Praktičnost toho není obsahem mé otázky.
-
Máte v tom pěkný hokej.
Zkuste si představit, že ta funkce v liché týdny přičítá a v sudé týdny odčítá. Budete definovat typ y-tý_následník_x_v_liché_ týdny_union_y-tý_předchůdce_v_sudé_týdny? Celou bankovní aplikaci pak navrhnete jako funkci main vracející ten správný datový typ™ a kompilátor už to nějak vyřeší?
Ano, přesně tak. Žádný problém pane hokejisto.
-
akorát bez pokročilé matematiky typu součet dvou čísel.
To mě připomíná, ono třeba v žádném mě známém typovaném jazyku není typ Int implemenován jako ...|1|2|3|4|5|6|7|8|9|10|... ale je na to nějaká zkratka na buildin typ, a stejně tomu ten kompilátor rozumí. Takže si představuji, že stejně tak se dá udělat i ta pokročilá matematika. Netřeba se utápět v detailech.
-
tak já bych si tipnul, že to jde (computational trinitiarism) a že bych u toho fakt nechtěl být (ale paper bych si přečet)
k tomu s algoritmama - když si představíte, že by ty funkce byly asi čisté, tj. rekurzivní (tj. bez cyklů), tak s o tom hned uvažuje jinak
-
computational trinitiarism
Můžeš prosím rozvést vo co de?
Jinak díky, píšu si do seznamu k nastudování :-)
-
computational trinitiarism
Můžeš prosím rozvést vo co de?
moc ne :D
https://existentialtype.wordpress.com/2011/03/27/the-holy-trinity/
https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence
https://ncatlab.org/nlab/show/computational+trinitarianism
dívám se na to tak, že chování programu se (s dostatečně schopným typovým systémem) zcela odráží v typu programu (který by byl a->b)
disclaimer: tady jsem už dost daleko od věcí o kterých bych si troufnul říct, že jim rozumím
-
computational trinitiarism
Můžeš prosím rozvést vo co de?
moc ne :D
https://existentialtype.wordpress.com/2011/03/27/the-holy-trinity/
https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence
https://ncatlab.org/nlab/show/computational+trinitarianism
Díky moc!
dívám se na to tak, že chování programu se (s dostatečně schopným typovým systémem) zcela odráží v typu programu (který by byl a->b)
Ano, taková je moje idea :-)
-
Jak typy zajistis, ze tvoje metoda sum(a,b) vraci pro int a a int b spravny int soucet? Jako alternativu k primitivnimu assertEquals(3, sum(1,2)) ?
Teorie typů praví, že sum a b je pohled na množinu všech možných kombinací <a, b>. Takže stejně tak, jako víme, že po 1čce přijde dvojka (pomocí těch axiomů), tak víme že (sum 1 2) == 3. Je třeba to nějak definovat, nemusí to být triviální, ale co už.
Pamatuji si učitele, který nám pro zajímavost ukazoval, jak se vypočítá odmocnina. Byl to vzorec na několik řádek (jak moc to byla hloupost netuším, od té doby jsem se k tomu nikdy nevrátil). A v reálu se proto stejně používají tabulky. (Jak to počítají procesory, zda na to mají vzorec, nebo používají taky tabulku, to netuším.)
-
Odmocni jde skoro z hlavy.
Mam cislo (50), vydelim dvema (25), sectu s 2 a udelam prumer(13,5).
Pokracuju 50:13=asi 3, zas sectu 13+3 a udelam prumer(8).
Pokracuju 50:8=asi 6, zas prumer 6+8 a tak dal.
-
Odmocni jde skoro z hlavy.
Mam cislo (50), vydelim dvema (25), sectu s 2 a udelam prumer(13,5).
Pokracuju 50:13=asi 3, zas sectu 13+3 a udelam prumer(8).
Pokracuju 50:8=asi 6, zas prumer 6+8 a tak dal.
Sice to nebylo pointou mého příspěvku - ale hezký :-)
-
Jestli to má být v C a jestli to jsou všechno ve skutečnosti jen doubly, tak na něj nevyběhne nic, protože všechny tři typy jsou kompatibilní. Pokud by kompilátor hlásil varování v každé takové situaci, tak by v programech rozsahem i jen málo nad rámec učebnicových příkladů vyhazoval tolik varování, že by se v nich ta relevantní ztratila, protože většina by byla planými poplachy. Další možností by bylo všude přetypovávat, což by zase vedlo k nepřehlednosti programu.
C nepatří mezi silně typové jazyky a pokud si na to člověk zvykne, má pocit, že to přece nemůže být jinak. Ale velké množství chyb a zkušenosti z takovýchto jazyků ukazují, že při správném návrhu to s tím přetypováváním není tak žhavé a vývoj to naopak značně zrychlí.
To si právě spousta lidí myslí, ale v praxi to tak optimistické zdaleka není. Na akademických příkládcích se dá každá vlastnost předvést jako naprosto elegantní, ale v praxi na reálném projektu to pak vypadá poněkud odlišně. (např. Pascal je typově silnější než C a byl to jeden z důvodů, proč lidi tolik iritoval a pro praktickou práci se sahalo raději po C, přestože na školách snad každý ve své době absolvoval pascalskou průpravu)
Třeba u mě se opakuje scénář: píšu v Javě, načichnu tím stylem. Po nějaké době mě to začne rozčilovat. Pak zkouším nějaký projekt a tak si řeknu, že to tentokrát zkusím v Pythonu. Nejdřív nadšení, jak jde všechno snadno a krásně, a pak když navzdory incrementálnímu vývoji už třetí den nedělám nic jiného než že spouštím aplikaci a opravuju chyby mě to začne štvát z druhé strany. Tak se vrátím zpět k Javě. Tam mě začne štvát, že žádné typy neumí, tak zkusím Scalu, Haskell...
U Haskellu to byla zatím největší spokojenost. Poněkud náročné na hlavu, ale jinak se dá. Nejvíc mě zatím vadilo, když mi totálně vyhnil cabal. Tak ale za to jazyk nemůže.
A o jak rozsáhlé věci asi tak šlo?
Jak typy zajistis, ze tvoje metoda sum(a,b) vraci pro int a a int b spravny int soucet? Jako alternativu k primitivnimu assertEquals(3, sum(1,2)) ?
Teorie typů praví, že sum a b je pohled na množinu všech možných kombinací <a, b>. Takže stejně tak, jako víme, že po 1čce přijde dvojka (pomocí těch axiomů), tak víme že (sum 1 2) == 3. Je třeba to nějak definovat, nemusí to být triviální, ale co už.
To mi teda smysl nedává.
Pamatuji si učitele, který nám pro zajímavost ukazoval, jak se vypočítá odmocnina. Byl to vzorec na několik řádek (jak moc to byla hloupost netuším, od té doby jsem se k tomu nikdy nevrátil). A v reálu se proto stejně používají tabulky. (Jak to počítají procesory, zda na to mají vzorec, nebo používají taky tabulku, to netuším.)
Je docela možné, že algoritmus výpočtu odmocniny by šlo nějak vměstnat do vzorce, ale ten procedurální přístup (1. rozděl číslo na skupinky po dvou, 2. najdi největší číslo, které po umocnění na druhou bude menší nebo rovno než skupinka vlevo, 3...) je poměrně názorný. Ale ta pointa mi stejně uniká.
-
Uz jsem si vpomel na nazev, to rucni odmocnovani je newtonuv vzorec.
Fi = F0 - f(x)/f'(x)
-
Uz jsem si vpomel na nazev, to rucni odmocnovani je newtonuv vzorec.
Fi = F0 - f(x)/f'(x)
Konkrétně tzv. babylonská metoda. Newtonův vzorec je iterativní metoda obecně na řešení transcendentních rovnic.
-
Tak za prvé, pomocí unittestů to taky implementuju ještě jednou.
Tak to ani náhodou. Unittesty obvykle testují jenom významné případy. Automaticky porovnat dvě implementace mezi sebou není vůbec jednoduché.
Ty vybrané případy můžou být významné na základě modelovaného problému, autorova odhadu, nebo prostě proto, že to na tomhle už někdy vybouchlo. Implementovat to ještě jednou je naopak kontraproduktivní. Pokud tu referenční implementaci nedělá někdo nezávislý, tak je velká šance, že tam autor naseká dost podobné chyby.
A za druhé, nikde jsem nepsal, že se to tak má dělat, nebo tak něco. Je to jen úvaha. Praktičnost toho není obsahem mé otázky.
V našem oboru neexistuje nic, co by se nedalo hrnout přímo v hexa. Všechno od assembleru výš je o té praktičnosti. ;)
Jde mi o to, že typy a unittesty chytají s přiměřenou námahou různé druhy chyb. Třeba přehozené pořadí násobení matic nejde přes typy skoro odhalit. Leda že by sémantika výsledku byla celá zakódovaná v typech. Ale to pak přesune problém jenom o úroveň výš, protože je třeba nějak ověřit ty komplikované typy.
-
tohle vlákno mě přimělo juknout se znovu na kousek kódu se kterým jsem si nedávno hrál, a světe div se, našel jsem tam chybu v type family, která měla zajišťovat korektnost (jeden z aspektů) programu vygenerovaného překladačem (takovým překladačem na hraní), takže taky hlasuju za nezavrhování testů :)
najdi jeden rozdíl (a uvaž, který případ je vlastně "správně"):
type family Drop (a :: [*]) (b :: [*]) :: [*] where
Drop '[] b = b
Drop (a ': a') (b ': b') = Drop a' b'
type family Drop (a :: [*]) (b :: [*]) :: [*] where
Drop '[] b = b
Drop (a ': a') (a ': b') = Drop a' b'
-
Kéž by toto vlákno skončilo konstatováním, že typový systém nemůže nahradit unit testy...
+1 ;D
-
Tak za prvé, pomocí unittestů to taky implementuju ještě jednou.
Tak to ani náhodou. Unittesty obvykle testují jenom významné případy. Automaticky porovnat dvě implementace mezi sebou není vůbec jednoduché.
Ty vybrané případy můžou být významné na základě modelovaného problému, autorova odhadu, nebo prostě proto, že to na tomhle už někdy vybouchlo. Implementovat to ještě jednou je naopak kontraproduktivní. Pokud tu referenční implementaci nedělá někdo nezávislý, tak je velká šance, že tam autor naseká dost podobné chyby.
A za druhé, nikde jsem nepsal, že se to tak má dělat, nebo tak něco. Je to jen úvaha. Praktičnost toho není obsahem mé otázky.
V našem oboru neexistuje nic, co by se nedalo hrnout přímo v hexa. Všechno od assembleru výš je o té praktičnosti. ;)
Jde mi o to, že typy a unittesty chytají s přiměřenou námahou různé druhy chyb. Třeba přehozené pořadí násobení matic nejde přes typy skoro odhalit. Leda že by sémantika výsledku byla celá zakódovaná v typech. Ale to pak přesune problém jenom o úroveň výš, protože je třeba nějak ověřit ty komplikované typy.
Nejsme ve sporu.
-
tohle vlákno mě přimělo juknout se znovu na kousek kódu se kterým jsem si nedávno hrál, a světe div se, našel jsem tam chybu v type family, která měla zajišťovat korektnost (jeden z aspektů) programu vygenerovaného překladačem (takovým překladačem na hraní), takže taky hlasuju za nezavrhování testů :)
najdi jeden rozdíl (a uvaž, který případ je vlastně "správně"):
type family Drop (a :: [*]) (b :: [*]) :: [*] where
Drop '[] b = b
Drop (a ': a') (b ': b') = Drop a' b'
type family Drop (a :: [*]) (b :: [*]) :: [*] where
Drop '[] b = b
Drop (a ': a') (a ': b') = Drop a' b'
Mám vyhrabat nějaký unittesty? :)
To je jako ten oblíbenej hejt na Lisp, že je to plné závorek. To ano, protože každá závorka v Lispu reprezentuje jednu třídu v Javě.
-
Nejsme ve sporu.
Jste. Vy jste napsal nesmysl, že v jednotkových testech něco implementujete znovu, JSH vám to správně vyvracel, že implementovat něco v jednotkovém testu znova je obvykle velmi špatně.
Mám vyhrabat nějaký unittesty? :)
Ano, myslím, že už je na čase.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Šlo by to tvrzení trochu rozvést? Generika, nebo i implicitní typy bych bral, ale silné typování samo o sobě tyhle věci neimplikuje.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Šlo by to tvrzení trochu rozvést? Generika, nebo i implicitní typy bych bral, ale silné typování samo o sobě tyhle věci neimplikuje.
“Silné” ve smyslu aspoň s HKT, prostě něco víc než Java. Generika jsou prvním stupněm. HKT umožní ještě více sdílení a závislostní typy ještě o stupeň více.
-
Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
Jak jste k tomu dospěl?
Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?
class Sčítačka {
Int součet(Int a, Int b) {
<cokoliv>
}
}
Int je třídou pro celá čísla (třeba vlastní implementace). Výsledek je nutně typu (správně instancí) Int, to je ale jediná věc, kterou vám typový systém garantuje. To ale nestačí - jak tento typ (třída) garantuje, že 1+1 rovná se opravdu 2???
Diskusi jsem nečetl - má to po výše uvedeném ještě smysl číst?
-
Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?
class Sčítačka {
Int součet(Int a, Int b) {
<cokoliv>
}
}
Int je třídou pro celá čísla (třeba vlastní implementace). Výsledek je nutně typu (správně instancí) Int, to je ale jediná věc, kterou vám typový systém garantuje. To ale nestačí - jak tento typ (třída) garantuje, že 1+1 rovná se opravdu 2???
Diskusi jsem nečetl - má to po výše uvedeném ještě smysl číst?
třeba peanova čísla na typové úrovni, v haskellu docela banální
type family Append a b where ...
součet :: I a -> I b -> I (Append a b)
součet = ...
-
třeba peanova čísla na typové úrovni, v haskellu docela banální
type family Append a b where ...
součet :: I a -> I b -> I (Append a b)
součet = ...
Jak by to mělo pomoct?
Součet dvou čísel je jenom příklad nějakého (netriviálního) výpočtu. Pokud ho popíšu v typu, tak jenom přesunu potenciálně vadný kód někam jinam. Pořád nevím, jestli je dobře. Akorát jsem se přesunul z deště pod okap, protože ten typ se čte hůř než původní kód.
-
Diskusi jsem nečetl - má to po výše uvedeném ještě smysl číst?
Záleží na tom. Ten váš příklad je v diskusi uveden několikrát, ale nepomohlo to…
-
třeba peanova čísla na typové úrovni, v haskellu docela banální
type family Append a b where ...
součet :: I a -> I b -> I (Append a b)
součet = ...
Jak by to mělo pomoct?
Součet dvou čísel je jenom příklad nějakého (netriviálního) výpočtu. Pokud ho popíšu v typu, tak jenom přesunu potenciálně vadný kód někam jinam. Pořád nevím, jestli je dobře. Akorát jsem se přesunul z deště pod okap, protože ten typ se čte hůř než původní kód.
ptal jste se na typ, který garantuje, že kód provádí součet a ten jsem naznačil
nic se nepřesouvá, pořád máte zvlášť program a jeho typ, že se v tom dá udělat chyba? no jistě, to jde všude
-
že se v tom dá udělat chyba? no jistě, to jde všude
Jenže celá diskuse začala tvrzením, že s propracovaným typovým systémem nejsou potřeba jednotkové testy – kde je skrytý předpoklad, že se při použití propracovaného typového systému chyba udělat nedá.
Nebo-li v této diskusi se vyskytují dvě skupiny diskutujících – jedním připadá samozřejmé, že je možné chybu udělat všude, zatímco druzí tomu, že je možné udělat chybu všude, nevěří.
-
ptal jste se na typ, který garantuje, že kód provádí součet a ten jsem naznačil
nic se nepřesouvá, pořád máte zvlášť program a jeho typ, že se v tom dá udělat chyba? no jistě, to jde všude
Já se ptal v kontextu tohohle vlákna. Diskutujeme o tom, jestli se unittesty dají nahradit typovým systémem. Zeptám se jinak :
Píšu funkci, která skládá transformace. To je dost netriviální. A je tam pár věcí, které se dají jednoduše zvrtat. Třeba přehodit pořadí násobení matic. Jak dokážu typovým systémem ověřit, jestli to mám dobře? V unittestech otestuju pár jednoduchých případů a mám celkem jistotu.
-
že se v tom dá udělat chyba? no jistě, to jde všude
Jenže celá diskuse začala tvrzením, že s propracovaným typovým systémem nejsou potřeba jednotkové testy – kde je skrytý předpoklad, že se při použití propracovaného typového systému chyba udělat nedá.
myslím, že žádný takový předpoklad tam není
má to být náhrada, dá se předpokládat, že i s některými vlastnostmi původního řešení
-
nejdřív bych zdůraznil svůj postoj: neargumentuju proti testům, testy jsou dobrá věc
původní dotaz se zabývá tím (moje interpretace), jestli se testy dají teoreticky nahradit typovým systémem a já si vzhledem k tomu co jsem o tématu četl, myslím, že ano, dále mě zajímají praktické limity tohoto přístupu, protože z vlastní praxe ho považuju za extrémně užitečný
ptal jste se na typ, který garantuje, že kód provádí součet a ten jsem naznačil
nic se nepřesouvá, pořád máte zvlášť program a jeho typ, že se v tom dá udělat chyba? no jistě, to jde všude
Já se ptal v kontextu tohohle vlákna. Diskutujeme o tom, jestli se unittesty dají nahradit typovým systémem.
asi nechápu
Píšu funkci, která skládá transformace. To je dost netriviální. A je tam pár věcí, které se dají jednoduše zvrtat. Třeba přehodit pořadí násobení matic. Jak dokážu typovým systémem ověřit, jestli to mám dobře? V unittestech otestuju pár jednoduchých případů a mám celkem jistotu.
napadají mě dvě možnosti, něco jako units of measure z F sharpu a pak prosté přejmenování typů, např místo (syntaxe haskellu) Float -> Float -> Float
napsat Distance -> Time -> Speed (kde newtype Distance = Distance Float etc)
-
nejdřív bych zdůraznil svůj postoj: neargumentuju proti testům, testy jsou dobrá věc
Tak o čem tu diskutujeme? Vlákno začalo tvrzením
Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
A všechny tyhle příklady, které sem házíme, jsou věci, které se dají ozkoušet triviálním unittestem, ale v typech je to přinejlepším strašně komplikované.
asi nechápu
Argumentujeme tu proti BoneFluteově extrémním postoji. Proti rozumnému využívání typů naše argumenty samozřejmě nedávají nejmenší smysl.
-
jeho extrémní postoj je zajímavý, rozumné použití typů je nuda (a co je dneska akademický blábol, může být zítra industry best practice)
-
myslím, že žádný takový předpoklad tam není
má to být náhrada, dá se předpokládat, že i s některými vlastnostmi původního řešení
Jednotkové testy se používají pro odhalení určitého typu chyb. Náhrada by musela alespoň odhalit stejný typ chyb, jinak to není náhrada.
původní dotaz se zabývá tím (moje interpretace), jestli se testy dají teoreticky nahradit typovým systémem a já si vzhledem k tomu co jsem o tématu četl, myslím, že ano, dále mě zajímají praktické limity tohoto přístupu, protože z vlastní praxe ho považuju za extrémně užitečný
A mohl byste tedy uvést konkrétní příklad? Zatím tady máme opakovaně příklad, kdy programátor omylem místo sčítání použije odčítání. Triviální jednotkový test takovou chybu odhalí. A zatím tady nebyl uveden žádný příklad typového systému, který by takové chybě zabránil. Viděli jsme jen příklady, že je možné operátor sčítání nahradit typem „výsledek součtu“, což ale neřeší ten problém, protože stejně, jako může programátor použít špatný operátor, může použít špatný typ.
Aby bylo jasno, já souhlasím s tím, že silnější typový systém znamená, že není potřeba psát některé jednotkové testy. Ale v žádném případě to neznamená, že dostatečně silný typový systém by znamenal, že nebudou potřeba žádné jednotkové testy (jak tvrdil BoneFlute), protože by vše, co se kontroluje jednotkovými testy, kontroloval typový systém.
-
myslím, že žádný takový předpoklad tam není
má to být náhrada, dá se předpokládat, že i s některými vlastnostmi původního řešení
Jednotkové testy se používají pro odhalení určitého typu chyb. Náhrada by musela alespoň odhalit stejný typ chyb, jinak to není náhrada.
přesně tak
původní dotaz se zabývá tím (moje interpretace), jestli se testy dají teoreticky nahradit typovým systémem a já si vzhledem k tomu co jsem o tématu četl, myslím, že ano, dále mě zajímají praktické limity tohoto přístupu, protože z vlastní praxe ho považuju za extrémně užitečný
A mohl byste tedy uvést konkrétní příklad?
uvedl
Zatím tady máme opakovaně příklad, kdy programátor omylem místo sčítání použije odčítání. Triviální jednotkový test takovou chybu odhalí. A zatím tady nebyl uveden žádný příklad typového systému, který by takové chybě zabránil.
byl
Viděli jsme jen příklady, že je možné operátor sčítání nahradit typem „výsledek součtu“
myslím, že ne
Ale v žádném případě to neznamená, že dostatečně silný typový systém by znamenal, že nebudou potřeba žádné jednotkové testy (jak tvrdil BoneFlute), protože by vše, co se kontroluje jednotkovými testy, kontroloval typový systém.
no a já si myslím, že to teoreticky možné je (výše jsem k tomu dal nějaké odkazy), což neznamená, že to někdy bude i praktické
-
V tom případě by to asi chtělo ten příklad rozvést a ukázat, jak je zabráněné tomu, abych místo typu „n-tý následník„ použil typ „n-tý předchůdce“, nebo „n-tý následník“ s -n místo n.
Konkrétně už tu byl uveden tento slabě typový pseudokód:
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
Jak by vypadal tentýž kód, který by pomocí silnějších typů zabránil tomu, aby někdo místo sčítání použil odčítání?
Podle mne je tedy nesmyslné vůbec se pokoušet nějaké takové typy vytvořit, protože to, jestli se má použít sčítání nebo odčítání, je vlastností řešené domény – tudíž musí programátor pochopit řešený problém, uvědomit si, zda použije sčítání nebo odčítání (případně něco úplně jiného), a pak použije vhodné prostředky programovacího jazyka. Tohle za programátora nevyřeší žádný typový systém, protože kompilátor neví nic o tom, zda se má např. částka přičíst nebo odečíst, když firma zaplatí fakturu.
-
V tom případě by to asi chtělo ten příklad rozvést a ukázat, jak je zabráněné tomu, abych místo typu „n-tý následník„ použil typ „n-tý předchůdce“, nebo „n-tý následník“ s -n místo n.
Konkrétně už tu byl uveden tento slabě typový pseudokód:
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
Jak by vypadal tentýž kód, který by pomocí silnějších typů zabránil tomu, aby někdo místo sčítání použil odčítání?
Podle mne je tedy nesmyslné vůbec se pokoušet nějaké takové typy vytvořit, protože to, jestli se má použít sčítání nebo odčítání, je vlastností řešené domény – tudíž musí programátor pochopit řešený problém, uvědomit si, zda použije sčítání nebo odčítání (případně něco úplně jiného), a pak použije vhodné prostředky programovacího jazyka. Tohle za programátora nevyřeší žádný typový systém, protože kompilátor neví nic o tom, zda se má např. částka přičíst nebo odečíst, když firma zaplatí fakturu.
tady je to hezky rozepsané https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell
-
V tom případě by to asi chtělo ten příklad rozvést a ukázat, jak je zabráněné tomu, abych místo typu „n-tý následník„ použil typ „n-tý předchůdce“, nebo „n-tý následník“ s -n místo n.
Konkrétně už tu byl uveden tento slabě typový pseudokód:
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
Jak by vypadal tentýž kód, který by pomocí silnějších typů zabránil tomu, aby někdo místo sčítání použil odčítání?
Podle mne je tedy nesmyslné vůbec se pokoušet nějaké takové typy vytvořit, protože to, jestli se má použít sčítání nebo odčítání, je vlastností řešené domény – tudíž musí programátor pochopit řešený problém, uvědomit si, zda použije sčítání nebo odčítání (případně něco úplně jiného), a pak použije vhodné prostředky programovacího jazyka. Tohle za programátora nevyřeší žádný typový systém, protože kompilátor neví nic o tom, zda se má např. částka přičíst nebo odečíst, když firma zaplatí fakturu.
tady je to hezky rozepsané https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell
Vždyť ten odkazovaný článek je o něčem úplně jiném. "Avoiding boundary errors" a to, jestli kód odpovídá modelovanému problému jsou někde úplně jinde.
-
tady je to hezky rozepsané https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell
Když tu délku článku srovnám s délkou jednotkového testu, tak test jednoznačně vítězí.
-
tady je to hezky rozepsané https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell
Vždyť ten odkazovaný článek je o něčem úplně jiném. "Avoiding boundary errors" a to, jestli kód odpovídá modelovanému problému jsou někde úplně jinde.
používá to peanovu aritmetiku na typové úrovni pro vynucení vlastností operací s vektorama (ve smyslu datové struktury), např. tahle funkce je vlastně to stejné jako sčítání:
append :: Vector a n -> Vector a m -> Vector a (n :+ m)
délka výsledného vektoru je součet délek vstupních vektorů (a typový systém to opravdu na implementaci vynutí)
-
Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?
class Sčítačka {
Int součet(Int a, Int b) {
<cokoliv>
}
}
Int je třídou pro celá čísla (třeba vlastní implementace). Výsledek je nutně typu (správně instancí) Int, to je ale jediná věc, kterou vám typový systém garantuje. To ale nestačí - jak tento typ (třída) garantuje, že 1+1 rovná se opravdu 2???
Diskusi jsem nečetl - má to po výše uvedeném ještě smysl číst?
třeba peanova čísla na typové úrovni, v haskellu docela banální
type family Append a b where ...
součet :: I a -> I b -> I (Append a b)
součet = ...
Tak jinak: Doplňuju svůj původní příspěvek:
místo <cokoliv> je "return 10"
Typově je vše správně, ale nějak nám to pro většinu vstupů nevychází, přičemž by to mělo vyjít alespoň pro ty, které budu používat.
Přeloženo: Typová kontrola by zafungovala pouze v případě, že pro každé dva sčítance a součet budete mít extra typy, což je ale v rozporu s jednoduchými, obecnými kategoriemi (zde celá čísla) a prakticky to neřeší problém.
-
používá to peanovu aritmetiku na typové úrovni pro vynucení vlastností operací s vektorama (ve smyslu datové struktury), např. tahle funkce je vlastně to stejné jako sčítání:
append :: Vector a n -> Vector a m -> Vector a (n :+ m)
délka výsledného vektoru je součet délek vstupních vektorů (a typový systém to opravdu na implementaci vynutí)
1) Ten typ ale vůbec nezaručuje, že ten append dělá to, co chceme. Ten typ je kompatibilní se spoustou věcí od appendu v libovolném pořadí až po nějaké pseudonáhodné promíchání.
2) V reálných programech se obvykle počet prvků dovídám až v runtimu.
3) A jak to vůbec souvisí s tím, jestli kód odpovídá řešenému problému?
-
...V unittestech otestuju pár jednoduchých případů a mám celkem jistotu.
Jistotu nemáte, ale i jednoduchým(!) testem můžete zachytit ty největší průsery či totální nefunkčnosti (pravděpodobnost, že chybějící implementace či metoda vám vrátí správný výsledek, je nula hovno), v případě pouhých několika specifických testů dokážete dosáhnout řádově větší protestovanosti než POUHOU typovou kontrolou (kterou můžete úplně klidně též do testu u netypového jazyku doplnit!).
Mimochodem v TDD je pravidlem, že se píší vybrakované metody, které se teprve na stížnost hotových testů vyplňují, případně (a teď pozor, soudruzi javaři nečtěte dále, aby vám z toho nehráblo) se tyto metody teprve vytvářejí! :O :O :O (No nekecej!)
Tohle není odpověď pro JSH, ale autora dotazu Boneflute.
-
Tak jinak: Doplňuju svůj původní příspěvek:
místo <cokoliv> je "return 10"
Typově je vše správně, ale nějak nám to pro většinu vstupů nevychází, přičemž by to mělo vyjít alespoň pro ty, které budu používat.
Přeloženo: Typová kontrola by zafungovala pouze v případě, že pro každé dva sčítance a součet budete mít extra typy, což je ale v rozporu s jednoduchými, obecnými kategoriemi (zde celá čísla) a prakticky to neřeší problém.
s použitím techniky o které jsem mluvil by se takový kód nepřeložil, že má třeba 1 a 2 jiný datový typ není nic až tak zvláštního
-
používá to peanovu aritmetiku na typové úrovni pro vynucení vlastností operací s vektorama (ve smyslu datové struktury), např. tahle funkce je vlastně to stejné jako sčítání:
append :: Vector a n -> Vector a m -> Vector a (n :+ m)
délka výsledného vektoru je součet délek vstupních vektorů (a typový systém to opravdu na implementaci vynutí)
Stále se míjíte s podstatou problému. V mém příkladu bylo záměrně sčítání a odčítání. Abyste si uvědomil, že v běžném programu budu potřebovat obojí, a žádný typový systém neohlídá to, že nepoužiju odčítání tam, kde z logiky věci má být sčítání.
-
používá to peanovu aritmetiku na typové úrovni pro vynucení vlastností operací s vektorama (ve smyslu datové struktury), např. tahle funkce je vlastně to stejné jako sčítání:
append :: Vector a n -> Vector a m -> Vector a (n :+ m)
délka výsledného vektoru je součet délek vstupních vektorů (a typový systém to opravdu na implementaci vynutí)
1) Ten typ ale vůbec nezaručuje, že ten append dělá to, co chceme. Ten typ je kompatibilní se spoustou věcí od appendu v libovolném pořadí až po nějaké pseudonáhodné promíchání.
2) V reálných programech se obvykle počet prvků dovídám až v runtimu.
3) A jak to vůbec souvisí s tím, jestli kód odpovídá řešenému problému?
1) to je pravda a nevím jak to řešit, pro sčítání to ovšem nehraje roli
2) to se dá řešit
3) typ specifikuje co je řešený problém, funkce tomu musí odpovídat
-
používá to peanovu aritmetiku na typové úrovni pro vynucení vlastností operací s vektorama (ve smyslu datové struktury), např. tahle funkce je vlastně to stejné jako sčítání:
append :: Vector a n -> Vector a m -> Vector a (n :+ m)
délka výsledného vektoru je součet délek vstupních vektorů (a typový systém to opravdu na implementaci vynutí)
Stále se míjíte s podstatou problému. V mém příkladu bylo záměrně sčítání a odčítání. Abyste si uvědomil, že v běžném programu budu potřebovat obojí, a žádný typový systém neohlídá to, že nepoužiju odčítání tam, kde z logiky věci má být sčítání.
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
-
s použitím techniky o které jsem mluvil by se takový kód nepřeložil, že má třeba 1 a 2 jiný datový typ není nic až tak zvláštního
Jak zabráníte tomu, aby programátor nepoužil špatný typ? Místo typu pro „sčítání“ použije typ pro „odčítání“.
-
s použitím techniky o které jsem mluvil by se takový kód nepřeložil, že má třeba 1 a 2 jiný datový typ není nic až tak zvláštního
A k čemu to je, když většina numerických hodnot, se kterýma se pracuje, je k dispozici až v runtime? Na zkontrolování čísel, která znám při kompilaci, obvykle stačí blbý static_assert či něco podobného.
-
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
To je ale nepochopení testů. Testy nemají opakovat implementaci, testy mají kontrolovat, zda pro zadaný vstup dostanu očekávaný výstup.
Nikdo netvrdil, že testy jsou dokonalé a že nemůže být chyba i v testu. Pouze vyvracíme tvrzení, že jednotkové testy lze plně nahradit silným typovým systémem. Vyvráceno to bylo triviálním příkladem, kdy programátor použije odčítání místo sčítání, a tomu žádný typový systém z logiky věci nemůže zabránit.
-
Sorry, tvé příspěvky nejsou vůbec inspirativní. Nebudu se tedy tebou již zabejvat.
Jirsák a nobody ;D ;D
-
s použitím techniky o které jsem mluvil by se takový kód nepřeložil, že má třeba 1 a 2 jiný datový typ není nic až tak zvláštního
A k čemu to je, když většina numerických hodnot, se kterýma se pracuje, je k dispozici až v runtime? Na zkontrolování čísel, která znám při kompilaci, obvykle stačí blbý static_assert či něco podobného.
nekontrolují se konkrétní čísla (typicky), ale funkce, které s nimi pracují, např. ten příklad se sčítáním tvrdí, že předpoklad z typu je splněn pro všechna čísla (Nat)
-
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
To je ale nepochopení testů. Testy nemají opakovat implementaci, testy mají kontrolovat, zda pro zadaný vstup dostanu očekávaný výstup.
Nikdo netvrdil, že testy jsou dokonalé a že nemůže být chyba i v testu. Pouze vyvracíme tvrzení, že jednotkové testy lze plně nahradit silným typovým systémem. Vyvráceno to bylo triviálním příkladem, kdy programátor použije odčítání místo sčítání, a tomu žádný typový systém z logiky věci nemůže zabránit.
já jsem ale o opakování implementace nic nepsal, pokud špatně pochopíte problém, můžete napsat test, který od funkce chce pro zadané vstupy jiné výstupy, než ty správné (z hlediska řešeného problému)
a prosím přestaňte si domýšlet obsah příspěvků, pokud máte pochybnosti tak se prostě zeptejte
-
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
To už ale nemá co dělat s problematikou testování, ale chápání řešené úlohy, zde nevznikne rozdíl při použití typového systému, nebo testů.
-
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
To už ale nemá co dělat s problematikou testování, ale chápání řešené úlohy, zde nevznikne rozdíl při použití typového systému, nebo testů.
souhlasím
-
...V unittestech otestuju pár jednoduchých případů a mám celkem jistotu.
Jistotu nemáte, ale i jednoduchým(!) testem můžete zachytit ty největší průsery či totální nefunkčnosti (pravděpodobnost, že chybějící implementace či metoda vám vrátí správný výsledek, je nula hovno), v případě pouhých několika specifických testů dokážete dosáhnout řádově větší protestovanosti než POUHOU typovou kontrolou (kterou můžete úplně klidně též do testu u netypového jazyku doplnit!).
Ty testy se nepíší náhodně, ale testují se hlavně okrajové podmínky, kdy testovaná jednotka může selhat nebo musí selhat.
Mimochodem v TDD je pravidlem, že se píší vybrakované metody, které se teprve na stížnost hotových testů vyplňují, případně (a teď pozor, soudruzi javaři nečtěte dále, aby vám z toho nehráblo) se tyto metody teprve vytvářejí! :O :O :O (No nekecej!)
Má to svůj důvod. Pokud vytvořím test, který neselže, je to problém, který se musí vyřešit dříve, než napíši první znak testované jednotky. Může to být způsobeno například kolizí názvů, takže ten test testuje jinou jednotku téhož jména, která náhodou také projde.
Pak teprve napíši ty prázdné metody, které musí splnit definované rozhraní. Až testy projdou, teprve je čas na rozšíření testů o požadované funkcionality a následně i rozšíření metod.
-
Stále se míjíte s podstatou problému. V mém příkladu bylo záměrně sčítání a odčítání. Abyste si uvědomil, že v běžném programu budu potřebovat obojí, a žádný typový systém neohlídá to, že nepoužiju odčítání tam, kde z logiky věci má být sčítání.
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
Jistě, ale vcelku brzy zjistí, že ten test je chybný. Testy na testy se však nepíší, od toho tu jsou testované jednotky.
-
já jsem ale o opakování implementace nic nepsal, pokud špatně pochopíte problém, můžete napsat test, který od funkce chce pro zadané vstupy jiné výstupy, než ty správné (z hlediska řešeného problému)
To je možné, ale je to spíše výjimečné. Daleko častější je případ, kdy ví správně, jaký výstup má být pro daný vstup, ale špatně to implementuje. Jednotkové testy řeší tenhle případ, a to silným typovým systémem nejde nahradit.
-
nejdřív bych zdůraznil svůj postoj: neargumentuju proti testům, testy jsou dobrá věc
původní dotaz se zabývá tím (moje interpretace), jestli se testy dají teoreticky nahradit typovým systémem a já si vzhledem k tomu co jsem o tématu četl, myslím, že ano, dále mě zajímají praktické limity tohoto přístupu, protože z vlastní praxe ho považuju za extrémně užitečný
Chápeš to zcela přesně jak jsem to myslel.
-
Mimochodem v TDD je pravidlem, že se píší vybrakované metody, které se teprve na stížnost hotových testů vyplňují, případně (a teď pozor, soudruzi javaři nečtěte dále, aby vám z toho nehráblo) se tyto metody teprve vytvářejí! :O :O :O (No nekecej!)
Tohle není odpověď pro JSH, ale autora dotazu Boneflute.
Obnošená vesta.
Proč @v dokázal pochopit, že se táži na limity toho typového systému vůči unittestům, zatímco jiní se mě pokouší přesvědčit že jsem idiot a ani nejsou schopni uvést zajímavé argumenty?
-
tak když někdo špatně pochopí problém, tak mu taky nic nezabrání napsat chybný test
To už ale nemá co dělat s problematikou testování, ale chápání řešené úlohy, zde nevznikne rozdíl při použití typového systému, nebo testů.
Samozřejmě.
-
já jsem ale o opakování implementace nic nepsal, pokud špatně pochopíte problém, můžete napsat test, který od funkce chce pro zadané vstupy jiné výstupy, než ty správné (z hlediska řešeného problému)
To je možné, ale je to spíše výjimečné. Daleko častější je případ, kdy ví správně, jaký výstup má být pro daný vstup, ale špatně to implementuje. Jednotkové testy řeší tenhle případ, a to silným typovým systémem nejde nahradit.
co si vlastně představujete pod pojmem "silný typový systém"? já přinejmenším ten implementovaný v GHC
-
Proč @v dokázal pochopit, že se táži na limity toho typového systému vůči unittestům, zatímco jiní se mě pokouší přesvědčit že jsem idiot a ani nejsou schopni uvést zajímavé argumenty?
Vy jste se na nic netázal, vy jste konstatoval, že jednotkové testy nejsou při použití kvalitního typového systému potřeba (protože typový systém zajistí to, co jinak zajišťují jednotkové testy). Což není pravda, jak už zde bylo opakovaně dokázáno. Akorát to někteří nechápou a neustále navrhují různé typové systémy, které ovšem neodhalí chybu, která zde byla několikrát uvedena jako příklad, a kterou jednotkový test odhalí.
Pokud se příště budete chtít na něco dotázat, doporučuji zeptat se na to a ne tvrdit zjevný nesmysl.
-
co si vlastně představujete pod pojmem "silný typový systém"?
Rozhodně něco s HKT (tím se vyloučí Java apod.), to by byl středně silný, nicméně jak tu už někdo zmiňoval, adjektivum "silný" by mělo implikovat alespoň běžné závislostní typy à la Agda/Coq/Idris.
-
co si vlastně představujete pod pojmem "silný typový systém"? já přinejmenším ten implementovaný v GHC
Pro účely této diskuse si pod tím představuji ten nejsilnější teoreticky možný typový systém. Podstatou této diskuse je totiž to, že velká část problémů, které jsou podchycené jednotkovými testy, není řešitelná žádnými formálními mechanismy – protože formálně jsou přípustní všechny možnosti, ale pro řešení daného problému je přípustná jen jedna možnost.
-
co si vlastně představujete pod pojmem "silný typový systém"?
Rozhodně něco s HKT (tím se vyloučí Java apod.), to by byl středně silný, nicméně jak tu už někdo zmiňoval, adjektivum "silný" by mělo implikovat alespoň běžné závislostní typy à la Agda/Coq/Idris.
co tohle https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell ?
asi neumím říct, kde závislostní typy začínají
a "silný" je asi dost blbé označení
-
co si vlastně představujete pod pojmem "silný typový systém"? já přinejmenším ten implementovaný v GHC
Pro účely této diskuse si pod tím představuji ten nejsilnější teoreticky možný typový systém.
nevím, který to je, postněte odkaz
-
co si vlastně představujete pod pojmem "silný typový systém"?
Rozhodně něco s HKT (tím se vyloučí Java apod.), to by byl středně silný, nicméně jak tu už někdo zmiňoval, adjektivum "silný" by mělo implikovat alespoň běžné závislostní typy à la Agda/Coq/Idris.
Rád bych, když bychom se nedrželi jen toho, co se zatím někomou podařilo implementovat. Zajímá mě klidně i to, co by teoreticky šlo.
-
nejdřív bych zdůraznil svůj postoj: neargumentuju proti testům, testy jsou dobrá věc
původní dotaz se zabývá tím (moje interpretace), jestli se testy dají teoreticky nahradit typovým systémem a já si vzhledem k tomu co jsem o tématu četl, myslím, že ano, dále mě zajímají praktické limity tohoto přístupu, protože z vlastní praxe ho považuju za extrémně užitečný
Chápeš to zcela přesně jak jsem to myslel.
Tohle téma je super (po dlouhé řadě trollotémat na Rootu), protože je zajímavé, aktuální a vybízí k hlubšímu zamyšlení. Obecně asi platí, že když se program převede do churchovského λ-kalkulu (kde se nerozlišuje mezi dobou překladu a běhu), tak jakákoliv totální funkce, jejíž doména je konečná, se dá verifikovat typově (čili v době překladu v nějaké implementaci s dostatečně silným typovým systémem). Odhalování a charakteristika chyb tímto způsobem souvisí (na úrovni pusté teorie) s ι-operátorem.
-
co si vlastně představujete pod pojmem "silný typový systém"?
Rozhodně něco s HKT (tím se vyloučí Java apod.), to by byl středně silný, nicméně jak tu už někdo zmiňoval, adjektivum "silný" by mělo implikovat alespoň běžné závislostní typy à la Agda/Coq/Idris.
co tohle https://www.schoolofhaskell.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell ?
asi neumím říct, kde závislostní typy začínají
a "silný" je asi dost blbé označení
Tý vozo, jsem ani nedoufal, že to v Haskellu jde. To bude zase propálených hodin.
-
co si vlastně představujete pod pojmem "silný typový systém"? já přinejmenším ten implementovaný v GHC
Pro účely této diskuse si pod tím představuji ten nejsilnější teoreticky možný typový systém.
nevím, který to je, postněte odkaz
Klidně zrovna ten v Haskellu. Problémy, které tu zazněly, totiž neřeší. Jeden každý váš odkaz řešil jiný a podstatně jednodušší problém.
-
Klidně zrovna ten v Haskellu. Problémy, které tu zazněly, totiž neřeší. Jeden každý váš odkaz řešil jiný a podstatně jednodušší problém.
tak zrovna to sčítání řeší
-
Obecně asi platí, že když se program převede do churchovského λ-kalkulu (kde se nerozlišuje mezi dobou překladu a běhu), tak jakákoliv totální funkce, jejíž doména je konečná, se dá verifikovat typově (čili v době překladu v nějaké implementaci s dostatečně silným typovým systémem). Odhalování a charakteristika chyb tímto způsobem souvisí (na úrovni pusté teorie) s ι-operátorem.
Limit typů jsou časová náročnost. Limit testů zase neúplnost. Dokážete si někdo představit, že by se dal uělat nějaký kompromis, omezit ultimátnost typů, aby to otestování proběhlo v kontrolovaném čase. Nebo optimalizovat compiler, aby si dokázal domyslet některé věci a nepočítal to hrubou silou?
Samozřejmě si představuju spíš otázku konfigurace, kdy při vývoji budu mět méně striktní režim, a pak při buildu dám kompilovat třeba tejden.
-
tak zrovna to sčítání řeší
„To sčítání“ možná řeší. Ale to je nějaký váš problém, který tu neřešíme. My tu řešíme problém, že programátor měl použít sčítání a použil odčítání. Tohle neřeší žádný typový systém (tedy kromě takového, který odčítání vůbec nedovolí, což ale bude pro většinu programů nepoužitelné).
-
... (kde se nerozlišuje mezi dobou překladu a běhu) ...
Akorát že doba překladu a běhu jsou oddělené jak v čase, tak v prostoru. Spoustu informací typový systém prostě nemá a ani nemůže mít k dispozici.
Už jsem to tu jednou zmiňoval a v se zmohl akorát na "to se dá řešit". ::)
-
co si vlastně představujete pod pojmem "silný typový systém"?
Rozhodně něco s HKT (tím se vyloučí Java apod.), to by byl středně silný, nicméně jak tu už někdo zmiňoval, adjektivum "silný" by mělo implikovat alespoň běžné závislostní typy à la Agda/Coq/Idris.
Rád bych, když bychom se nedrželi jen toho, co se zatím někomou podařilo implementovat. Zajímá mě klidně i to, co by teoreticky šlo.
Co by šlo teoreticky se ví. Stačí vzít churchovský λ-kalkul a zamyslet se, jaké výpočty lze přenést na úroveň typů. Pokud požadujeme, aby překlad syntakticky správně utvořeného programu trval vždy jen konečnou dobu (to je poměrně rozumný předpoklad), lze přenést na tu vyšší ("typovou") úroveň funkce, které jsou totální (předpokladem je samozřejně dostatečně silný typový systém). Vše, co zbyde, se musí ponechat v tělech formulí. V implementaci by to pak zbylo na jednotkové testy. V podstatě stačí přečíst si původní článek o zmiňovaném λ-kalkulu a v příslušných kontextech si u typů představovat závislostní typy (jež korespondují s formální logikou s kvantifikátory). Tolik k tomu "co by teoreticky šlo", protože v praxi by byl přínos sporný až nesmyslný.
-
... (kde se nerozlišuje mezi dobou překladu a běhu) ...
Akorát že doba překladu a běhu jsou oddělené jak v čase, tak v prostoru. Spoustu informací typový systém prostě nemá a ani nemůže mít k dispozici.
Už jsem to tu jednou zmiňoval a v se zmohl akorát na "to se dá řešit". ::)
taky jste se mohl zeptat na detaily, nechce se mi rozepisovat všechno, když píšu sem, tak nepíšu kód :D
http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html
tohle je můj oblíbený příklad, ukazuje jak se od netypového syntaktického stromu dostat k silně typovanému, stejně to jde i s číslama
-
Limit typů jsou časová náročnost. Limit testů zase neúplnost. Dokážete si někdo představit, že by se dal uělat nějaký kompromis, omezit ultimátnost typů, aby to otestování proběhlo v kontrolovaném čase. Nebo optimalizovat compiler, aby si dokázal domyslet některé věci a nepočítal to hrubou silou?
Samozřejmě si představuju spíš otázku konfigurace, kdy při vývoji budu mět méně striktní režim, a pak při buildu dám kompilovat třeba tejden.
Problém je, že hodně zjednodušujete, a pak vyvozujete něco z nepřesností toho zjednodušení. Protože problém neúplnosti testů znamená, že mohou existovat vstupy, pro které dává testovaná jednotka chybný výsledek – přičemž taková kombinace není pokrytá testem. To je ale úplně jiná neúplnost, než „úplnost“ typů.
Formální dokazatelnost má smysl řešit u jednoduchých a kritických úloh typu zabezpečovací zařízení na železnici. U komplexních systémů typu ERP, bankovní systémy, webové prohlížeče apod. nemá vůbec smysl řešit rychlost případného kompilátoru, protože to je ten nejmenší problém – skutečný problém je v tom, že nikdo tak komplexní systém nedokáže správně formálně vyjádřit.
-
... (kde se nerozlišuje mezi dobou překladu a běhu) ...
Akorát že doba překladu a běhu jsou oddělené jak v čase, tak v prostoru. Spoustu informací typový systém prostě nemá a ani nemůže mít k dispozici.
Už jsem to tu jednou zmiňoval a v se zmohl akorát na "to se dá řešit". ::)
Jistě, ale když už se tu volá po teorii, je poměrně snadné namapovat si prakticky používaný jazyk na zmíněný λ-kalkul a uvědomit si, že těla formulí jsou "běh" a typové výrazy "překlad". Typový systém taky může počítat, jen o úroveň výš (v praxi něco na způsob TMP v C++, v teorii na úrovni typů složených z *). Jde jen o to, jaké operátory jsou na té které úrovni povoleny.
-
... (kde se nerozlišuje mezi dobou překladu a běhu) ...
Akorát že doba překladu a běhu jsou oddělené jak v čase, tak v prostoru. Spoustu informací typový systém prostě nemá a ani nemůže mít k dispozici.
Už jsem to tu jednou zmiňoval a v se zmohl akorát na "to se dá řešit". ::)
taky jste se mohl zeptat na detaily, nechce se mi rozepisovat všechno, když píšu sem, tak nepíšu kód :D
http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html
tohle je můj oblíbený příklad, ukazuje jak se od netypového syntaktického stromu dostat k silně typovanému, stejně to jde i s číslama
Cože??? To jako že až se na uživatelově stroji načtou vstupy, tak si pro ty vstupy teprve zkompiluju něco spustitelného???
Já doufám, že jsem to vůbec nepochopil. Opravdu v to upřímně doufám.
-
Klidně zrovna ten v Haskellu. Problémy, které tu zazněly, totiž neřeší. Jeden každý váš odkaz řešil jiný a podstatně jednodušší problém.
tak zrovna to sčítání řeší
Jaké je tedy správné řešení s použitím typů, které odhalí, že ve sčítací funkci programátor chybně napsal znaménko "-"? Zatím jsem se dozvěděl jen to, že to jde, s odkazem na článek. Jak by tedy vypadal zápis této triviality, např. v Haskellu?
-
... (kde se nerozlišuje mezi dobou překladu a běhu) ...
Akorát že doba překladu a běhu jsou oddělené jak v čase, tak v prostoru. Spoustu informací typový systém prostě nemá a ani nemůže mít k dispozici.
Už jsem to tu jednou zmiňoval a v se zmohl akorát na "to se dá řešit". ::)
taky jste se mohl zeptat na detaily, nechce se mi rozepisovat všechno, když píšu sem, tak nepíšu kód :D
http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html
tohle je můj oblíbený příklad, ukazuje jak se od netypového syntaktického stromu dostat k silně typovanému, stejně to jde i s číslama
Cože??? To jako že až se na uživatelově stroji načtou vstupy, tak si pro ty vstupy teprve zkompiluju něco spustitelného???
Já doufám, že jsem to vůbec nepochopil. Opravdu v to upřímně doufám.
nepochopil a jestli máte podobný background jako já (v mém případě C, C++, C#, python), tak se ani nedivím, docela mi trvalo než jsem to vstřebal (s pauzama možná rok), vlastně to není nic tak komplikovaného, ale je to hodně odlišné od programátorského mainstreamu
-
Klidně zrovna ten v Haskellu. Problémy, které tu zazněly, totiž neřeší. Jeden každý váš odkaz řešil jiný a podstatně jednodušší problém.
tak zrovna to sčítání řeší
Jaké je tedy správné řešení s použitím typů, které odhalí, že ve sčítací funkci programátor chybně napsal znaménko "-"? Zatím jsem se dozvěděl jen to, že to jde, s odkazem na článek. Jak by tedy vypadal zápis této triviality, např. v Haskellu?
viz článek hned pod větou "For example, singleton function for natural addition :+ can be implemented as follows:"
-
že těla formulí jsou "běh" a typové výrazy "překlad".
Možná ti jen nerozumím, ale:
mám množiny
Bool = True | False
RGB = Red | Green | Blue
pak mám funkci
isRed :: RGB -> Bool
která se dá zapsat takto:
isRed :: RGB -> Bool = (Red -> True) | (Green -> False) | (Blue -> False)
Té množině isRed ale obvykle říkáme funkce, a něco počítá, ale je to stejně jen množina, respektive pohled na průnik dvou množin. (Nebudu se pokoušet trefit se do přesného pojmosloví.)
Bavíme se cca o tom samém?
-
Jaké je tedy správné řešení s použitím typů, které odhalí, že ve sčítací funkci programátor chybně napsal znaménko "-"? Zatím jsem se dozvěděl jen to, že to jde, s odkazem na článek. Jak by tedy vypadal zápis této triviality, např. v Haskellu?
viz článek hned pod větou "For example, singleton function for natural addition :+ can be implemented as follows:"
Celý článek? V testech je to na několika řádcích a definice typu je na celý článek?
-
Proč @v dokázal pochopit, že se táži na limity toho typového systému vůči unittestům, zatímco jiní se mě pokouší přesvědčit že jsem idiot a ani nejsou schopni uvést zajímavé argumenty?
Omezené možnosti kontroly správnosti programu typovým systémem jsem vám přímočaře a bleskově (a vypadá to, že nejen já, nečetl jsem vše) předvedl na příkladu, víceméně důkazu sporem. Takže odpověď na váš původní dotaz už máte. Je třeba ještě něco řešit?
-
Jaké je tedy správné řešení s použitím typů, které odhalí, že ve sčítací funkci programátor chybně napsal znaménko "-"? Zatím jsem se dozvěděl jen to, že to jde, s odkazem na článek. Jak by tedy vypadal zápis této triviality, např. v Haskellu?
viz článek hned pod větou "For example, singleton function for natural addition :+ can be implemented as follows:"
Celý článek? V testech je to na několika řádcích a definice typu je na celý článek?
typy můžou být definovány v knihovnách a mezi testem a tím v článku je přece jenom trochu rozdíl, ty záruky (pro všechny dvojice přirozených čísel) prostě testama nelze nahradit
-
nepochopil a jestli máte podobný background jako já (v mém případě C, C++, C#, python), tak se ani nedivím, docela mi trvalo než jsem to vstřebal (s pauzama možná rok), vlastně to není nic tak komplikovaného, ale je to hodně odlišné od programátorského mainstreamu
Tak mi to prosím osvětlete. Můj background je primárně C++ a hned po tom právě Haskell. Jestli jsem ten článek pochopil dobře, tak je to o JIT kompilaci Haskellu. Kdy a kde ta JIT kompilace běží?
Jestli u mně, tak neznám všechny vstupy a nemůžu si dovolit třeba velikosti polí nacpat do typu.
Jestli to běží u uživatele, tak jsou důkladné unit testy jediná možnost, jak si užít klidnou dovolenou.
-
Proč @v dokázal pochopit, že se táži na limity toho typového systému vůči unittestům, zatímco jiní se mě pokouší přesvědčit že jsem idiot a ani nejsou schopni uvést zajímavé argumenty?
Omezené možnosti kontroly správnosti programu typovým systémem jsem vám přímočaře a bleskově (a vypadá to, že nejen já, nečetl jsem vše) předvedl na příkladu, víceméně důkazu sporem. Takže odpověď na váš původní dotaz už máte. Je třeba ještě něco řešit?
Pro pořádek, hodíte sem link na ten příspěvek, prosím? Protože je možné, že jsem to mezi spoustou toho smetí přehlédl.
-
viz článek hned pod větou "For example, singleton function for natural addition :+ can be implemented as follows:"
Nebudu líny jako ty a pošlu sem ten kus kódu, který má nahradit test na sčítání typem:
infixl 6 :+
(%:+) :: SNat n -> SNat m -> SNat (n :+ m)
SZ %:+ m = m
SS n %:+ m = SS (n %:+ m)
Vypadá to skoro jako test.
-
že těla formulí jsou "běh" a typové výrazy "překlad".
Možná ti jen nerozumím, ale:
mám množiny
Bool = True | False
RGB = Red | Green | Blue
pak mám funkci
isRed :: RGB -> Bool
která se dá zapsat takto:
isRed :: RGB -> Bool = (Red -> True) | (Green -> False) | (Blue -> False)
Té množině isRed ale obvykle říkáme funkce, a něco počítá, ale je to stejně jen množina, respektive pohled na průnik dvou množin. (Nebudu se pokoušet trefit se do přesného pojmosloví.)
Bavíme se cca o tom samém?
Ano, bavíme. Jen jsem psal (možná to trochu zapadlo), že operace (výpočty) na všech úrovních jsou dány formulemi a základními hodnotami. Co jde vypočítat na té které úrovni je dáno těmito hodnotami stanovenými úmluvou. Na té nejnižší úrovni se utvořeným výrazům říká funkce, protože odpovídají funkcím v teorii množin (nebo prostě aritmetice apod.). Stejně tvořeným výrazům na vyšší úrovni už se říká jinak (podle kontextu metavýrazy, metahodnoty apod.), ale v podstatě to je to samé, jen o úroveň výše. V případě isRed můžu jednoduše napsat funkci a stejně jednoduše můžu vytvořit součtový typ nad RGB implementující isRed o úroveň výše (něco jako "metaIsRed"), jenž by šel použít v typovém systému pro kontrolu v době překladu. Ale jak už jsem psal nejméně dvakrát, moc praktické takové počínání není, už jen proto, že takové typy by se nikdy nepoužily za běhu (ne že by se to nedělalo, ale jde jen o velmi speciální případy v avionice nebo kódu pro jaderné elektrárny apod.).
-
nepochopil a jestli máte podobný background jako já (v mém případě C, C++, C#, python), tak se ani nedivím, docela mi trvalo než jsem to vstřebal (s pauzama možná rok), vlastně to není nic tak komplikovaného, ale je to hodně odlišné od programátorského mainstreamu
Tak mi to prosím osvětlete. Můj background je primárně C++ a hned po tom právě Haskell. Jestli jsem ten článek pochopil dobře, tak je to o JIT kompilaci Haskellu. Kdy a kde ta JIT kompilace běží?
Jestli u mně, tak neznám všechny vstupy a nemůžu si dovolit třeba velikosti polí nacpat do typu.
Jestli to běží u uživatele, tak jsou důkladné unit testy jediná možnost, jak si užít klidnou dovolenou.
tak možná jsem zvolil trochu matoucí příklad, JIT je tam to co se implementuje, ne technika, která se využívá k implementaci něčeho jiného (uff)
kouzelný typ tam je "data TExp a" a pointa je, že nejde vytvořit hodnota tohoto typu, která by reprezentoval chybně typovaný syntaktický strom
-
že těla formulí jsou "běh" a typové výrazy "překlad".
Možná ti jen nerozumím, ale:
mám množiny
Bool = True | False
RGB = Red | Green | Blue
pak mám funkci
isRed :: RGB -> Bool
která se dá zapsat takto:
isRed :: RGB -> Bool = (Red -> True) | (Green -> False) | (Blue -> False)
Té množině isRed ale obvykle říkáme funkce, a něco počítá, ale je to stejně jen množina, respektive pohled na průnik dvou množin. (Nebudu se pokoušet trefit se do přesného pojmosloví.)
Bavíme se cca o tom samém?
Ano, bavíme. Jen jsem psal (možná to trochu zapadlo), že operace (výpočty) na všech úrovních jsou dány formulemi a základními hodnotami. Co jde vypočítat na té které úrovni je dáno těmito hodnotami stanovenými úmluvou. Na té nejnižší úrovni se utvořeným výrazům říká funkce, protože odpovídají funkcím v teorii množin (nebo prostě aritmetice apod.). Stejně tvořeným výrazům na vyšší úrovni už se říká jinak (podle kontextu metavýrazy, metahodnoty apod.), ale v podstatě to je to samé, jen o úroveň výše. V případě isRed můžu jednoduše napsat funkci a stejně jednoduše můžu vytvořit součtový typ nad RGB implementující isRed o úroveň výše (něco jako "metaIsRed"), jenž by šel použít v typovém systému pro kontrolu v době překladu.
Neměl by si prosím nějakou pěknu demonstraci principu toho metaIsRed. Nebo link na nějaké zdroje. Přeci jenom to hned z fleku nedávám (už jen ty množiny mi chvilku trvaly, než jsem dosáhl aha efektu).
A hlavně díky :-)
Ale jak už jsem psal nejméně dvakrát, moc praktické takové počínání není, už jen proto, že takové typy by se nikdy nepoužily za běhu.
Jak už jsem psal taky nejméně dvakrát, na praktičnost vám prdim :-)
-
tak možná jsem zvolil trochu matoucí příklad, JIT je tam to co se implementuje, ne technika, která se využívá k implementaci něčeho jiného (uff)
kouzelný typ tam je "data TExp a" a pointa je, že nejde vytvořit hodnota tohoto typu, která by reprezentoval chybně typovaný syntaktický strom
Wow!
+1
-
Ano, bavíme. Jen jsem psal (možná to trochu zapadlo), že operace (výpočty) na všech úrovních jsou dány formulemi a základními hodnotami. Co jde vypočítat na té které úrovni je dáno těmito hodnotami stanovenými úmluvou.
Nejsou ty formule náhodou takové ty "grupové axiomy"? Abych si to nějak srovnal.
-
typy můžou být definovány v knihovnách a mezi testem a tím v článku je přece jenom trochu rozdíl, ty záruky (pro všechny dvojice přirozených čísel) prostě testama nelze nahradit
Měl jem na mysli hlavně typy, které v knihovnách definovány nejsou a které je třeba definovat ke každé uživatelské funkci. Kdybych to aplikoval například na určitý integrál s mezemi a, b a funkcí f(x), tak ta definice typu bude buď nehorázně složitá, anebo bude duplicitou té funkce. Úplně se tím vytratí kouzlo jednoduchosti funkcionálního jazyka.
-
Ano, bavíme. Jen jsem psal (možná to trochu zapadlo), že operace (výpočty) na všech úrovních jsou dány formulemi a základními hodnotami. Co jde vypočítat na té které úrovni je dáno těmito hodnotami stanovenými úmluvou.
Nejsou ty formule náhodou takové ty "grupové axiomy"? Abych si to nějak srovnal.
Vypadají tak. Formule se prostě poskládá z elementárních hodnot (ty závisí na úrovni, o kterou se jedná) a operací (grupy mají např. jen jednu). Hlavní rozdíl je, že u grup nejsou typy. Jakmile je přidáme, dostaneme kategorie, ale o těch se tu nemluví, jinak přijde Voldemort a sežere nám všechny monády...
-
Nejsou ty formule náhodou takové ty "grupové axiomy"? Abych si to nějak srovnal.
Vypadají tak. Formule se prostě poskládá z elementárních hodnot (ty závisí na úrovni, o kterou se jedná) a operací (grupy mají např. jen jednu). Hlavní rozdíl je, že u grup nejsou typy. Jakmile je přidáme, dostaneme kategorie, ale o těch se tu nemluví, jinak přijde Voldemort a sežere nám všechny monády...
Díky!
-
Pro pořádek, hodíte sem link na ten příspěvek, prosím? Protože je možné, že jsem to mezi spoustou toho smetí přehlédl.
Zde: https://forum.root.cz/index.php?topic=18804.msg270520#msg270520 (https://forum.root.cz/index.php?topic=18804.msg270520#msg270520)
Když tu tak čtu tu diskusi (a některým věcem nerozumím), tak mě napadá, že by asi šlo testy nahradit nějakým typovým systémem, ale jeho složitost by byla extrémní. Z praktického hlediska testy vyměňují obecnost (kategorie) či případnou složitost typového systému za svoji neúplnost (testování diskrétních hodnot) - diskrétní hodnoty by musely být nahrazeny mnoha specifickými třídami vedoucími na výraznou složitost typového systému. Uvažuju správně?
-
Nejsou ty formule náhodou takové ty "grupové axiomy"? Abych si to nějak srovnal.
Vypadají tak. Formule se prostě poskládá z elementárních hodnot (ty závisí na úrovni, o kterou se jedná) a operací (grupy mají např. jen jednu). Hlavní rozdíl je, že u grup nejsou typy. Jakmile je přidáme, dostaneme kategorie, ale o těch se tu nemluví, jinak přijde Voldemort a sežere nám všechny monády...
Díky!
Abych to ještě uvedl přesněji: jsou dány základní typy (Church měl například ι a ο pro individua a pravdivostní hodnoty) a typované operace nad těmito typy. Funkčním výrazům odpovídají výhradně uzavřené formule, kupříkladu +≡(λx:ω)(λy:ω)x+y. Tělo je "x+y" a je vidět, že formule je uzavřená a výsledek je typu ω, takže typ formule je ωωω (asociativita je doleva). Tady je názorně vidět, že jediná operace u typů je v případě Churchova systému kompozice (v Haskellu se říká typový konstruktor). Když připustíme silnější typy, například se závislostmi (λ-kalkulu to je jedno, funguje s jakýmkoliv typovým systémem), můžeme počítat s typy a hodnoty na té nižší úrovní budou triviální (pro účely kontroly "překladu"), třeba u toho metaIsRed bychom měli jednotkové typy True a False. Největší sranda je, že jakmile začneme takto šaškovat s typy, neskončíme u dvou úrovní, ale nekonečně mnoha :) V praxi (jakmile to chceme implementovat) nás pak omezuje jen ta podmínka na konečnou dobu překladu (i když nekonečno vs. 100 let už zase takový rozdíl v praxi není...).
-
Pro pořádek, hodíte sem link na ten příspěvek, prosím? Protože je možné, že jsem to mezi spoustou toho smetí přehlédl.
Když tu tak čtu tu diskusi (a některým věcem nerozumím), tak mě napadá, že by asi šlo testy nahradit nějakým typovým systémem, ale jeho složitost by byla extrémní.
Přesně, výhody by rozhodně nepřevažovaly. Ale výslovně byla žádána teorie bez ohledu na praxi.
-
Když tu tak čtu tu diskusi (a některým věcem nerozumím), tak mě napadá, že by asi šlo testy nahradit nějakým typovým systémem, ale jeho složitost by byla extrémní. Z praktického hlediska testy vyměňují obecnost (kategorie) či případnou složitost typového systému za svoji neúplnost (testování diskrétních hodnot) - diskrétní hodnoty by musely být nahrazeny mnoha specifickými třídami vedoucími na výraznou složitost typového systému. Uvažuju správně?
Nešlo by takto nahradit ani zdaleka všechny testy. Vycházíte z toho, že test pokryje jenom některé možné vstupy, a nějakým typovým systémem byste omezil typy tak, aby byly možné jenom ty vstupy, které dávají správné výstupy. Jenomže tím se dostáváte do cyklu, protože to, zda jsou výstupy správné, není vlastností toho typového systému, ale je to arbitrární vlastnost – něco, co tomu přisuzujeme z venku. A k tomu právě slouží ty testy, abychom ověřili, že implementace (libovolná, klidně jako „typový systém“) odpovídá těm námi stanoveným pravidlům.
Jinak řečeno – o nějakém algoritmu ani typu nelze říci, zda je nebo není správně (sám o sobě). Jestli je nebo není správně závisí na tom, k čemu ho chceme použít. A to právě dělají testy – dají dohromady implementaci (algoritmus) a způsob použití a testují, zda daný algoritmus je správný pro daný způsob použití.
Typový systém nás může omezit, abychom něco nemohli použít způsobem, který pravděpodobně nikdy nebude správně. Ale už nás nemůže omezovat ve způsobu použití, který někdy správně je ale jindy správně není.
-
typy můžou být definovány v knihovnách a mezi testem a tím v článku je přece jenom trochu rozdíl, ty záruky (pro všechny dvojice přirozených čísel) prostě testama nelze nahradit
Měl jem na mysli hlavně typy, které v knihovnách definovány nejsou a které je třeba definovat ke každé uživatelské funkci. Kdybych to aplikoval například na určitý integrál s mezemi a, b a funkcí f(x), tak ta definice typu bude buď nehorázně složitá, anebo bude duplicitou té funkce. Úplně se tím vytratí kouzlo jednoduchosti funkcionálního jazyka.
pokud se bavíme o tom co teoreticky jde, tak je jedno jestli je to komplikované, pokud se bavíme o tom co je praktické, tak na integrál apod. to nikdo (???) aplikovat nebude, použití v http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html je aspoň pro mě takový sweet spot (viz též https://hackage.haskell.org/package/TTTAS-0.6.0)
-
Pro pořádek, hodíte sem link na ten příspěvek, prosím? Protože je možné, že jsem to mezi spoustou toho smetí přehlédl.
Zde: https://forum.root.cz/index.php?topic=18804.msg270520#msg270520 (https://forum.root.cz/index.php?topic=18804.msg270520#msg270520)
myslím, že jsem vám psal (?), že tohle by se nepřeložilo
Když tu tak čtu tu diskusi (a některým věcem nerozumím), tak mě napadá, že by asi šlo testy nahradit nějakým typovým systémem, ale jeho složitost by byla extrémní. Z praktického hlediska testy vyměňují obecnost (kategorie) či případnou složitost typového systému za svoji neúplnost (testování diskrétních hodnot) - diskrétní hodnoty by musely být nahrazeny mnoha specifickými třídami vedoucími na výraznou složitost typového systému. Uvažuju správně?
kurz und gut, že něco jde ještě neznamená, že to je dobrý nápad
-
Mě by zajímalo: Pokud tvrdíte, že typy dokáží nahradit unit testy, jak by se (jen teoreticky, ať se to překládá třeba sto let) naimplementovala funkce incrementString převádějící čísla uloženého ve stringu (třeba "42") na string obsahující číslo o jedna vyšší ("43") tak, aby typová kontrola dokázala nahradit alespoň (ne všechny případy pokrývající, situaci by mohl výrazně zlepšit např. nějaký property check test, ale to není pointou příspěvku) unit test
assertEqual("43", incrementString("42"))
? (nevalidní čísla není třeba pro potřeby příkladu uvažovat, můžeme pro ně např. chtít vrátit prázdný string)
-
Mě by zajímalo: Pokud tvrdíte, že typy dokáží nahradit unit testy, jak by se (jen teoreticky, ať se to překládá třeba sto let) naimplementovala funkce incrementString převádějící čísla uloženého ve stringu (třeba "42") na string obsahující číslo o jedna vyšší ("43") tak, aby typová kontrola dokázala nahradit alespoň (ne všechny případy pokrývající, situaci by mohl výrazně zlepšit např. nějaký property check test, ale to není pointou příspěvku) unit test
assertEqual("43", incrementString("42"))
? (nevalidní čísla není třeba pro potřeby příkladu uvažovat, můžeme pro ně např. chtít vrátit prázdný string)
Treba v jazyce Idris existuje za timto ucelem datovy typ So : Bool -> Type (https://github.com/idris-lang/Idris-dev/blob/master/libs/base/Data/So.idr), jehoz jedina hodnota je Oh a ta ma typ So True.
Pak staci psat
nazevTestu : So ("43" == incrementString("42"))
nazevTestu = Oh
Pokud tedy pozadovano rovnost neplati, ma nazevTestu typ So False jenze Oh ma typ So True, takze se program neprelozi.
-
Mě by zajímalo: Pokud tvrdíte, že typy dokáží nahradit unit testy, jak by se (jen teoreticky, ať se to překládá třeba sto let) naimplementovala funkce incrementString převádějící čísla uloženého ve stringu (třeba "42") na string obsahující číslo o jedna vyšší ("43") tak, aby typová kontrola dokázala nahradit alespoň (ne všechny případy pokrývající, situaci by mohl výrazně zlepšit např. nějaký property check test, ale to není pointou příspěvku) unit test
assertEqual("43", incrementString("42"))
? (nevalidní čísla není třeba pro potřeby příkladu uvažovat, můžeme pro ně např. chtít vrátit prázdný string)
Treba v jazyce Idris existuje za timto ucelem datovy typ So : Bool -> Type (https://github.com/idris-lang/Idris-dev/blob/master/libs/base/Data/So.idr), jehoz jedina hodnota je Oh a ta ma typ So True.
Pak staci psat
nazevTestu : So ("43" == incrementString("42"))
nazevTestu = Oh
Pokud tedy pozadovano rovnost neplati, ma nazevTestu typ So False jenze Oh ma typ So True, takze se program neprelozi.
Hmm, jestli chápu správně, tak pro tento příklad jedna (zřejmě dost pozdní) z fází překladu v jazyce Idris je vlastně spuštění kódu "43" == incrementString("42")?
Taková "typová kontrola" mi nakonec zní dost podobně jako unit test (což je také spuštění kódu), s tím rozdílem, že u unit testu si sám rozhodnu, že když dopadne červeně, mám kód považovat za nevalidní, kdežto v příkladu s Idris to za mě rozhodne překladač (kód je vždy nevalidní). Nebo je tam nějaký další rozdíl, který nevidím?
Každopádně je to zajímavé, ale jestli jsem to pochopil správně, paradoxně mi to vychází spíš jako argument pro unit testy :)
-
Pro pořádek, hodíte sem link na ten příspěvek, prosím? Protože je možné, že jsem to mezi spoustou toho smetí přehlédl.
Zde: https://forum.root.cz/index.php?topic=18804.msg270520#msg270520 (https://forum.root.cz/index.php?topic=18804.msg270520#msg270520)
Obávám se, že toto je ta samá věc, kterou uváděl Filip Jirsák. A tuším, že tu bylo minimálně dvakrát poukazováno, že to by problém být neměl - viz závislostní typy.
-
V tomto vláknu https://forum.root.cz/index.php?topic=18370.0 , díky pěkné odpovědi od @andi-ho, jsem si uvědomil jednu věc:
Mám zápis, čitelný pro stroj:
case s `hasMinimumLen` 4 of
Just sn -> Str.sub sn 20
Nothing -> "default"
Ale pro člověka je mnohem lepší zápis:
if (Str.len s) < 4 then
"default"
else
Str.sub s 20
Jenže není vůbec žádný problém naučit stroj, aby ten druhý, lidský zápis chápal a převedl si ho na ten svůj.
Tudíž já mohu napsat:
add x y = x + y
stroj si to převede na svou reprezentaci (něco jako x * succ y), ale podstatné je, že když změním implementaci:
add x y = y + x
add x y = if x == 0 then y else x + y
tak stroj pozná, že je to stejného typu, a nebude mět výhrady, zatímco
add x y = if x < 1 then y else x + y
odmítne.
Pointa je tedy taková, že možná není tak úplně nutné, aby psaní těch komplexních typů bylo nějak zvláště o tolik složitější než na to napsat test. Záleží, jak dobře se to navrhne.
-
Obávám se, že toto je ta samá věc, kterou uváděl Filip Jirsák. A tuším, že tu bylo minimálně dvakrát poukazováno, že to by problém být neměl - viz závislostní typy.
Nazval bych to teologickým programováním: „Když něčemu nerozumím, musí to být všemocné“. (Po této fázi následuje fáze zklamání, že to příslušný jazyk nebo koncepce „neumí“, zařazení jazyka či koncepce na seznam špatných jazyků/koncepcí a vyhlédnutí dalšího kandidáta, který už určitě bude dokonalý.)
Vy se stále touláte někde ve výšinách, ale unikají vám základní věci. Testy se píšou proto, aby odhalily případné chyby v programu. Na tom se shodneme? Tedy pokud program může obsahovat chyby, má smysl psát testy. Na tom se také shodneme? Pak tedy platí, že testy nemá smysl psát jenom u programu, u kterého bezpečně víme, že neobsahuje žádnou chybu. I na tom se shodneme? Takže vy tu vlastně hledáte způsob, jak docílit toho, aby platilo „pokud to šlo zkompilovat, není v tom žádná chyba“, je to tak?
-
Pointa je tedy taková, že možná není tak úplně nutné, aby psaní těch komplexních typů bylo nějak zvláště o tolik složitější než na to napsat test. Záleží, jak dobře se to navrhne.
Test pokrývá jen malou množinu vstupů z (často teoreticky nekonečné) množiny všech možných vstupů. Jak by asi „kompilátor“ doplnil definici toho komplexního typu pro vstupy, které by tím testem nebyly pokryté?
Napsat test může být takhle jednoduché:
assert 5 == fun(2, 3)
assert 3 == fun(1, 2)
Co k tomu přidáte, aby to popisovalo komplexní typ?
-
Napsat test může být takhle jednoduché:
assert 5 == fun(2, 3)
assert 3 == fun(1, 2)
V Perlu 6 by šel napsat typ (resp. podtyp), který jen kontroluje tyto případy
subset Add where { $++ || add(1,1) == 2 && add(2,3) == 5 };
sub add ( $a, $b --> Add ) { $a + $b };
say add 1,2 ;
ale samozřejmě chápu, že k tomuto původní dotaz nesměřoval :)
-
tak možná jsem zvolil trochu matoucí příklad, JIT je tam to co se implementuje, ne technika, která se využívá k implementaci něčeho jiného (uff)
kouzelný typ tam je "data TExp a" a pointa je, že nejde vytvořit hodnota tohoto typu, která by reprezentoval chybně typovaný syntaktický strom
Tak já zopakuju svůj blbý dotaz. Ty instance toho typu TExp se vytvářejí v runtime? Jestli ne, tak proč to neprohnat přímo skrz ghc (se všemi omezeními, které už jsem zmiňoval)?
Pokud se vytvářejí v runtime, tak je to argument pro unit (a ostatní) testy. Udělat z Haskellu dynamicky typovaný jazyk je sice cool, ale jako u každého jiného dynamicky typovaného jazyka ztrácím typovou kontrolu v době překladu a jsem odkázáný čistě na ty testy.
-
tak možná jsem zvolil trochu matoucí příklad, JIT je tam to co se implementuje, ne technika, která se využívá k implementaci něčeho jiného (uff)
kouzelný typ tam je "data TExp a" a pointa je, že nejde vytvořit hodnota tohoto typu, která by reprezentoval chybně typovaný syntaktický strom
Tak já zopakuju svůj blbý dotaz. Ty instance toho typu TExp se vytvářejí v runtime? Jestli ne, tak proč to neprohnat přímo skrz ghc (se všemi omezeními, které už jsem zmiňoval)?
Pokud se vytvářejí v runtime, tak je to argument pro unit (a ostatní) testy. Udělat z Haskellu dynamicky typovaný jazyk je sice cool, ale jako u každého jiného dynamicky typovaného jazyka ztrácím typovou kontrolu v době překladu a jsem odkázáný čistě na ty testy.
ano, v runtime, je to miniaturní překladač, překladače mají dispozici překládaný kód až v runtime (TExp je syntaktický strom překládaného "jazyka")
-
Zde: https://forum.root.cz/index.php?topic=18804.msg270520#msg270520 (https://forum.root.cz/index.php?topic=18804.msg270520#msg270520)
myslím, že jsem vám psal (?), že tohle by se nepřeložilo
Právěže přeložilo, syntakticky ani typově to nemá chybu, ale významově už ano.
-
ano, v runtime, je to miniaturní překladač, překladače mají dispozici překládaný kód až v runtime (TExp je syntaktický strom překládaného "jazyka")
Konečně. Takže tady má BoneFlute příklad, kdy unittesty (nebo testy obecně) nejde nahradit typovým systémem. A to ani hypoteticky za jakýchkoliv předpokladů. Prostě proto, že se typový systém dostane ke slovu až v runtimu.
-
Zde: https://forum.root.cz/index.php?topic=18804.msg270520#msg270520 (https://forum.root.cz/index.php?topic=18804.msg270520#msg270520)
myslím, že jsem vám psal (?), že tohle by se nepřeložilo
Právěže přeložilo, syntakticky ani typově to nemá chybu, ale významově už ano.
nepřeložilo, reprezentace celých čísel, kterou to používá má pro každé konkrétní číslo jiný datový typ (to jsou ty "dependent types"), ale neznamená to, že musíte pro každé číslo implementovat funkcionalitu zvlášť, ten typový systém je docela chytrý
-
ano, v runtime, je to miniaturní překladač, překladače mají dispozici překládaný kód až v runtime (TExp je syntaktický strom překládaného "jazyka")
Konečně. Takže tady má BoneFlute příklad, kdy unittesty (nebo testy obecně) nejde nahradit typovým systémem. A to ani hypoteticky za jakýchkoliv předpokladů. Prostě proto, že se typový systém dostane ke slovu až v runtimu.
tak to není a pro původní dotaz to moc neznamená, protože ten se týkal teoretických mezí
-
tak to není a pro původní dotaz to moc neznamená, protože ten se týkal teoretických mezí
Ani sebelepší typový systém nezajistí, že program bude bez chyby. Teoretické meze neleží v typovém systému nebo kompilátoru, ale ve schopnosti formálně popsat specifikaci. Pak může nastoupit automatické dokazování nebo verifikace, např. Isabelle.
-
ad "Ani sebelepší typový systém nezajistí, že program bude bez chyby."
ano, stejně jako ten nejlepší testovací framework, musíte ho taky použít, v obou případech musíte napsat správný typ resp. testy
ad "Teoretické meze neleží v typovém systému nebo kompilátoru, ale ve schopnosti formálně popsat specifikaci."
to nejsou teoretické meze ale praktické - "lidský faktor"
ad "Pak může nastoupit automatické dokazování nebo verifikace, např. Isabelle."
tak kontrola souladu datového typu s programem je formální verfikace a přijde mi pozoruhodné, že jste zmínil Isabelle a ne IMHO mnohem známější Coq
-
tak to není a pro původní dotaz to moc neznamená, protože ten se týkal teoretických mezí
Ani sebelepší typový systém nezajistí, že program bude bez chyby. Teoretické meze neleží v typovém systému nebo kompilátoru, ale ve schopnosti formálně popsat specifikaci. Pak může nastoupit automatické dokazování nebo verifikace, např. Isabelle.
V čem se liší dostatečně silný typový systém od automatického dokazování?
-
V čem se liší dostatečně silný typový systém od automatického dokazování?
Že typová kontrola může proběhnout až dynamicky za běhu. Automatické dokazování se pokud vím obvykle za běhu neprovádí.
-
Mám zápis, čitelný pro stroj:
case s `hasMinimumLen` 4 of
Just sn -> Str.sub sn 20
Nothing -> "default"
Ale pro člověka je mnohem lepší zápis:
if (Str.len s) < 4 then
"default"
else
Str.sub s 20
Co to má být "zápis čitelný pro stroj"? Program v jakémkoli jazyce, který lze zpracovat překladačem? Nebo strojový kód?
-
V čem se liší dostatečně silný typový systém od automatického dokazování?
Že typová kontrola může proběhnout až dynamicky za běhu. Automatické dokazování se pokud vím obvykle za běhu neprovádí.
No.... ne.
Pierce, TPL: A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute.
...
The word “static” is sometimes added explicitly—we speak of a “statically typed programming language,” for example—to distinguish the sorts of compile-time analyses we are considering here from the dynamic or latent typing found in languages such as Scheme, where run-time type tags are used to distinguish different kinds of structures in the heap. Terms like “dynamically typed” are arguably misnomers and should probably be replaced by “dynamically checked,” but the usage is standard.
Myslím, že v tomhle bych se o autoritu opřel :)
-
Co to má být "zápis čitelný pro stroj"? Program v jakémkoli jazyce, který lze zpracovat překladačem? Nebo strojový kód?
BoneFlute má na mysli, že v tom prvním případě programátor překladači poskytnul důkaz správnosti typů, v tom druhém případě si ten důkaz počítač našel sám (což je obecně nerozhodnutelný problém).
-
Co to má být "zápis čitelný pro stroj"? Program v jakémkoli jazyce, který lze zpracovat překladačem? Nebo strojový kód?
BoneFlute má na mysli, že v tom prvním případě programátor překladači poskytnul důkaz správnosti typů, v tom druhém případě si ten důkaz počítač našel sám
Ne tak docela "našel", jako že prostě si řekne, že "if podmínka" aha, to si musím přeložit na tyhle Maybe typy...
(což je obecně nerozhodnutelný problém)
V jakém smyslu? Buď té konstrukci rozumí, nebo jí odmítne. IMHO nic složitého.
-
Co to má být "zápis čitelný pro stroj"? Program v jakémkoli jazyce, který lze zpracovat překladačem? Nebo strojový kód?
Bavíme se o typech, a v tomto kontextu strojem nazývám kompilátor.
-
V čem se liší dostatečně silný typový systém od automatického dokazování?
Že typová kontrola může proběhnout až dynamicky za běhu. Automatické dokazování se pokud vím obvykle za běhu neprovádí.
No.... ne.
Pierce, TPL: A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute.
...
The word “static” is sometimes added explicitly—we speak of a “statically typed programming language,” for example—to distinguish the sorts of compile-time analyses we are considering here from the dynamic or latent typing found in languages such as Scheme, where run-time type tags are used to distinguish different kinds of structures in the heap. Terms like “dynamically typed” are arguably misnomers and should probably be replaced by “dynamically checked,” but the usage is standard.
Myslím, že v tomhle bych se o autoritu opřel :)
OK. Pak ale zase padá spousta argumentů, které tu tahali v a BoneFlute. Padá např. ten odkaz od v o přesunu překladu Haskellu do runtime. Protože to pak říká jenom to, že pomocí LLVM mašinerie se dá z Haskellu udělat “dynamically checked” jazyk.
-
ano, stejně jako ten nejlepší testovací framework, musíte ho taky použít, v obou případech musíte napsat správný typ resp. testy
Máte testy zařazené na špatnou úroveň. Na jedné úrovni jsou typy nebo algoritmy – ty musí být správně, aby program fungoval správně. Pak je volitelná druhá úroveň – můžete napsat testy, které otestují nějaké zajímavé případy. Žádný systém algoritmizace, typů nebo psaní testů nezajistí bezchybnost programu – testy slouží jen ke zvýšení pravděpodobnosti, že chybu odhalíte.
to nejsou teoretické meze ale praktické - "lidský faktor"
Myslel jsem, že se bavíme o tom, co je reálně dosažitelné. Ne že prohlásíme, že program předhodíme nějakému orákulu nebo CML, který nám řekne, zda je správně nebo špatně. No a že takový CML neumíme vytvořit? To je „lidský faktor“…
-
Myslel jsem, že se bavíme o tom, co je reálně dosažitelné. Ne že prohlásíme, že program předhodíme nějakému orákulu nebo CML, který nám řekne, zda je správně nebo špatně. No a že takový CML neumíme vytvořit? To je „lidský faktor“…
A navrch se těma typama a dokazováním zabýváme právě kvůli tomu lidskému faktoru.
-
OK. Pak ale zase padá spousta argumentů, které tu tahali v a BoneFlute. Padá např. ten odkaz od v o přesunu překladu Haskellu do runtime. Protože to pak říká jenom to, že pomocí LLVM mašinerie se dá z Haskellu udělat “dynamically checked” jazyk.
ne, ten článek říká, že jde v haskellu udělat překladač (AOT/JIT nezáleží), který bude pracovat s dočasnou reprezentací (TExp), která má stejné typové garance, jako by to byl kód v haskellu, tj. TExp garantuje, že žádná funkce nad ním (funkce, která je součástí kompilátoru, staticky ověřená při překladu překladače) neudělá blbost typu string + int (nejprovařenější příklad, jde to rozšířit na další vlastnosti) a dále ukazuje, že k takové reprezentaci lze přejít za běhu (proto jsem ten link postnul), což je docela normální, protože překladač dostane zdroják až za běhu, ne při překladu překladače
-
OK. Pak ale zase padá spousta argumentů, které tu tahali v a BoneFlute. Padá např. ten odkaz od v o přesunu překladu Haskellu do runtime. Protože to pak říká jenom to, že pomocí LLVM mašinerie se dá z Haskellu udělat “dynamically checked” jazyk.
Zrovna tu mám projektík, kde se podobnou mašinérii budu snažit vyrobit... ne, ten článek říká něco jiného.
Autor píše "interpret" jazyka. Za tímto účelem si vyrobil Abstrat syntax tree, který je postavený na GADT... což se hezky dá využít k tomu, že v tom stromě nelze sestavit špatně typovaný program (uzel má typ "TExp Bool" - tak ho nejde dát jako potomka "+", který očekává jako parametry "TExp Double"). Při parsingu si vyrobí AST bez typů (takže tam tyhle chybné operace vyjádřit jde) - a ten článek je o tom, jak té netypované reprezentace přejde k té typované.
Je to v podstatě ta otázka o tom sčítání - když bych měl tu funkci
add :: SNat n -> SNat m -> SNat (n + m)
tak je to hezké, ale jak vyrobit tu funkci
toNat :: Int -> SNat n
Kdy ten typ závisí na vstupu od uživatele. No a..ono to nějak jde (někdy)...doufám, že až si to implementuju, tak i pochopím jak...
-
Myslel jsem, že se bavíme o tom, co je reálně dosažitelné. Ne že prohlásíme, že program předhodíme nějakému orákulu nebo CML, který nám řekne, zda je správně nebo špatně. No a že takový CML neumíme vytvořit? To je „lidský faktor“…
To není lidský faktor, to je halting problem....
-
toNat :: Int -> SNat n
Kdy ten typ závisí na vstupu od uživatele. No a..ono to nějak jde (někdy)...doufám, že až si to implementuju, tak i pochopím jak...
hint: jestli na to ghc nemá nějaký nový trik, tak budete potřebovat něco jako je v článku "data ATExp = forall a . TExp a ::: TTyp a", já jsem to teda potřeboval (a kdybyste to zvládl bez ATExp tak to sem určitě napište :D )
-
(ne že by se to nedělalo, ale jde jen o velmi speciální případy v avionice nebo kódu pro jaderné elektrárny apod.).
O tom bych měl něco vědět. Pro které elektrárny konkrétně? A o jaký typ kódu?
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
No tak to bych řekl, že ani náhodou! Nějaké podklady/porovnání by nebyly?
-
Myslel jsem, že se bavíme o tom, co je reálně dosažitelné. Ne že prohlásíme, že program předhodíme nějakému orákulu nebo CML, který nám řekne, zda je správně nebo špatně. No a že takový CML neumíme vytvořit? To je „lidský faktor“…
To není lidský faktor, to je halting problem....
To neni halting problem.
Uvedom si, ze tomu orakulu nepredhazujes libovolny program, ale program v urcenem formatu s urcenymi omezenimi (v extremnim pripade si muzes predstavit, ze povinnou soucasti programu v danem jazyce je i jeho dukaz).
Samozrejme zdaleka nejsme tam, kde by tohle bylo prakticke. Ale je potreba si uvedomit, ze se to obecnemu halting problemu podoba, ale ta uloha je (resp. muze byt) lehci.
-
Myslel jsem, že se bavíme o tom, co je reálně dosažitelné. Ne že prohlásíme, že program předhodíme nějakému orákulu nebo CML, který nám řekne, zda je správně nebo špatně. No a že takový CML neumíme vytvořit? To je „lidský faktor“…
To není lidský faktor, to je halting problem....
To neni halting problem.
Uvedom si, ze tomu orakulu nepredhazujes libovolny program, ale program v urcenem formatu s urcenymi omezenimi (v extremnim pripade si muzes predstavit, ze povinnou soucasti programu v danem jazyce je i jeho dukaz).
No já reagoval na:
Myslel jsem, že se bavíme o tom, co je reálně dosažitelné. Ne že prohlásíme, že program předhodíme nějakému orákulu nebo CML, který nám řekne, zda je správně nebo špatně.
Což bych řekl, že o omezení nemluví...
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
No tak to bych řekl, že ani náhodou! Nějaké podklady/porovnání by nebyly?
No, neodvažoval bych se něco takového tvrdit, ale faktem je, že programy v Haskellu jsou typicky docela hodně úsporné, takže "ani náhodou" bych se teda neodvažoval tvrdit taky.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
No tak to bych řekl, že ani náhodou! Nějaké podklady/porovnání by nebyly?
Je směšně triviální nahlédnout, že čím silnější typový systém, tím lepší znovupoužitelnost (ve smyslu DRY). V Javě a spol. nejde např. napsat obecná monáda kvůli absenci HKT (v C++ jde). S HKT bez závislostních typů se ale taky brzy narazí a musí se duplikovat. V několika iteracích to je názorně vidět na Swiftu, na začátku bylo v stdlib hodně duplicitního kódu kvůli slabému typovému systému. V poslední verzi (4.2) se kvanta kódu mohla smazat díky podmíněné konformanci a dalším vymoženostem. Až přidají HKT (je to v plánu), stdlib opět zeštíhlí. Tím to asi skončí, protože v 5. verzi už má být (konečně) stabilní ABI, ale i tak je docílená minimalizace kódu úctyhodná (nemluvě o vyšší bezpečnosti).
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
No tak to bych řekl, že ani náhodou! Nějaké podklady/porovnání by nebyly?
Je směšně triviální nahlédnout, že čím silnější typový systém, tím lepší znovupoužitelnost (ve smyslu DRY). V Javě a spol. nejde např. napsat obecná monáda kvůli absenci HKT (v C++ jde). S HKT bez závislostních typů se ale taky brzy narazí a musí se duplikovat. V několika iteracích to je názorně vidět na Swiftu, na začátku bylo v stdlib hodně duplicitního kódu kvůli slabému typovému systému. V poslední verzi (4.2) se kvanta kódu mohla smazat díky podmíněné konformanci a dalším vymoženostem. Až přidají HKT (je to v plánu), stdlib opět zeštíhlí. Tím to asi skončí, protože v 5. verzi už má být (konečně) stabilní ABI, ale i tak je docílená minimalizace kódu úctyhodná (nemluvě o vyšší bezpečnosti).
Ale já myslel nějaké konkrétní příklady v porovnání s dynamickými jazyky, ne s Javou. Že vymakaný typový systém zjednoduší program oproti neohrabanému jako je třeba v Javě, o tom bych se asi nepřel. Ale ten samý efekt vidím i u dynamických jazyků. Jenže zatímco takový Lisp nebo Smalltalk jsou směšně jednoduché, tak třeba ten Haskell mi vždycky připadal jako poměrně složitý.
-
Ale já myslel nějaké konkrétní příklady v porovnání s dynamickými jazyky, ne s Javou.
Tohle možná půjde díky širokým knihovnám v některých dynamických jazycích, ale typicky to bývá dost problém... setřiď lidi sestupně podle věku, vzestupně podle příjmení - využívá typeclass Monoid a "rekurzivní" instance.
sortBy (flip (comparing age) <> comparing surname)
Monady - callback hell - JS vs. PureScript (nový JS na to má "await", takže tam už ten rozdíl není tak velký).
Polymorfní v návratové hodnotě - parsing JSONu. Tenhle kód provede kontrolu - nahlásí chybu, pokud vstupní data neobsahují položky s korektním typem. Dekóduje čas ve stringu na odpovídající typ, se kterým se dá normálně pracovat (UTCTime je něco jako "new Date()").
Vysvětlení: operátor ".:" je polymorfní v návratové hodnotě, takže hledá v objektu ten typ, který je požadován. Celé to běží v Parser monadu, takže v případě chyby se to celkem rozumně reportuje. Operátor <|> je "nebo" a funguje podobně jako "try...catch", dá se hezky řetězit.
data Person = Person Text Double UTCTime
instance FromJSON Person where
parseJSON = withObject "person" $ \o -> do
jmeno <- o .: "name" <|> o .: "jmeno"
vyska <- o .: "height" <|> o .: "vyska"
narozeni <- o .: "birthdate" <|> o .: "narozeni"
return (Person jmeno vyska narozeni)
IMO kód v dynamických jazycích může být kratší, protože třeba v případě toho parsingu by se člověk prostě vybodnul na kontrolu korektního vstupu... v některých jaycích a knihovnách to ještě nějak relativně dobře funguje přes generic parsing, ale jak do toho člověk potřebuje trochu víc hrábnout (zpětná kompatibilita apod.), tak už ten kód hodně roste a je dost nepřehledný.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
No tak to bych řekl, že ani náhodou! Nějaké podklady/porovnání by nebyly?
Je směšně triviální nahlédnout, že čím silnější typový systém, tím lepší znovupoužitelnost (ve smyslu DRY). V Javě a spol. nejde např. napsat obecná monáda kvůli absenci HKT (v C++ jde). S HKT bez závislostních typů se ale taky brzy narazí a musí se duplikovat. V několika iteracích to je názorně vidět na Swiftu, na začátku bylo v stdlib hodně duplicitního kódu kvůli slabému typovému systému. V poslední verzi (4.2) se kvanta kódu mohla smazat díky podmíněné konformanci a dalším vymoženostem. Až přidají HKT (je to v plánu), stdlib opět zeštíhlí. Tím to asi skončí, protože v 5. verzi už má být (konečně) stabilní ABI, ale i tak je docílená minimalizace kódu úctyhodná (nemluvě o vyšší bezpečnosti).
Ale já myslel nějaké konkrétní příklady v porovnání s dynamickými jazyky, ne s Javou. Že vymakaný typový systém zjednoduší program oproti neohrabanému jako je třeba v Javě, o tom bych se asi nepřel. Ale ten samý efekt vidím i u dynamických jazyků. Jenže zatímco takový Lisp nebo Smalltalk jsou směšně jednoduché, tak třeba ten Haskell mi vždycky připadal jako poměrně složitý.
U dynamických jazyků to vyjde nastejno, akorát člověk nemá tu typovou kontrolu. Přínos mocných typových systémů je právě v tom, že při plné typové kontrole umožňuje značnou flexibilitu (“dynamičnost”). Jinak Haskell složitý není, jen jiný - matoucí je možná syntax.
-
IMO kód v dynamických jazycích může být kratší, protože třeba v případě toho parsingu by se člověk prostě vybodnul na kontrolu korektního vstupu...
Byl bych velmi opatrný s tvrzením, že kratší kód se automaticky rovná lepší kód. Vy jste napsal konkrétní případ, kdy je kód kratší ale jiný, ale ani kratší kód, který dělá přesně to samé, jako delší kód, nemusí být lepší.
-
Že vymakaný typový systém zjednoduší program oproti neohrabanému jako je třeba v Javě, o tom bych se asi nepřel. Ale ten samý efekt vidím i u dynamických jazyků.
někdo tvrdí, že pokud máte dostatečné pokrytí testy, tak nepotřebujete statický typový systém - myslíte, že by ten efekt nezmizel kdybychom započítali i testy? přece jenom typy umožňují množinu možných testcasů dost zmenšit
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Nechci spekulovat, ale jednoduchá úvaha, že když netypový systém otypuju, tj. omezím jej, dosáhnu tak větší znovupoužitelnosti, neboli obecnosti, mi nedává smysl.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Nechci spekulovat, ale jednoduchá úvaha, že když netypový systém otypuju, tj. omezím jej, dosáhnu tak větší znovupoužitelnosti, neboli obecnosti, mi nedává smysl.
Co je “netypový systém”? Dynamické typování je netypové nebo ne? Jinak znovupoužitelnost nesouvisí s obecností.
-
někdo tvrdí, že pokud máte dostatečné pokrytí testy, tak nepotřebujete statický typový systém - myslíte, že by ten efekt nezmizel kdybychom započítali i testy? přece jenom typy umožňují množinu možných testcasů dost zmenšit
Pozor, další myšlenka:
Opačně: Neobsahuje v sobě každý test z podstaty "typovou" kontrolu? Neboli vkládám-li na vstup diskrétní hodnoty a testuju-li výstupní diskrétní hodnoty (přísnější podmínka), netestuju zároveň i kategorii těch hodnot (volnější podmínka)?
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Nechci spekulovat, ale jednoduchá úvaha, že když netypový systém otypuju, tj. omezím jej, dosáhnu tak větší znovupoužitelnosti, neboli obecnosti, mi nedává smysl.
Co je “netypový systém”? Dynamické typování je netypové nebo ne? Jinak znovupoužitelnost nesouvisí s obecností.
Navíc je nutné rozlišit slabé typování od dynamického.
Dynamické typování je také typové. Rozdíl je jen v tom, že typ si nese jako atribut.
-
Nechci spekulovat, ale jednoduchá úvaha, že když netypový systém otypuju, tj. omezím jej, dosáhnu tak větší znovupoužitelnosti, neboli obecnosti, mi nedává smysl.
Co je “netypový systém”? Dynamické typování je netypové nebo ne?
Netypový systém je systém bez typů (odvolávám se na Smalltalk, když už se tu šermuje Haskellem), dynamicky typovaný systém (https://en.wikipedia.org/wiki/Type_system#Dynamic_type_checking_and_runtime_type_information) typy obsahuje a testuje.
Jinak znovupoužitelnost nesouvisí s obecností.
Opravdu? Třeba se pletu. Nadhoďte příklad (ale prosím v nějaké profláklejší notaci než Haskellu).
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Naopak silný typový systém zvyšuje délku kódu a snižuje znovupoužitelnost. Pokud mi typový systém nedovolí vložit int místo float nebo float místo double, musím to v kódu nějak obejít, což jej prodlouží.
Bavíme se o silně nabo staticky typovaném systému?
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Naopak silný typový systém zvyšuje délku kódu a snižuje znovupoužitelnost. Pokud mi typový systém nedovolí vložit int místo float nebo float místo double, musím to v kódu nějak obejít, což jej prodlouží.
To rozhodně ne, jak implicitní type cast prodlouží kód? Je třeba mít na paměti, že v jazycích s kontrolou typů v době překladu je tendence redukovat explicitní deklaraci typů. Logicky nikdo se nechce párat s psaním zbytečného kódu, ale chce vyzobat rozinky přísné a včasné typové kontroly. V běžných jazycích (OO i funkcionálních) se většina typů odvozuje (dedukuje). V kombinaci s rozhraními se použití dobře navržené knihovny obejde bez explicitních deklarací typů. V takovém C++ můžu mít téměř všude auto, včetně deklarací funkcí.
-
Nechci spekulovat, ale jednoduchá úvaha, že když netypový systém otypuju, tj. omezím jej, dosáhnu tak větší znovupoužitelnosti, neboli obecnosti, mi nedává smysl.
Co je “netypový systém”? Dynamické typování je netypové nebo ne?
Netypový systém je systém bez typů (odvolávám se na Smalltalk, když už se tu šermuje Haskellem)
Smalltalk ale typy má.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Naopak silný typový systém zvyšuje délku kódu a snižuje znovupoužitelnost. Pokud mi typový systém nedovolí vložit int místo float nebo float místo double, musím to v kódu nějak obejít, což jej prodlouží.
Bavíme se o silně nabo staticky typovaném systému?
nechá http://hackage.haskell.org/package/base-4.11.1.0/docs/Prelude.html#t:Num
IMHO silně a staticky
-
Jinak znovupoužitelnost nesouvisí s obecností.
Opravdu? Třeba se pletu.
Možná jde jen o slovíčkaření. Už tu byl uveden příklad Swiftu. Ve verzi 4.2 se silnějším typovým systémem se z stdlib smazalo hodně duplicitního kódu (specializací generik), který byl nahrazen jednou implementací pro mnoho typů (se společným protokolem). Obecnějšími se ty typy ovšem nestaly.
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Naopak silný typový systém zvyšuje délku kódu a snižuje znovupoužitelnost. Pokud mi typový systém nedovolí vložit int místo float nebo float místo double, musím to v kódu nějak obejít, což jej prodlouží.
To rozhodně ne, jak implicitní type cast prodlouží kód? Je třeba mít na paměti, že v jazycích s kontrolou typů v době překladu je tendence redukovat explicitní deklaraci typů. Logicky nikdo se nechce párat s psaním zbytečného kódu, ale chce vyzobat rozinky přísné a včasné typové kontroly. V běžných jazycích (OO i funkcionálních) se většina typů odvozuje (dedukuje). V kombinaci s rozhraními se použití dobře navržené knihovny obejde bez explicitních deklarací typů. V takovém C++ můžu mít téměř všude auto, včetně deklarací funkcí.
Tím, že jsem nucen používat explicitní typování tam, kde bych přetypovávat nemusel. Nemohu jednou funkcí sčítat int, float a spojovat stringy. Musím mít tři funkce.
Také si potřebné typy musím nadefinovat, jinak deklarace funkcí vypadají takhle:
circumference :: Float -> Float
circumference r = 2 * pi * r
-
někdo tvrdí, že pokud máte dostatečné pokrytí testy, tak nepotřebujete statický typový systém - myslíte, že by ten efekt nezmizel kdybychom započítali i testy? přece jenom typy umožňují množinu možných testcasů dost zmenšit
Pozor, další myšlenka:
Opačně: Neobsahuje v sobě každý test z podstaty "typovou" kontrolu? Neboli vkládám-li na vstup diskrétní hodnoty a testuju-li výstupní diskrétní hodnoty (přísnější podmínka), netestuju zároveň i kategorii těch hodnot (volnější podmínka)?
furt je ten test jenom pro jednu volbu typů argumentů, u dynamického jazyka je možných voleb spousta
-
Ještě tu nezaznělo, že kromě vyšší bezpečnosti přináší silný typový systém také úsporu kódu díky větší znovupoužitelnosti. To jen tak pro úplnost.
Naopak silný typový systém zvyšuje délku kódu a snižuje znovupoužitelnost. Pokud mi typový systém nedovolí vložit int místo float nebo float místo double, musím to v kódu nějak obejít, což jej prodlouží.
To rozhodně ne, jak implicitní type cast prodlouží kód? Je třeba mít na paměti, že v jazycích s kontrolou typů v době překladu je tendence redukovat explicitní deklaraci typů. Logicky nikdo se nechce párat s psaním zbytečného kódu, ale chce vyzobat rozinky přísné a včasné typové kontroly. V běžných jazycích (OO i funkcionálních) se většina typů odvozuje (dedukuje). V kombinaci s rozhraními se použití dobře navržené knihovny obejde bez explicitních deklarací typů. V takovém C++ můžu mít téměř všude auto, včetně deklarací funkcí.
Tím, že jsem nucen používat explicitní typování tam, kde bych přetypovávat nemusel. Nemohu jednou funkcí sčítat int, float a spojovat stringy. Musím mít tři funkce.
Také si potřebné typy musím nadefinovat, jinak deklarace funkcí vypadají takhle:
circumference :: Float -> Float
circumference r = 2 * pi * r
Doporučuju přečíst si to ještě jednou a zamyslet se. Implicitní type cast obchází explicitní typování. Neboli prodloužení kódu se nekoná.
-
Jenže zatímco takový Lisp nebo Smalltalk jsou směšně jednoduché
Možná proto ono tvrzení, že každý reálně použitelný jazyk konverguje k Lispu :)
-
Je poučné podívat se, jak zachází C++ nebo Swift s callbacky. Můžu mít třeba
let request = ...
request.perform { response, error in ... }
Tedy vše bez explicitního uvádění typů a zároveň s plnou kontrolou v době překladu. V podstatě to vypadá jako v dynamicky typovaném jazyce. V C++ to dotáhli ještě dál. Prostě vzhled/zápis kódu ani v nejmenším nevypovídá nic o charakteru jazyka vzhledem k jeho typovému systému.
-
Tím, že jsem nucen používat explicitní typování tam, kde bych přetypovávat nemusel. Nemohu jednou funkcí sčítat int, float a spojovat stringy. Musím mít tři funkce.
Doporučuju přečíst si to ještě jednou a zamyslet se. Implicitní type cast obchází explicitní typování. Neboli prodloužení kódu se nekoná.
Jenže s implicitním typováním si vystačím jen u primitivních funkcí. Jakmile budu vytvářet cokoli složitějšího, musím si nadefinovat vlastní typy.
-
Jenže zatímco takový Lisp nebo Smalltalk jsou směšně jednoduché
Možná proto ono tvrzení, že každý reálně použitelný jazyk konverguje k Lispu :)
Otázkou tedy je, proč místo Lispu používáme náhražky :)
-
To rozhodně ne, jak implicitní type cast prodlouží kód?
Tohle zrovna není dobrý příklad silného typového systému, spíš ojebávky (nehledě na to, že je to obecně problematický mechanismus). Zkuste jiný příklad zvýšení znovupoužitelnosti posílením typového systému, ať se tu nemusíme hádat.
Je třeba mít na paměti, že v jazycích s kontrolou typů v době překladu je tendence redukovat explicitní deklaraci typů. Logicky nikdo se nechce párat s psaním zbytečného kódu, ale chce vyzobat rozinky přísné a včasné typové kontroly. V běžných jazycích (OO i funkcionálních) se většina typů odvozuje (dedukuje). V kombinaci s rozhraními se použití dobře navržené knihovny obejde bez explicitních deklarací typů. V takovém C++ můžu mít téměř všude auto, včetně deklarací funkcí.
Jestli máte na mysli psaní "var" např. v Jávce, tak to je triviální dovození typu, kdy není pochyby. V jazycích OO (skutečných, ne imperativních hybridech) je komunikace místo voláním funkcí řešeno posíláním zpráv obsahujících selektor metody, takže typový systém by tu k ničemu nebyl, není co odvozovat!
-
Smalltalk ale typy má.
Nemá. Jestli s tím máte problém, zkuste si představit javascriptové objekty ad-hoc.
-
Jenže zatímco takový Lisp nebo Smalltalk jsou směšně jednoduché
Možná proto ono tvrzení, že každý reálně použitelný jazyk konverguje k Lispu :)
Otázkou tedy je, proč místo Lispu používáme náhražky :)
Alergie na závorky? ;)
-
Tím, že jsem nucen používat explicitní typování tam, kde bych přetypovávat nemusel. Nemohu jednou funkcí sčítat int, float a spojovat stringy. Musím mít tři funkce.
Doporučuju přečíst si to ještě jednou a zamyslet se. Implicitní type cast obchází explicitní typování. Neboli prodloužení kódu se nekoná.
Jenže s implicitním typováním si vystačím jen u primitivních funkcí. Jakmile budu vytvářet cokoli složitějšího, musím si nadefinovat vlastní typy.
To je právě omyl. Z nějakého nepochopitelného důvodu evidentně rozšířený.
-
Možná jde jen o slovíčkaření. Už tu byl uveden příklad Swiftu. Ve verzi 4.2 se silnějším typovým systémem se z stdlib smazalo hodně duplicitního kódu (specializací generik), který byl nahrazen jednou implementací pro mnoho typů (se společným protokolem). Obecnějšími se ty typy ovšem nestaly.
Supr. Tak teď ještě vykopejte ty "generika" (tj. zobecněný typovací systém) a ponechejte to netypové, a bude to (logicky) maximálně stejně velké, možná taky poloviční.
-
Zkuste jiný příklad zvýšení znovupoužitelnosti posílením typového systému, ať se tu nemusíme hádat.
Už nejméně dvakrát jsem ho uváděl: podmíněná konformance. Vlastně třikrát. Stačí letmo mrknout na Swift.
-
Jenže zatímco takový Lisp nebo Smalltalk jsou směšně jednoduché
Možná proto ono tvrzení, že každý reálně použitelný jazyk konverguje k Lispu :)
Otázkou tedy je, proč místo Lispu používáme náhražky :)
časy se mění, lisp vznikl ve stejné době jako projekt použití jaderných zbraní na stavební práce
-
Pozor, další myšlenka:
Opačně: Neobsahuje v sobě každý test z podstaty "typovou" kontrolu? Neboli vkládám-li na vstup diskrétní hodnoty a testuju-li výstupní diskrétní hodnoty (přísnější podmínka), netestuju zároveň i kategorii těch hodnot (volnější podmínka)?
furt je ten test jenom pro jednu volbu typů argumentů, u dynamického jazyka je možných voleb spousta
To je právě ten problém - testování kategorií hodnot ještě neznamená správnost kombinací jejich hodnot.
Takže se shodneme, že oba systémy jsou (to se ale dalo čekat) neúplné.
-
Možná proto ono tvrzení, že každý reálně použitelný jazyk konverguje k Lispu :)
Opět nepodložené tvrzení. Doložte to.
-
Unit testy jsem nikdy neřešil, vždy si vše testuji sám vlastním systémem, že si vytvořím testovací třídu, která testuje veškeré elementární objekty (třídy, funkce), kdy ověřuji, zda na zadaný vstup leze zadaný výstup. Systém téměř debuggovat nemusím a pokud systém vykazuje chybu, vím hned, kde konkrétně je.
-
Pozor, další myšlenka:
Opačně: Neobsahuje v sobě každý test z podstaty "typovou" kontrolu? Neboli vkládám-li na vstup diskrétní hodnoty a testuju-li výstupní diskrétní hodnoty (přísnější podmínka), netestuju zároveň i kategorii těch hodnot (volnější podmínka)?
furt je ten test jenom pro jednu volbu typů argumentů, u dynamického jazyka je možných voleb spousta
To je právě ten problém - testování kategorií hodnot ještě neznamená správnost kombinací jejich hodnot.
Takže se shodneme, že oba systémy jsou (to se ale dalo čekat) neúplné.
asi nevím co je "kategorie hodnot"
se statickým typovým systémem můžete u některých funkcí dosáhnout vyčerpávajícího testování, u dynamického asi nikdy
-
testování kategorií hodnot
asi nevím co je "kategorie hodnot"
[/quote]
chytil jsem se do pasti?
-
Diskuse se poněkud odklonila od původního tématu. Jako obvykle "type haters" nekriticky prosazují "čisté OOP". Přitom flexibilní (smalltalkovské) posílání zpráv a mocný typový systém s kontrolou v době překladu se ani v nejmenším nevylučují. Malý kvíz: který "čistě OO" jazyk má generika, varianci typů (to nemá ani C++ nebo Swift) a typovou kontrolu při překladu?
-
Pozor, další myšlenka:
Opačně: Neobsahuje v sobě každý test z podstaty "typovou" kontrolu? Neboli vkládám-li na vstup diskrétní hodnoty a testuju-li výstupní diskrétní hodnoty (přísnější podmínka), netestuju zároveň i kategorii těch hodnot (volnější podmínka)?
furt je ten test jenom pro jednu volbu typů argumentů, u dynamického jazyka je možných voleb spousta
To je právě ten problém - testování kategorií hodnot ještě neznamená správnost kombinací jejich hodnot.
Takže se shodneme, že oba systémy jsou (to se ale dalo čekat) neúplné.
asi nevím co je "kategorie hodnot"
Kategorie je taková ta blbost s morfismama a funktorama a dalšíma fuj věcma :)
-
Už nejméně dvakrát jsem ho uváděl: podmíněná konformance. Vlastně třikrát. Stačí letmo mrknout na Swift.
Tohle https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md (https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md) je ono? Dopracováváme se zpět k myšlence, že dokonalý typový systém možná existuje, ale určitě je složitý jak prase? Tak to soráč květináč, ale to si radši nechám ten netypovaný systém s jednotkovými testy.
-
Diskuse se poněkud odklonila od původního tématu. Jako obvykle "type haters" nekriticky prosazují "čisté OOP". Přitom flexibilní (smalltalkovské) posílání zpráv a mocný typový systém s kontrolou v době překladu se ani v nejmenším nevylučují. Malý kvíz: který "čistě OO" jazyk má generika, varianci typů (to nemá ani C++ nebo Swift) a typovou kontrolu při překladu?
Který "čistě OO" jazyk potřebuje generika, varianci typů a typovou kontrolu při překladu?
-
Unit testy jsem nikdy neřešil, vždy si vše testuji sám vlastním systémem, že si vytvořím testovací třídu, která testuje veškeré elementární objekty (třídy, funkce), kdy ověřuji, zda na zadaný vstup leze zadaný výstup. Systém téměř debuggovat nemusím a pokud systém vykazuje chybu, vím hned, kde konkrétně je.
Supr! A teď si zkuste tipnout, jak se tomu, co jste vytvořil, říká.
-
asi nevím co je "kategorie hodnot"
se statickým typovým systémem můžete u některých funkcí dosáhnout vyčerpávajícího testování, u dynamického asi nikdy
To je jiný název pro typy.
To se tu právě řeší.
-
Už nejméně dvakrát jsem ho uváděl: podmíněná konformance. Vlastně třikrát. Stačí letmo mrknout na Swift.
Tohle https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md (https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md) je ono? Dopracováváme se zpět k myšlence, že dokonalý typový systém možná existuje, ale určitě je složitý jak prase?
Co je na tom složitého? Naopak když budu psát nějakou generickou kolekci, tak si ušetřím psaní kódu. DRY se tomu říká. Jestli pro někoho psaní méně kódu znamená vyšší složitost, tak asi nemá cenu dál diskutovat, jedem das seine.
-
Už nejméně dvakrát jsem ho uváděl: podmíněná konformance. Vlastně třikrát. Stačí letmo mrknout na Swift.
Tohle https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md (https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md) je ono? Dopracováváme se zpět k myšlence, že dokonalý typový systém možná existuje, ale určitě je složitý jak prase? Tak to soráč květináč, ale to si radši nechám ten netypovaný systém s jednotkovými testy.
co je na tom tak složitého?
-
Už nejméně dvakrát jsem ho uváděl: podmíněná konformance. Vlastně třikrát. Stačí letmo mrknout na Swift.
Tohle https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md (https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md) je ono? Dopracováváme se zpět k myšlence, že dokonalý typový systém možná existuje, ale určitě je složitý jak prase? Tak to soráč květináč, ale to si radši nechám ten netypovaný systém s jednotkovými testy.
co je na tom tak složitého?
Asi je pro někoho obtížné to pochopit. Což nechápu proč, ale i mimo IT někteří preferují dělat věci složitě, i když to jde jednoduše a s menší námahou. Holt svět není dokonalý.
-
Asi je pro někoho obtížné to pochopit. Což nechápu proč, ale i mimo IT někteří preferují dělat věci složitě, i když to jde jednoduše a s menší námahou. Holt svět není dokonalý.
Přesně! Přesně to samé si myslím o vás.
-
Malý kvíz: který "čistě OO" jazyk má generika, varianci typů (to nemá ani C++ nebo Swift) a typovou kontrolu při překladu?
Nenapínejte nás.
-
Asi je pro někoho obtížné to pochopit. Což nechápu proč, ale i mimo IT někteří preferují dělat věci složitě, i když to jde jednoduše a s menší námahou. Holt svět není dokonalý.
Přesně! Přesně to samé si myslím o vás.
tohle je zajímavý moment
-
Unit testy jsem nikdy neřešil, vždy si vše testuji sám vlastním systémem, že si vytvořím testovací třídu, která testuje veškeré elementární objekty (třídy, funkce), kdy ověřuji, zda na zadaný vstup leze zadaný výstup. Systém téměř debuggovat nemusím a pokud systém vykazuje chybu, vím hned, kde konkrétně je.
Supr! A teď si zkuste tipnout, jak se tomu, co jste vytvořil, říká.
Komparační test elementárních funkcí. Nebo také elementární test.
-
Asi je pro někoho obtížné to pochopit. Což nechápu proč, ale i mimo IT někteří preferují dělat věci složitě, i když to jde jednoduše a s menší námahou. Holt svět není dokonalý.
Přesně! Přesně to samé si myslím o vás.
tohle je zajímavý moment
Ano, konečně i v tomto vlákně došlo na ad hominem :)
-
Asi je pro někoho obtížné to pochopit. Což nechápu proč, ale i mimo IT někteří preferují dělat věci složitě, i když to jde jednoduše a s menší námahou. Holt svět není dokonalý.
Přesně! Přesně to samé si myslím o vás.
tohle je zajímavý moment
Ano, konečně i v tomto vlákně došlo na ad hominem :)
je dobře, že si svůj prohřešek uvědomujete, teď zpět k věcné debatě :)
-
Asi je pro někoho obtížné to pochopit. Což nechápu proč, ale i mimo IT někteří preferují dělat věci složitě, i když to jde jednoduše a s menší námahou. Holt svět není dokonalý.
Přesně! Přesně to samé si myslím o vás.
tohle je zajímavý moment
Ano, konečně i v tomto vlákně došlo na ad hominem :)
teď zpět k věcné debatě :)
Ano, teď se čeká, až SB a Kit dodají důkazy svých tvrzení. Trochu to začíná připomínat debatu Čada vs. Virius, kde prvně jmenovaný přestal se snahou dokládat svá uhozená tvrzení.
-
Ano, teď se čeká, až SB a Kit dodají důkazy svých tvrzení. Trochu to začíná připomínat debatu Čada vs. Virius, kde prvně jmenovaný přestal se snahou dokládat svá uhozená tvrzení.
Které z mých tvrzení potřebuješ doložit?
-
Nechci spekulovat, ale jednoduchá úvaha, že když netypový systém otypuju, tj. omezím jej, dosáhnu tak větší znovupoužitelnosti, neboli obecnosti, mi nedává smysl.
Pokud otypuju netypový jazyk (třeba ve stylu TypeScript), tak ne. Zajímavé to začne být, jakmile je schopen překladač na základě těch typů něco rozhodovat. Zářným případem je právě polymorfismus na základě návratové hodnoty. To prostě nejde s "vtable"-like jazyky rozumně udělat, přitom pokud má překladač k dispozici informace o typech, tak je pro něj celkem jednoduché vybrat tu "správnou" funkci (nebo i konstantu).
Ona teda i ta typová kontrola vede k vyšší jednoduchosti kódu, protože prostě nemusím spoustu věcí kontrolovat - a vím, že je nemusím kontrolovat a nic se nestane (překladač to garantuje). Ono stačí se podívat na to jak fungují Promisy v JS a zkusit si představit, že by podobný protokol měl být naprosto běžný pro spoustu jiných situací.
-
Ano, teď se čeká, až SB a Kit dodají důkazy svých tvrzení. Trochu to začíná připomínat debatu Čada vs. Virius, kde prvně jmenovaný přestal se snahou dokládat svá uhozená tvrzení.
Které z mých tvrzení potřebuješ doložit?
Třeba toto: "Jenže s implicitním typováním si vystačím jen u primitivních funkcí. Jakmile budu vytvářet cokoli složitějšího, musím si nadefinovat vlastní typy." Ani ne doložit, spíš objasnit. Implicitní typování nevylučuje vlastní typy, takže můžeme zůstat u první věty.
-
Implicitní typování
co to vlastně je? implicitní přetypování? jako "implicit type cast"/"implicit type conversion"?
-
Které z mých tvrzení potřebuješ doložit?
Třeba toto: "Jenže s implicitním typováním si vystačím jen u primitivních funkcí. Jakmile budu vytvářet cokoli složitějšího, musím si nadefinovat vlastní typy." Ani ne doložit, spíš objasnit. Implicitní typování nevylučuje vlastní typy, takže můžeme zůstat u první věty.
Měl jsem za to, že signatury funkcí jsou například v Haskellu povinné nebo přinejmenším doporučené.
-
Jinak čistě pragmaticky - v případě Swiftu proběhla diskuse, jestli podporovat HKT, protože "jsou moc složité a málokdo jim rozumí" (což je určitě pravda). Úplně stejnou věc debatovali tvůrci Rustu ("skoro nikdo to není schopen pochopit, takže se to nebude používat"). Haskellisti si tuto otázku nějak moc nekladli, pročež má teď Haskell nálepku esoterického a akademického jazyka, protože naučit se jej nad rámec povrchního seznámení se syntaxí zvládne jen zlomek lidí, co se považují za programátory (i když určitě by to dalo 100% teoretických fyziků například). V tomto vlákně se opět manifestuje staré známé "nejsem-li něco schopen pochopit, je to k ničemu". Aneb na co používat bagr, když mám lopatu...
-
Které z mých tvrzení potřebuješ doložit?
Třeba toto: "Jenže s implicitním typováním si vystačím jen u primitivních funkcí. Jakmile budu vytvářet cokoli složitějšího, musím si nadefinovat vlastní typy." Ani ne doložit, spíš objasnit. Implicitní typování nevylučuje vlastní typy, takže můžeme zůstat u první věty.
Měl jsem za to, že signatury funkcí jsou například v Haskellu povinné nebo přinejmenším doporučené.
nejsou povinné
-
Implicitní typování
co to vlastně je? implicitní přetypování? jako "implicit type cast"/"implicit type conversion"?
Ne, jde o deklarace. Nezná-li někdo definici, Google napoví ("implicit typing").
-
Ano, teď se čeká, až SB a Kit dodají důkazy svých tvrzení...
Které tvrzení potřebujete dokázat ode mě?
-
Měl jsem za to, že signatury funkcí jsou například v Haskellu povinné nebo přinejmenším doporučené.
povinné nejsou, jsou nutné u některých zvláštních případů (co vím tak teba pattern matching na některých GADTs) a silně se doporučují u funkcí exportovaných z modulu
-
Implicitní typování
co to vlastně je? implicitní přetypování? jako "implicit type cast"/"implicit type conversion"?
Ne, jde o deklarace. Nezná-li někdo definici, Google napoví ("implicit typing").
děkuji
-
Implicitní typování
co to vlastně je? implicitní přetypování? jako "implicit type cast"/"implicit type conversion"?
Ne, jde o deklarace. Nezná-li někdo definici, Google napoví ("implicit typing").
děkuji
Není samozřejmě zač. Jinak implicitní přetypování (nebo jen typová aserce) se toho také výslovně týká. Nicméně pořád zůstává, že dynamické typování a kontrola typů při překladu se nijak nevylučují. Na druhou stranu je-li k dispozici ta aserce, nepotřebuju "čistý" OO runtime, protože obecně čím pozdnější vazba, tím hůře (krom oprávněných případů pochopitelně, těch je ale jak šafránu). Někdy mám pocit, že lidi zkazilo C++ a dorazila to Java.
-
Měl jsem za to, že signatury funkcí jsou například v Haskellu povinné nebo přinejmenším doporučené.
silně se doporučují u funkcí exportovaných z modulu
To mi přijde jako samozřejmé, protože jsou součástí dokumentace. Ale možná jsem jen v tomto ohledu naivní a programátoři nad sebou potřebují bič 24/7...
-
Ano, teď se čeká, až SB a Kit dodají důkazy svých tvrzení...
Které tvrzení potřebujete dokázat ode mě?
Radši nic.
-
Jinak čistě pragmaticky - v případě Swiftu proběhla diskuse, jestli podporovat HKT, protože "jsou moc složité a málokdo jim rozumí" (což je určitě pravda). Úplně stejnou věc debatovali tvůrci Rustu ("skoro nikdo to není schopen pochopit, takže se to nebude používat"). Haskellisti si tuto otázku nějak moc nekladli, pročež má teď Haskell nálepku esoterického a akademického jazyka, protože naučit se jej nad rámec povrchního seznámení se syntaxí zvládne jen zlomek lidí, co se považují za programátory (i když určitě by to dalo 100% teoretických fyziků například). V tomto vlákně se opět manifestuje staré známé "nejsem-li něco schopen pochopit, je to k ničemu". Aneb na co používat bagr, když mám lopatu...
No tak nemusím být ani nijak zvlášť inteligentní. Tak tomu prostě dám pár hodin navíc no.
Pamatuju si, jak jsem kolegovi vysvětloval, proč je jako docela fajn v konstruktoru testovat vstupní hodnoty; že jinak to balit do třídy nemá smysl. Strašně se kroutil. Je docela chytrý, ale celou svou inteligenci vyčerpal na to, aby mi dokázalmě uhádal, že to tak není.
-
Jinak čistě pragmaticky - v případě Swiftu proběhla diskuse, jestli podporovat HKT, protože "jsou moc složité a málokdo jim rozumí" (což je určitě pravda). Úplně stejnou věc debatovali tvůrci Rustu ("skoro nikdo to není schopen pochopit, takže se to nebude používat"). Haskellisti si tuto otázku nějak moc nekladli, pročež má teď Haskell nálepku esoterického a akademického jazyka, protože naučit se jej nad rámec povrchního seznámení se syntaxí zvládne jen zlomek lidí, co se považují za programátory (i když určitě by to dalo 100% teoretických fyziků například). V tomto vlákně se opět manifestuje staré známé "nejsem-li něco schopen pochopit, je to k ničemu". Aneb na co používat bagr, když mám lopatu...
No tak nemusím být ani nijak zvlášť inteligentní. Tak tomu prostě dám pár hodin navíc no.
Jen jsem volně citoval, nicméně asi skutečně existují lidé, co nechápou třeba jen funkce vyššího řádu. A i ti píšou komerční kód.
-
[...]
P.S. Jinak to není jen v IT, divil byste se, jak málo lidí je schopno pochopit například podvojné účetnictví.
-
Jen jsem volně citoval, nicméně asi skutečně existují lidé, co nechápou třeba jen funkce vyššího řádu. A i ti píšou komerční kód.
Tak to nechápou no. Tak přijde senior, řekne jim - to je tak a tak, voni na to - hmm, pomaleji... Zkusí to na malém příkladu, vyzkouší na části projektu, po pěti aplikacích (toho konceptu) budou tvrdit, že to znali vždycky.
Chci říct, samozřejmě souhlasím. Největší problém je ignorace. Ignorace na straně neznalých, že to je blbost, a ignorace na straně znalých, že není třeba to polopatě vysvětlit.
-
V tomto vlákně se opět manifestuje staré známé "nejsem-li něco schopen pochopit, je to k ničemu". Aneb na co používat bagr, když mám lopatu...
Přitom to celé začalo starým známým „nejsem schopen to pochopit, ale zrovna bych potřeboval bagrovat, tak to určitě je bagr“. Jen nevím, co je horší…
-
Tak to nechápou no. Tak přijde senior, řekne jim - to je tak a tak, voni na to - hmm, pomaleji... Zkusí to na malém příkladu, vyzkouší na části projektu, po pěti aplikacích (toho konceptu) budou tvrdit, že to znali vždycky.
Chci říct, samozřejmě souhlasím. Největší problém je ignorace. Ignorace na straně neznalých, že to je blbost, a ignorace na straně znalých, že není třeba to polopatě vysvětlit.
Obávám se, že ještě horší je, když někdo jenom zahlédne nějaký kousíček, a už má pocit, že to chápe. To je pak ten neznalý, který si ale navíc nenechá vysvětlit, že je neznalý.
-
Největší problém je ignorace. Ignorace na straně neznalých, že to je blbost, a ignorace na straně znalých, že není třeba to polopatě vysvětlit.
+1
empatie by mohla pomoct, třeba tady SB, banda rádobychytrých pseudomatematiků se mu snaží nacpat, že nějaké conditional conformance burrito je lepší než to prostě napsat v pythonu
-
Obávám se, že ještě horší je, když někdo jenom zahlédne nějaký kousíček, a už má pocit, že to chápe. To je pak ten neznalý, který si ale navíc nenechá vysvětlit, že je neznalý.
Tak ona je taková dobrá zásada, když člověk něco zjišťuje, tak vyfiltrovat zdroje/lidi, které evidentně nejsou k užitku.
-
empatie by mohla pomoct, třeba tady SB, banda rádobychytrých pseudomatematiků se mu snaží nacpat, že nějaké conditional conformance burrito je lepší než to prostě napsat v pythonu
Mou jedinou otázkou (odpovídající původnímu dotazu), na kterou mě zajímala odpověď, bylo, zda se mi vyplatí budovat typové systémy, nebo mě vyjde jednodušeji a pružněji celý tento aparát odbourat a nechat to na oněch testech (kterým se možná stejně nevyhnu). Nechci se kvůli tomu hádat, každý si stejně vybere to svoje.
-
empatie by mohla pomoct, třeba tady SB, banda rádobychytrých pseudomatematiků se mu snaží nacpat, že nějaké conditional conformance burrito je lepší než to prostě napsat v pythonu
Mou jedinou otázkou (odpovídající původnímu dotazu), na kterou mě zajímala odpověď, bylo, zda se mi vyplatí budovat typové systémy, nebo mě vyjde jednodušeji a pružněji celý tento aparát odbourat a nechat to na oněch testech (kterým se možná stejně nevyhnu). Nechci se kvůli tomu hádat, každý si stejně vybere to svoje.
Šel jsem oběma cestama. A musím říct, že napsat aplikaci, kde spolehlivost bude stát jen na testech je peklo.
Psát aplikaci v Haskellu, kde mi vše drží typy mi přišla pohodlnější. Ale zase to jde ztuha, a ty IO monády - no člověk si musí hodně zvykat.
Za mě je ideální kompromis: co nejvíc typů, a teprve když to nejde tak pomoct testy.
A úplně největší peklo je Java.
-
Jen jsem volně citoval, nicméně asi skutečně existují lidé, co nechápou třeba jen funkce vyššího řádu. A i ti píšou komerční kód.
Tak to nechápou no. Tak přijde senior, řekne jim - to je tak a tak, voni na to - hmm, pomaleji... Zkusí to na malém příkladu, vyzkouší na části projektu, po pěti aplikacích (toho konceptu) budou tvrdit, že to znali vždycky.
Chci říct, samozřejmě souhlasím. Největší problém je ignorace. Ignorace na straně neznalých, že to je blbost, a ignorace na straně znalých, že není třeba to polopatě vysvětlit.
Ano, ale každý má limit chápání někde jinde. Polopatě se nedá vysvětlit vše, taková kvantová chromodynamika nebo obecná teorie relativity mají hodně vysoké předpoklady.
-
empatie by mohla pomoct, třeba tady SB, banda rádobychytrých pseudomatematiků se mu snaží nacpat, že nějaké conditional conformance burrito je lepší než to prostě napsat v pythonu
Mou jedinou otázkou (odpovídající původnímu dotazu), na kterou mě zajímala odpověď, bylo, zda se mi vyplatí budovat typové systémy, nebo mě vyjde jednodušeji a pružněji celý tento aparát odbourat a nechat to na oněch testech (kterým se možná stejně nevyhnu). Nechci se kvůli tomu hádat, každý si stejně vybere to svoje.
Za mě je ideální kompromis: co nejvíc typů, a teprve když to nejde tak pomoct testy.
K tomuto poznatku jednou dospěje každý. Pokud teda dříve neumře...
-
A úplně největší peklo je Java.
Někomu třeba peklo vyhovuje.
-
Pamatuju si, jak jsem kolegovi vysvětloval, proč je jako docela fajn v konstruktoru testovat vstupní hodnoty; že jinak to balit do třídy nemá smysl. Strašně se kroutil. Je docela chytrý, ale celou svou inteligenci vyčerpal na to, aby mi dokázalmě uhádal, že to tak není.
Jak kdy. Pokud potřebuji pozdní vazbu, tak nevím, co bych v tom konstruktoru testoval.
-
Mou jedinou otázkou (odpovídající původnímu dotazu), na kterou mě zajímala odpověď, bylo, zda se mi vyplatí budovat typové systémy, nebo mě vyjde jednodušeji a pružněji celý tento aparát odbourat a nechat to na oněch testech (kterým se možná stejně nevyhnu). Nechci se kvůli tomu hádat, každý si stejně vybere to svoje.
za sebe tvrdím, že se to vyplatí a určitě je jednodušší to odbourat a nechat to na testech, přínos se IMHO liší
na typy se dá dívat jako na další testovací nástroj (s každým nástrojem se musí člověk naučit), překladač něco ověří, typy výrazně omezí množinu vstupů (a tím testů) a pak jsou tu QuickCheck-y...
a tak dále
-
Největší problém je ignorace.
Někdy i absence ignorace, diskuse by byla přínosnější, kdyby ji ignoroval místní Gang of IQ 4. Ale zrovna toto vlákno bylo místy hodně zajímavé.
-
Pamatuju si, jak jsem kolegovi vysvětloval, proč je jako docela fajn v konstruktoru testovat vstupní hodnoty; že jinak to balit do třídy nemá smysl. Strašně se kroutil. Je docela chytrý, ale celou svou inteligenci vyčerpal na to, aby mi dokázalmě uhádal, že to tak není.
Jak kdy. Pokud potřebuji pozdní vazbu, tak nevím, co bych v tom konstruktoru testoval.
Nějak to pleteš. Míchat konstruktory a pozdní vazbu chce hodně divokou představivost.
-
Pamatuju si, jak jsem kolegovi vysvětloval, proč je jako docela fajn v konstruktoru testovat vstupní hodnoty; že jinak to balit do třídy nemá smysl. Strašně se kroutil. Je docela chytrý, ale celou svou inteligenci vyčerpal na to, aby mi dokázalmě uhádal, že to tak není.
Jak kdy. Pokud potřebuji pozdní vazbu, tak nevím, co bych v tom konstruktoru testoval.
Nějak to pleteš. Míchat konstruktory a pozdní vazbu chce hodně divokou představivost.
Ve chvíli, kdy vytvořím objekt, ještě nevím, které metody budu volat a které atributy mám validovat. Validuje se až při zavolání konkrétní metody.
-
Pamatuju si, jak jsem kolegovi vysvětloval, proč je jako docela fajn v konstruktoru testovat vstupní hodnoty; že jinak to balit do třídy nemá smysl. Strašně se kroutil. Je docela chytrý, ale celou svou inteligenci vyčerpal na to, aby mi dokázalmě uhádal, že to tak není.
Jak kdy. Pokud potřebuji pozdní vazbu, tak nevím, co bych v tom konstruktoru testoval.
Nějak to pleteš. Míchat konstruktory a pozdní vazbu chce hodně divokou představivost.
Ve chvíli, kdy vytvořím objekt, ještě nevím, které metody budu volat a které atributy mám validovat. Validuje se až při zavolání konkrétní metody.
Aha. Takže když vytvořím instanci třídy Person s věkem -50, tak ti to je jedno, protože na zavolání metody “chcípni” (pure OO ekšperti by řekli poslání zprávy “chcípni”) to nemá vliv? Co zásada “fail early”? To “early” taky může znamenat před pádem letadla nebo výbuchem elektrárny.
-
takové fajne vlákno to bylo :(
-
Ve chvíli, kdy vytvořím objekt, ještě nevím, které metody budu volat a které atributy mám validovat. Validuje se až při zavolání konkrétní metody.
Aha. Takže když vytvořím instanci třídy Person s věkem -50, tak ti to je jedno, protože na zavolání metody “chcípni” (pure OO ekšperti by řekli poslání zprávy “chcípni”) to nemá vliv? Co zásada “fail early”? To “early” taky může znamenat před pádem letadla nebo výbuchem elektrárny.
Co když ten věk vůbec nebudu potřebovat a v konstruktoru není uveden? Proč bych ho měl validovat?
"fail early" je cestou do pekel, protože narušuje atomicitu operací. Co když mezi validací a použitím hodnoty mi ji nějaké jiné vlákno změní? Výjimky pro tento účel poslouží mnohem lépe.
-
Jak kdy. Pokud potřebuji pozdní vazbu, tak nevím, co bych v tom konstruktoru testoval.
Hele, založ si vlastní vlákno!
-
Šel jsem oběma cestama. A musím říct, že napsat aplikaci, kde spolehlivost bude stát jen na testech je peklo.
Nějak mne nenapadá, v čem by se měla lišit dovednost psát testy od dovednosti programovat.
Častým projevem toho nechápání bývá paušální odsuzování – a je jedno, zda PHP, JavaScriptu, Javy nebo C.
-
Aha. Takže když vytvořím instanci třídy Person s věkem -50, tak ti to je jedno, protože...
Ono hodně dělají zvyky z těch statických typu. Pro nás už jen představa existence nevalidního objektu je neprijatelná.
V případě netypovych jazyku kde to může kdykoliv kdekoliv chcipnout - to tolik neprozivaji.
-
Aha. Takže když vytvořím instanci třídy Person s věkem -50, tak ti to je jedno, protože...
Ono hodně dělají zvyky z těch statických typu. Pro nás už jen představa existence nevalidního objektu je neprijatelná.
V případě netypovych jazyku kde to může kdykoliv kdekoliv chcipnout - to tolik neprozivaji.
To už je o zvyku a disciplíně bez ohledu na jazyk. Prasit jde i v Haskellu.
-
Častým projevem toho nechápání bývá paušální odsuzování – a je jedno, zda PHP, JavaScriptu, Javy nebo C.
vyloučil jste možnost, že ten nechápající jste vy?
-
Častým projevem toho nechápání bývá paušální odsuzování – a je jedno, zda PHP, JavaScriptu, Javy nebo C.
vyloučil jste možnost, že ten nechápající jste vy?
Jistě, Haskell tady přece nikdo neodsuzuje. Není lepší ani horší než ostatní jazyky, je prostě jiný.
-
Aha. Takže když vytvořím instanci třídy Person s věkem -50, tak ti to je jedno, protože...
Ono hodně dělají zvyky z těch statických typu. Pro nás už jen představa existence nevalidního objektu je neprijatelná.
V případě netypovych jazyku kde to může kdykoliv kdekoliv chcipnout - to tolik neprozivaji.
To už je o zvyku a disciplíně bez ohledu na jazyk.
Před seznámením se z Haskellem jsem to psal proto, protože je to tak správně. Po seznámení s Haskellem jsem začal chápat proč.
Prasit jde i v Haskellu.
To mě zajímá. Ne, to, zda to jde, ale nějakou pěknou ukázku prasení v Haskellu.
-
Aha. Takže když vytvořím instanci třídy Person s věkem -50, tak ti to je jedno, protože...
Ono hodně dělají zvyky z těch statických typu. Pro nás už jen představa existence nevalidního objektu je neprijatelná.
V případě netypovych jazyku kde to může kdykoliv kdekoliv chcipnout - to tolik neprozivaji.
To už je o zvyku a disciplíně bez ohledu na jazyk.
Před seznámením se z Haskellem jsem to psal proto, protože je to tak správně. Po seznámení s Haskellem jsem začal chápat proč.
Je fakt škoda, že se Haskell neučí do hloubky na našich VŠ.
-
To mě zajímá. Ne, to, zda to jde, ale nějakou pěknou ukázku prasení v Haskellu.
Nic konkrétního po ruce nemám, prasečiny si neschovávám, ale většinou jde o stupidní použití do notace. Ono vůbec nejhorší jsou lidi, co si myslí, že umí Haskell, a pak v něm něco píšou nebo ho nedejbože vysvětlují jiným. Operátor <- je pro ně přiřazení (haha) a kód píší v podstatě procedurálně.
-
Pro inspiraci: https://medium.com/@pereroigcat/functional-algorithmics-2-type-operators-and-higher-kinds-a594cd9cb01
-
Častým projevem toho nechápání bývá paušální odsuzování – a je jedno, zda PHP, JavaScriptu, Javy nebo C.
vyloučil jste možnost, že ten nechápající jste vy?
Je to Jirsák. Co bys čekal.
-
Častým projevem toho nechápání bývá paušální odsuzování – a je jedno, zda PHP, JavaScriptu, Javy nebo C.
vyloučil jste možnost, že ten nechápající jste vy?
Jistě, Haskell tady přece nikdo neodsuzuje. Není lepší ani horší než ostatní jazyky, je prostě jiný.
Totéž se dá říct o whitespacu....
-
Častým projevem toho nechápání bývá paušální odsuzování – a je jedno, zda PHP, JavaScriptu, Javy nebo C.
vyloučil jste možnost, že ten nechápající jste vy?
Jistě, Haskell tady přece nikdo neodsuzuje. Není lepší ani horší než ostatní jazyky, je prostě jiný.
Totéž se dá říct o whitespacu....
No říct se to sice dá, ale dost pochybuju že by to Kit opravdu řekl. Je to totiž úplná kravina. Dokonce bych řekl, že pojmem "jazyky" myslel automaticky "neezoterické jazyky".
-
Jistě, Haskell tady přece nikdo neodsuzuje. Není lepší ani horší než ostatní jazyky, je prostě jiný.
Totéž se dá říct o whitespacu....
No říct se to sice dá, ale dost pochybuju že by to Kit opravdu řekl. Je to totiž úplná kravina. Dokonce bych řekl, že pojmem "jazyky" myslel automaticky "neezoterické jazyky".
Přesně. Kdysi jsem si napsal vlastní jazyk, který jsem používal komerčně. Byl sice Turing complete, ale přesto bych ho s běžně používanými jazyky nesrovnával.
-
Jistě, Haskell tady přece nikdo neodsuzuje. Není lepší ani horší než ostatní jazyky, je prostě jiný.
Totéž se dá říct o whitespacu....
No říct se to sice dá, ale dost pochybuju že by to Kit opravdu řekl. Je to totiž úplná kravina. Dokonce bych řekl, že pojmem "jazyky" myslel automaticky "neezoterické jazyky".
Přesně. Kdysi jsem si napsal vlastní jazyk, který jsem používal komerčně.
No to měli asi zákazníci radost.
-
Přesně. Kdysi jsem si napsal vlastní jazyk, který jsem používal komerčně.
No to měli asi zákazníci radost.
Fungoval perfektně a hlavně mi urychlil vývoj aplikací.
-
Přesně. Kdysi jsem si napsal vlastní jazyk, který jsem používal komerčně.
No to měli asi zákazníci radost.
Fungoval perfektně a hlavně mi urychlil vývoj aplikací.
A co vendor lock-in?
-
Přesně. Kdysi jsem si napsal vlastní jazyk, který jsem používal komerčně.
No to měli asi zákazníci radost.
Fungoval perfektně a hlavně mi urychlil vývoj aplikací.
A co vendor lock-in?
Vendor lock-in tam nebyl, bylo to otevřené. Něco podobného na stejném principu později vydal i David Grudl a nikdo mu vendor lock-in nevyčítá.
-
Vyčítají si to akorát lidi, co to teď musí spravovat... Taky jsem pár podobných řešení vymyslel a s odstupem času... nebyl to dobrý nápad. Ten čas a energii, které jsem promrhal vymýšlením kulatějšího kola, jsem mohl radši věnovat do vývoje samotné aplikace - tam by ten investovaný čas byl aspoň vidět, což by ocenili jak zákazníci(kteří by nemuseli pracovat s nějakou ezoterickou vesmírnou technologií), tak uživatelé(kteří by měli propracovanější produkt).
-
Vyčítají si to akorát lidi, co to teď musí spravovat... Taky jsem pár podobných řešení vymyslel a s odstupem času... nebyl to dobrý nápad. Ten čas a energii, které jsem promrhal vymýšlením kulatějšího kola, jsem mohl radši věnovat do vývoje samotné aplikace - tam by ten investovaný čas byl aspoň vidět, což by ocenili jak zákazníci(kteří by nemuseli pracovat s nějakou ezoterickou vesmírnou technologií), tak uživatelé(kteří by měli propracovanější produkt).
Davidu Grudlovi dnes někdo vyčítá, že aplikace v Nette teď po něm musí spravovat?
Tenkrát nic takového neexistovalo, ani Nette, všechno obsahovalo lock-in. Můj jazyk ho naopak otevřel a zjednodušil modifikaci aplikace za provozu obyčejným editorem. Nechápu, proč by mi to měl dnes někdo vyčítat. S odstupem času to hodnotím jako skvělý nápad.
-
Nemluvím o nette, ale o tvojem řešení, které jsi použil jednou a nechal jsi ho tam jako artefakt pro budoucí generace. Vyvíjíš to i dál? Má to aspoň pořádnou dokumentaci? Neznám samozřejmě okolnosti, třeba to mělo opodstatnění, ale spíš mi to připadá jako když postavím celý projekt na vlastním UI frameworku, co jsem včeral slepil na koleně s postupy, které se nikde jinde nepoužívají a na námitky řeknu jenom: podívejte na React, vyčítá jim to někdo? Jenže React je samostatný projekt, který tady bude i za dalších X let, má komunitu, neustále se vyvíjí s ohledem na dění kolem a seženu dalších milión lidí, co v něm umí pracovat.
-
To jsem jim tam měl dát zkompilovanou binárku, jako všichni ostatní?
-
To své řešení jsem pak používal ve všech aplikacích pro firmy, protože se osvědčilo. Dokumentaci po mně nikdo nechtěl.
-
To své řešení jsem pak používal ve všech aplikacích pro firmy, protože se osvědčilo. Dokumentaci po mně nikdo nechtěl.
Hádám že dneska bys tam místo vlastního jazyka použil Luu, či něco podobného, že?
-
To své řešení jsem pak používal ve všech aplikacích pro firmy, protože se osvědčilo. Dokumentaci po mně nikdo nechtěl.
Hádám že dneska bys tam místo vlastního jazyka použil Luu, či něco podobného, že?
Nebo JS :)
-
To své řešení jsem pak používal ve všech aplikacích pro firmy, protože se osvědčilo. Dokumentaci po mně nikdo nechtěl.
Hádám že dneska bys tam místo vlastního jazyka použil Luu, či něco podobného, že?
Dnes pro tyto účely používám PHP s XSLT, všechno client-server. V DOSu už nedělám, přece jen doba mezitím trochu pokročila.
-
To své řešení jsem pak používal ve všech aplikacích pro firmy, protože se osvědčilo. Dokumentaci po mně nikdo nechtěl.
Hádám že dneska bys tam místo vlastního jazyka použil Luu, či něco podobného, že?
Nevím, jestli je ta averze psát si vlastní jazyk opodstatněná. Elasticsearch má vlastní jazyk. Nevím, jak by to vyřešili s nějakou Luou... Mapbox styly mají vlastní expression jazyk. Dtto. Co mi připadá trošku srandovní je to, že v podstatě objevují závorky z lispu, akorát to místo toho cpou do JSONu... (ten mapbox jazyk aspoň evidentně navrhoval někdo, kdo funkcionálním jazykům trošku rozumí...elasticsearch je strašný).. nevím, jestli to je výhoda nebo ne... on ani ten lisp není zrovna výkvět přehlednosti....
Interpretovat lisp-like výrazy je dost triviální záležitost. Tak je trošku otázka, proč kvůli tomu hledat nějaké speciální knihovny...
-
Co mi připadá trošku srandovní je to, že v podstatě objevují závorky z lispu, akorát to místo toho cpou do JSONu...
Když se podívám na šablony Latte, tak je to skoro Lisp - jen místo kulatých závorek jsou chlupaté. Psát název funkce dovnitř závorky je pro interpret velmi praktické - zrychluje a zjednodušuje to zpracování. Někomu vadí velké množsví závorek v Lispu, ale je jich zhruba stejně (možná i méně) než ve srovnatelné javovské aplikaci.
-
Nevím, jestli je ta averze psát si vlastní jazyk opodstatněná. Elasticsearch má vlastní jazyk. Nevím, jak by to vyřešili s nějakou Luou...
Lua je skvělá. Malá, kompaktní, šikovná, rychlá. Ale není funkcionální a nepřekvapivě nemá žádné typy.
Když bych hledal nějaký jazyk, který bych chtěl zakomponovat do svého programu, tak zase tak moc na výběr není. (Nebo tedy já nebyl úspěšný.)
-
Lua je skvělá. Malá, kompaktní, šikovná, rychlá. Ale není funkcionální a nepřekvapivě nemá žádné typy.
S typy je to pravda bídné, ale některé funkcionální věci tam jdou. Přes metatabulku se dá udělat libovolná lua table volatelná, takže tam jdou udělat minimálně funkce vyšších řádů. Dře to, ale jde to.
A je objektovější (v původním smyslu) než jakýkoliv mainstreamový jazyk. S drobnýma výhradama se tam dá psát skoro jako ve Smalltalku, nebo Selfu.
-
Lua je skvělá. Malá, kompaktní, šikovná, rychlá. Ale není funkcionální a nepřekvapivě nemá žádné typy.
S typy je to pravda bídné, ale některé funkcionální věci tam jdou. Přes metatabulku se dá udělat libovolná lua table volatelná, takže tam jdou udělat minimálně funkce vyšších řádů. Dře to, ale jde to.
A je objektovější (v původním smyslu) než jakýkoliv mainstreamový jazyk. S drobnýma výhradama se tam dá psát skoro jako ve Smalltalku, nebo Selfu.
Ta "vyšší objektovost" je ale spíš nevýhoda, ne?
-
Nevím, jestli je ta averze psát si vlastní jazyk opodstatněná. Elasticsearch má vlastní jazyk. Nevím, jak by to vyřešili s nějakou Luou...
Lua je skvělá. Malá, kompaktní, šikovná, rychlá. Ale není funkcionální a nepřekvapivě nemá žádné typy.
Lua má typy. Odvozené, ale má.
Když bych hledal nějaký jazyk, který bych chtěl zakomponovat do svého programu, tak zase tak moc na výběr není. (Nebo tedy já nebyl úspěšný.)
Co tak zmíněný Lisp? Funkcionální je, typy má také, makra na suprové úrovni,...
Jako alternativu z objektového světa jsem zkoušel Smalltalk. Má některé zajímavé vychytávky a jako zdroj inspirace pro tvorbu vlastního jazyka vůbec není špatný.
Lua zase má výhodu v tom, že je integrována do některých jazyků jako modul, např. PHP či Redis. Někdy se to prostě hodí.
-
Ta "vyšší objektovost" je ale spíš nevýhoda, ne?
Proč by měla být "vyšší objektovost" nevýhodou?
-
Já si v rámci inspirace tady tím LLVM příkladem napsal interpret toho mapbox expression jazyka i s typecheckerem. Typechecker má 80 řádek, interpret dalších 80 (definice struktur/typů dalších 80). Faktem je, že díky Lisp-like syntaxi je parser asi na 25 řádek. Napsat si k tomu eventuálně nějaký parser, aby to bylo pro lidi, popravdě taky není zas až takový problém... ale pochopil jsem, proč mají lidi rádi lisp...
V každým případě nějak nevidím úplně nějaký zásadní problém v tom psát si vlastní jazyk... ani bych před pár lety nevěřil, že něco takového řeknu...
Lua má typy. Odvozené, ale má.
Nemá. Pierce jsem už tady citoval. "Tagování" proměnných nejsou typy.
-
Nevím, jestli je ta averze psát si vlastní jazyk opodstatněná. Elasticsearch má vlastní jazyk. Nevím, jak by to vyřešili s nějakou Luou... Mapbox styly mají vlastní expression jazyk. Dtto.
To ale není nějaký ad-hoc jazyk bez dokumentace, který se použije na jedné aplikaci a jede se dál, užijte si to. Tohle je úplně jiný případ.
-
Nevím, jestli je ta averze psát si vlastní jazyk opodstatněná. Elasticsearch má vlastní jazyk. Nevím, jak by to vyřešili s nějakou Luou... Mapbox styly mají vlastní expression jazyk. Dtto.
To ale není nějaký ad-hoc jazyk bez dokumentace, který se použije na jedné aplikaci a jede se dál, užijte si to. Tohle je úplně jiný případ.
Ne, je to ad-hoc jazyk s dokumentací (někdy nejednoznacnou), který se použije na jedné aplikaci (elastic, aplikace mapboxu pro zobrazení map)... Je to úplně jiný případ..
-
ES není aplikace, ale knihovna, kterou někdo spravuje, opravuje v ní bugy, poskytuje support. Ano, je to jiný případ.
-
ještě k prapůvodnímu dotazu: https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/
-
ES není aplikace, ale knihovna, kterou někdo spravuje, opravuje v ní bugy, poskytuje support. Ano, je to jiný případ.
Aha... takže když někdo dodává aplikace, které nikdo nespravuje a neopravuje v nich bugy a neposkytuje support, tak by v těchto aplikacích neměl poskytovat konfiguraci přes vlastní jazyk, případě by tu aplikaci neměl vyvíjet s použitím nějakého vlastního jazyka... (jako třeba v době, kdy nebylo XSLT, tak si rozhodně pro vývoj aplikací nepsat něco, co dělá něco podobného...)......
-
Ta "vyšší objektovost" je ale spíš nevýhoda, ne?
Objektovost bych jí nevyčítal.
Metatabulky jsou perfektní věc. Daj se pak děla i ty type-tagy. Akorát tedy nejde přiřadit meta ke scaláru.
Jedna věc, která mi přijde tak nějak navíc jsou eventy. Díky tomu mám problém to nazvat funkcionální :-)
-
Objektovost bych jí nevyčítal.
Ono říct “objektovost” je dost vágní. Je-li dostatečně pragmatická, je přínosem. Ty type tagy jsou dobrým příkladem. Takto se pak ale dostaneme k polymorfismu.
Jinak ještě k původnímu tématu - vedle typování a jednotkových testů se někdy taky používá obecné dokazování korektnosti při překladu, vývojář napíše podmínky v nějaké deklarativní notaci, které pak překladač vyhodnotí, než vygeneruje kód. Formálně to je jen zobecnění typové kontroly, ale za použití neomezené logiky. Například si můžu “staticky” vyžádat, že odmocnina prvočísla je vždy iracionální apod.
-
vedle typování a jednotkových testů se někdy taky používá obecné dokazování korektnosti při překladu, vývojář napíše podmínky v nějaké deklarativní notaci, které pak překladač vyhodnotí, než vygeneruje kód. Formálně to je jen zobecnění typové kontroly, ale za použití neomezené logiky. Například si můžu “staticky” vyžádat, že odmocnina prvočísla je vždy iracionální apod.
Uniká mi v čem se to liší od typů. Já pomocí typu nemůžu "říct", že odmocnina z prvočísla je vždy iracionální?
nthRoot = x : PrimeNum -> IrrationalNum
-
vedle typování a jednotkových testů se někdy taky používá obecné dokazování korektnosti při překladu, vývojář napíše podmínky v nějaké deklarativní notaci, které pak překladač vyhodnotí, než vygeneruje kód. Formálně to je jen zobecnění typové kontroly, ale za použití neomezené logiky. Například si můžu “staticky” vyžádat, že odmocnina prvočísla je vždy iracionální apod.
Uniká mi v čem se to liší od typů. Já pomocí typu nemůžu "říct", že odmocnina z prvočísla je vždy iracionální?
nthRoot = x : PrimeNum -> IrrationalNum
To samozřejmě jde, měl jsem na mysli aparát, ve kterém se nadefinuje, co je prvočíslo, co je iracionální číslo a jak se odmocňuje. Možná jsem zvolil špatný příklad.
-
To samozřejmě jde, měl jsem na mysli aparát, ve kterém se nadefinuje, co je prvočíslo, co je iracionální číslo a jak se odmocňuje. Možná jsem zvolil špatný příklad.
Jasně.
Právě, že v tom nevidím rozdíl. Pro mě jsou ty typy právě takový aparát.
Napadlo mě něco takového:
Person = {
name: String 1 50
surname: String 1 100
birth: Date * now
sex: Male | Female
spouse: Person | None
} where [
if spouse == Person:
sex != spouse.sex
birth < Now - (18 * year)
]
Ale považuji to také za typový systém.
-
To samozřejmě jde, měl jsem na mysli aparát, ve kterém se nadefinuje, co je prvočíslo, co je iracionální číslo a jak se odmocňuje. Možná jsem zvolil špatný příklad.
Jasně.
Právě, že v tom nevidím rozdíl. Pro mě jsou ty typy právě takový aparát.
Napadlo mě něco takového:
Person = {
name: String 1 50
surname: String 1 100
birth: Date * now
sex: Male | Female
spouse: Person | None
} where [
if spouse == Person:
sex != spouse.sex
birth < Now - (18 * year)
]
Ale považuji to také za typový systém.
Ano. Možná mluvíme o tom samém každý jinak. Na dostatečně abstraktní úrovni a s kvantifikátory se jedná o to samé. Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
-
Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
Ale hlavně se tomu nesmí říkat unit-testy... že? ;D
-
Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
Ale hlavně se tomu nesmí říkat unit-testy... že? ;D
A tak já proti unittestů zas v zásadě nic nemám. Ale tobě to přijde jako unittest?
-
Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
Ale hlavně se tomu nesmí říkat unit-testy... že? ;D
Unit testy se neprovádí v době překladu, na rozdíl od typové kontroly. Máš v tom guláš. A nepoužívej přebytečné pomlčky a smailíky.
-
Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
Ale hlavně se tomu nesmí říkat unit-testy... že? ;D
A tak já proti unittestů zas v zásadě nic nemám. Ale tobě to přijde jako unittest?
On neví, o čem mluví. Ale mám za to, že jsme se tu všichni shodli, že typová kontrola nemůže nahradit jednotkové testy ani naopak, byť se do značné míry překrývají (záleží na síle typového systému, v Javě je to tragédie, ale málokdo píše weby w Coqu nebo Agdě, to už spíš tíhnou k horším věcem).
-
Ale mám za to, že jsme se tu všichni shodli, že typová kontrola nemůže nahradit jednotkové testy ani naopak
Tak na to ať si udělá názor každý sám :-)
-
Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
Tak jak sis mohl všimnout, pro mnohé jsou Java typy vrchol toho co znají.
Jak jsem už uváděl. Pro mě je pro ty typy zásadní, že jsou deklarativní. Popisují a "vysvětlují" to kompilátoru, co to má být. Jestli to napíšeš tak či onak, je IMHO nepodstatné. Někdy si pomáhám slovíčkem "pravidla". Definuju pravidla, kterým ten element musí odpovídat, aby to označil za korektní. A ty pravdla samozřejmě nemusí být jen o "je" a "má", ale můžou být klidně docela komplexní. Klidně to je naféráka jazyk. Akorád nepoučuješ procesor, co má udělat, ale kompilátor, co má ten graf programu znamenat. V čemž vidím rozdíl oproti unittestů. Ty obvykle nejsou tak deklarativní, a hlavně compilátoru nepomáhají.
-
Unit testy se neprovádí v době překladu, na rozdíl od typové kontroly.
Kdy jindy bys chtěl dělat jednotkové testy, než při překladu?
-
Akorát teda pak zápis těch podmínek nebude moc připomínat typování, spíš nějaký lambda kalkul.
pro mnohé jsou Java typy vrchol toho co znají.
Ano, to jsme si všimnul. Je to smutné.
-
Unit testy se neprovádí v době překladu, na rozdíl od typové kontroly.
Kdy jindy bys chtěl dělat jednotkové testy, než při překladu?
Jednotkové testy jsou kód jako každý jiný, normálně se přeloží (compile time) a spustí (run time). Typová kontrola probíhá při překladu nad oanotovaným syntaktickým stromem.
-
Unit testy se neprovádí v době překladu, na rozdíl od typové kontroly.
Kdy jindy bys chtěl dělat jednotkové testy, než při překladu?
Jednotkové testy jsou kód jako každý jiný, normálně se přeloží (compile time) a spustí (run time). Typová kontrola probíhá při překladu nad oanotovaným syntaktickým stromem.
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
-
Unit testy se neprovádí v době překladu, na rozdíl od typové kontroly.
Kdy jindy bys chtěl dělat jednotkové testy, než při překladu?
Jednotkové testy jsou kód jako každý jiný, normálně se přeloží (compile time) a spustí (run time). Typová kontrola probíhá při překladu nad oanotovaným syntaktickým stromem.
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
Ne. Testy se spouští při buildu. Build a compile není to samé.
-
Unit testy se neprovádí v době překladu, na rozdíl od typové kontroly.
Kdy jindy bys chtěl dělat jednotkové testy, než při překladu?
Jednotkové testy jsou kód jako každý jiný, normálně se přeloží (compile time) a spustí (run time). Typová kontrola probíhá při překladu nad oanotovaným syntaktickým stromem.
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
Viz boneflutovo vysvětlení. Unit testy nejsou compile time.
-
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
Ne. Testy se spouští při buildu. Build a compile není to samé.
To bych se načekal. Někdy spouštím testy i 3× za minutu.
-
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
Ne. Testy se spouští při buildu. Build a compile není to samé.
To bych se načekal. Někdy spouštím testy i 3× za minutu.
Podle me nepoustis testy, ale aparatus. Aparatus zajisti, ze se prelozi "jednotka" (pricemz probehne typova kontrola) pak se prelozi test a nakonec se test spusti. Takze unit test se spusti (tesne) po prekladu, ale rozhodne ne pri nem.
-
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
Ne. Testy se spouští při buildu. Build a compile není to samé.
To bych se načekal. Někdy spouštím testy i 3× za minutu.
No a?
-
Nejprve spustím test, ten spustí kompilaci jednotky a otestuje ji. Test tedy spouštím při překladu nebo ne?
Ne. Testy se spouští při buildu. Build a compile není to samé.
To bych se načekal. Někdy spouštím testy i 3× za minutu.
Podle me nepoustis testy, ale aparatus. Aparatus zajisti, ze se prelozi "jednotka" (pricemz probehne typova kontrola) pak se prelozi test a nakonec se test spusti. Takze unit test se spusti (tesne) po prekladu, ale rozhodne ne pri nem.
Sleduj. Teď zase odskočí někam jinam.
-
To bych se načekal. Někdy spouštím testy i 3× za minutu.
Podle me nepoustis testy, ale aparatus. Aparatus zajisti, ze se prelozi "jednotka" (pricemz probehne typova kontrola) pak se prelozi test a nakonec se test spusti. Takze unit test se spusti (tesne) po prekladu, ale rozhodne ne pri nem.
Konečně to někdo pochopil :)
Jednotkové testy už prostě používám jako druhou fázi kompilace.
-
To bych se načekal. Někdy spouštím testy i 3× za minutu.
Podle me nepoustis testy, ale aparatus. Aparatus zajisti, ze se prelozi "jednotka" (pricemz probehne typova kontrola) pak se prelozi test a nakonec se test spusti. Takze unit test se spusti (tesne) po prekladu, ale rozhodne ne pri nem.
Konečně to někdo pochopil :)
Jednotkové testy už prostě používám jako druhou fázi kompilace.
Až na to, že to kompilace není, protože nic nekompiluješ. No nic, log-off.
-
Nemám sílu to už sledovat, takže se omlouvám, pokud něco opakuji.
Osobně vidím rozdíl mezi unittestem a kontrolu pomocí typového systémem tak, jak je zde popsán. Zatímco typový systém určuje omezení, kterým podléhá výsledek, unit test specifikuje vstupy a pro něj správný výstup. Rozumím tomu, že typový popis vypadá velmi elegantně a zachycuje všechny možné hodnoty. Ale nastavit správný typ pro komplexní funkce nemusí být triviální a může se v něm zrcadlit algoritmus výpočtu, což může snadno zanést chybu. Naproti tomu unit test, jakkoliv zachytí jen velmi omezenou množinu možných hodnot, je triviální - vstupy a požadovaný výstup. Možnost chyby velmi omezená. A proto se budou typový systém a unit testy, IMHO, vždy doplňovat. Čím dokonalejší typový systém, tím může být unit tetsů méně, ale nemyslím si, že je možné je zcela pominout. Chyba může vzniknout nejen při programování funkce, ale i při definici typu.
-
Až na to, že to kompilace není, protože nic nekompiluješ. No nic, log-off.
V PHP je sice kompilace skryta, ale interpretr to už dávno není. A tato kompilace se spouští až po spuštění testů.
-
Nemám sílu to už sledovat, takže se omlouvám, pokud něco opakuji.
Osobně vidím rozdíl mezi unittestem a kontrolu pomocí typového systémem tak, jak je zde popsán. Zatímco typový systém určuje omezení, kterým podléhá výsledek, unit test specifikuje vstupy a pro něj správný výstup. Rozumím tomu, že typový popis vypadá velmi elegantně a zachycuje všechny možné hodnoty. Ale nastavit správný typ pro komplexní funkce nemusí být triviální a může se v něm zrcadlit algoritmus výpočtu, což může snadno zanést chybu. Naproti tomu unit test, jakkoliv zachytí jen velmi omezenou množinu možných hodnot, je triviální - vstupy a požadovaný výstup. Možnost chyby velmi omezená. A proto se budou typový systém a unit testy, IMHO, vždy doplňovat. Čím dokonalejší typový systém, tím může být unit tetsů méně, ale nemyslím si, že je možné je zcela pominout. Chyba může vzniknout nejen při programování funkce, ale i při definici typu.
Rozumím. Ale chyba může vzniknout i při psaní testu. Vzhledem k tomu, jak často zoufale nečitelné mohou testy být - velmi snadno.
Jednou se mi stalo, že jsem našel chybu v kódu, který měl stoprocentní pokrytí testy. Byl to den, kdy jsem na coverage zanevřel.
-
Rozumím. Ale chyba může vzniknout i při psaní testu. Vzhledem k tomu, jak často zoufale nečitelné mohou testy být - velmi snadno.
Jednou se mi stalo, že jsem našel chybu v kódu, který měl stoprocentní pokrytí testy. Byl to den, kdy jsem na coverage zanevřel.
Dnes i testy musí mít stejnou úroveň jako produkční kód. Pokud jsou nečitelné, tak to autorovi dřív nebo později někdo omlátí o hlavu. Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
-
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..
-
Rozumím. Ale chyba může vzniknout i při psaní testu. Vzhledem k tomu, jak často zoufale nečitelné mohou testy být - velmi snadno.
To je ovšem dané špatným způsobem psaní testů. Jednotkové testy mají testovat, zda pro „zajímavé“ vstupy dává kód očekávané výstupy. Není důvod, proč by takový test měl být nečitelný. V testu samozřejmě může být chyba, ale pak se na ní obvykle přijde při spouštění testů, protože test neprojde. Vzhledem k tomu, že je test napsaný úplně jiným způsobem, než testovaný kód, je velmi nepravděpodobné, že by v něm byla stejná algoritmická chyba (zejména když v testu žádný algoritmus nemá být). Samozřejmě je možné, že tam bude systematická chyba – test bude očekávat chybný výstup, protože programátor špatně pochopil zadání. Jenže pokud programátor špatně pochopil zadání, bude chyba v kódu vždy, i když bude mít sebelepší typový systém nebo jakýkoli jiný systém kontroly. Tam je jediná šance, že ten test bude psát někdo jiný, kdo zadání pochopí jinak – ale ani to není stoprocentní cesta k úspěchu, protože problém bývá velmi často v tom zadání, takže je dost pravděpodobné, že ho dva programátoři pochopí stejně špatně. A konečně zřejmě nejčastější důvod, proč test neodhalí chybu, je ten, že nepokrývá všechny zajímavé případy – takže chyba bude jednoduše v něčem, co se netestuje. I tenhle typ chyby se bude objevovat u sebelepšího typového systému, protože když programátora nenapadne, že to je zajímavý případ a měl by na to udělat test, nenapadne ho ani ošetřit to v typovém systému.
Jednou se mi stalo, že jsem našel chybu v kódu, který měl stoprocentní pokrytí testy. Byl to den, kdy jsem na coverage zanevřel.
Vy se neustále míjíte s podstatou problémů. Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu. To samozřejmě v žádném případě neznamená, že jsou otestované všechny případy. Pokrytí kódu testy se používá opačně – když nemáte stoprocentní pokrytí kódu testy, máte takřka jistotu, že nepokrytý kód není otestován žádným způsobem. (Zbývá malá možnost, že nepokrytý kód je nedostupný, pak by ale stejně v kódu neměl být.) Takže pokud jste chybu v kódu, který měl stoprocentní pokrytí testy, našel jenom jednou, zažil jste toho zatím opravdu málo. Že jste na code coverage zanevřel po nalezení jediné chyby svědčí pouze a jen o nedostatku pokory, a to vás pak nezachrání sebelepší nástroje. Proto jsem vám už minule psal, že nemáte hledat stříbrnou kulku, která nějak mechanicky zajistí, že budete psát bezchybné programy (to je nemožné), a radši byste se měl snažit pochopit, k čemu slouží nástroje, které máte k dispozici, a správně je používat. Pak můžete dobrý kód psát i v Javě, v JavaScriptu nebo PHP.
-
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..
To je jen formálně 100% pokrytí, které spočítají nějaké automatické vyhodnocovače. To bych mohl napsat prázdné testy, které by nic nedělaly a také tvrdit, že mám 100% pokrytí. Ostatně totéž se běžně dělá i u typů, protože se s tím nikdo nechce piplat.
-
Vzhledem k tomu, že je test napsaný úplně jiným způsobem, než testovaný kód, je velmi nepravděpodobné, že by v něm byla stejná algoritmická chyba (zejména když v testu žádný algoritmus nemá být).
Až na to, že pokud algoritmus něco složitého "počítá", tak není moc šance na to psát unit test buď tak, že ten algoritmus implementuje někdo jiný/jinak, nebo tak, že se prostě výsledek algoritmu vezme jako že je "správně". Ono to má své opodstatěnění, při refaktoringu/optimalizaci to najde, co to rozbilo (nebo naopak spravilo), ale bohužel chyby to často moc nemá šanci najít.
A konečně zřejmě nejčastější důvod, proč test neodhalí chybu, je ten, že nepokrývá všechny zajímavé případy – takže chyba bude jednoduše v něčem, co se netestuje. I tenhle typ chyby se bude objevovat u sebelepšího typového systému, protože když programátora nenapadne, že to je zajímavý případ a měl by na to udělat test, nenapadne ho ani ošetřit to v typovém systému.
No... taková trapárna jako "null pointer exception". Problém je, že u silného typového systému člověk prostě dělá design tak, aby k té chybě vůbec nemohlo dojít už z principu. U testů je velmi jednoduché zapomenout testovat nějakou funkci na to, zda při nějaké konfiguraci vstupů nespadne na null pointer exception.
Takže čistě z praktického hlediska u této konkrétní kategorie chyby bude typický výsledek ten, že typované programy prostě nullpointerexception vyhazovat nebudou, netypované "testované" ano, protože to programátor zapomněl na spoustě míst ošetřit a testy to nenašly.
Já to spíš vidím tak, že některé věci prostě není praktické psát do typů (navíc u některých věcí neexistuje třeba jazyk, který by tyhle věci byl schopen vůbec vyjádřit, u souladu se specifikací to IMO u spousty věcí fakt nejde), někdy by z toho i tak bylo víc práce než užitku.... (na druhou stranu, prakticky kdykoliv jsem nepoužil NonEmpty pro neprázdný list, tak se mi to vymstilo).
Ale konkrétně - jak jsem se inspiroval tím LLVM paperem, tak jsem napsal interpret na ten Mapbox style jazyk a běželo to bez testů napoprvé (po cca. 5 hodinách psaní) a doteď jsem v tom kódu interpretu žádnou chybu nenašel (měl jsem jednu chybu mimo interpret, kdy jsem ve 3 ráno omylem napsal && místo ||). A tady je mimo jiné odpověď na týkající se otázky na "méně kódu" - díky těm typům pak při interpretaci není potřeba kontrolovat, jakého typu jsou vstupy funkcí. Protože prostě mají ten správný typ.
-
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..
To je jen formálně 100% pokrytí, které spočítají nějaké automatické vyhodnocovače. To bych mohl napsat prázdné testy, které by nic nedělaly a také tvrdit, že mám 100% pokrytí. Ostatně totéž se běžně dělá i u typů, protože se s tím nikdo nechce piplat.
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
-
Rozumím. Ale chyba může vzniknout i při psaní testu. Vzhledem k tomu, jak často zoufale nečitelné mohou testy být - velmi snadno.
To je ovšem dané špatným způsobem psaní testů. Jednotkové testy mají testovat, zda pro „zajímavé“ vstupy dává kód očekávané výstupy. Není důvod, proč by takový test měl být nečitelný. V testu samozřejmě může být chyba, ale pak se na ní obvykle přijde při spouštění testů, protože test neprojde.
To je ten lepší případ. Horší je, když chybný test projde, což má BoneFlute zřejmě na mysli. Jenže pak nelze tvrdit, že tento test pokrývá testovaný kód - možná jen formálně.
-
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..
To je jen formálně 100% pokrytí, které spočítají nějaké automatické vyhodnocovače. To bych mohl napsat prázdné testy, které by nic nedělaly a také tvrdit, že mám 100% pokrytí. Ostatně totéž se běžně dělá i u typů, protože se s tím nikdo nechce piplat.
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
-
Pokud jsi našel chybu v kódu, tak zcela jistě neměl 100% pokrytí testy.
ale no tak... test může být prostě blbě - buď je chyba v něčem, co nekontroluje (např. testuje, že delete smaže prvek, ale nezkontroluje, že nesmaže víc než je požadováno) - 100% pokrytí splněno. Nebo máš testy, kdy se testuje, že pro zadaný vstup to dává furt stejný výstup...až na to, že ten "stejný" výstup je od začátku blbě. Opět klidně 100% pokrytí..
To je jen formálně 100% pokrytí, které spočítají nějaké automatické vyhodnocovače. To bych mohl napsat prázdné testy, které by nic nedělaly a také tvrdit, že mám 100% pokrytí. Ostatně totéž se běžně dělá i u typů, protože se s tím nikdo nechce piplat.
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Coz ti zadny nastroj jen tak neprozradi. Napovedet muze az mutacni testovani.
-
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...
Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.
-
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...
Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.
Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.
-
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...
Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.
Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.
v dynamickém jazce? postněte nějaký jednoduchý příklad (funkce+testy), bylo by zajímavé zkusit co s tím udělá zavedení typů
-
Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.
v dynamickém jazce? postněte nějaký jednoduchý příklad (funkce+testy), bylo by zajímavé zkusit co s tím udělá zavedení typů
Zavedení dalších typů s tím neudělá vůbec nic, protože typy nezkoumají funkčnost.
-
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...
Obvyklá definice je ve stylu "testy spustí všechny řádky kódu programu". Ideální by byla definice ve stylu "testy projdou všechen stavový prostor", což ale vzhledem ke state-explosion je dost nereálné. Ale i to negarantuje, že výsledný program bude pracovat správně (např. pro "a * b" by vstup "2,2" prošel veškerý stavový prostor, ale že jsi napsal "a + b" by neodhalil). Další možnost je projít všechny vstupy programu a porovnat je s očekávanými výstupy, ale to je v podstatě reimplementace toho programu, což ten problém moc neřeší...
Jinak když teda definuješ 100% pokrytí testy jako kód pracuje správně, jak bys definoval 90% pokrytí testy?
-
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...
Zajímavá implikace. Na to jsi přišel matematickými postupy?
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
-
Až na to, že pokud algoritmus něco složitého "počítá", tak není moc šance na to psát unit test buď tak, že ten algoritmus implementuje někdo jiný/jinak, nebo tak, že se prostě výsledek algoritmu vezme jako že je "správně". Ono to má své opodstatěnění, při refaktoringu/optimalizaci to najde, co to rozbilo (nebo naopak spravilo), ale bohužel chyby to často moc nemá šanci najít.
Jednotkový test nemá nic počítat. Když budu psát jednotkový test na odmocňování, budu testovat, že odmocnina ze dvou vrátí po zaokrouhlení 1,4142 (což si najdu třeba v tabulkách) a odmocnina z -2 vrátí chybu vstupu. Jak se ve skutečnosti odmocnina počítá nemusím pro psaní testu vůbec vědět. Ano, někdy je ten algoritmus tak netypický, že nikde jinde správné výsledky nenajdu, pak opravdu nezbývá, než testem zafixovat výsledky, co ten algoritmus spočítal. Ale to není tak častý případ.
No... taková trapárna jako "null pointer exception". Problém je, že u silného typového systému člověk prostě dělá design tak, aby k té chybě vůbec nemohlo dojít už z principu. U testů je velmi jednoduché zapomenout testovat nějakou funkci na to, zda při nějaké konfiguraci vstupů nespadne na null pointer exception.
„Null pointer exception“ je řekl bych ukázkový příklad. Můžu to ošetřit pomocí typů, pomocí assertů a nebo to můžu testovat. BoneFlute tu asserty řadí do typového systému a dospěl k tomu tak, že začal do typů vkládat přímo testy. Asserty jsou přitom záměrně navržené tak, aby jednoduché případy mohl vyhodnocovat už kompilátor (nebo něco k němu přilepeného). Takže dohadovat se, co přesně je ještě součástí kompilace a co už ne je trochu akademická diskuse, protože to záleží na konkrétní implementaci – právě asserty se obvykle vyhodnocují až za běhu (poprvé tedy typicky v testech), ale stejně tak je může vyhodnocovat už kompilátor.
Takže čistě z praktického hlediska u této konkrétní kategorie chyby bude typický výsledek ten, že typované programy prostě nullpointerexception vyhazovat nebudou, netypované "testované" ano, protože to programátor zapomněl na spoustě míst ošetřit a testy to nenašly.
Myslím, že je to opět spíš teoretický příklad. Z praktického hlediska bude k těm „null pointer exception“ docházet i v těch typových programech, protože ty nefungují ve vzduchoprázdnu, ale komunikují s okolím – a z něj ty NIL hodnoty dostávají. A i tam budou případy, kdy to programátor prostě přetypuje bez kontroly. Krásně je to vidět např. na Kotlinu, který nullable typy zavedl, ale když se někde váže na Javu, je to plné vykřičníků (tj. přetypování nullable typu na non-nullable, ze kterého může vypadnout NullPointerException).
Já to spíš vidím tak, že některé věci prostě není praktické psát do typů (navíc u některých věcí neexistuje třeba jazyk, který by tyhle věci byl schopen vůbec vyjádřit, u souladu se specifikací to IMO u spousty věcí fakt nejde), někdy by z toho i tak bylo víc práce než užitku.... (na druhou stranu, prakticky kdykoliv jsem nepoužil NonEmpty pro neprázdný list, tak se mi to vymstilo).
Souhlasím. A stejně tak souhlasím s tím, že některé věci je naopak dobré mít v typech – třeba rozlišování typů na nullable/non-nullable považuju za hodně užitečné (i když to počet „null pointer exeception“ jen sníží, ale kromě akademických příkladů je nikdy nevymýtí úplně). Nikdy jsem netvrdil, že silnější typový systém nemůže některé testy učinit zbytečnými. Jenom tvrdím, že sebesilnější typový systém nedokáže nahradit všechny jednotkové testy – protože to, že se algoritmus pro nějaký vstup trefil do správného oboru hodnot ještě neznamená, že je výsledek správně.
Ale konkrétně - jak jsem se inspiroval tím LLVM paperem, tak jsem napsal interpret na ten Mapbox style jazyk a běželo to bez testů napoprvé (po cca. 5 hodinách psaní) a doteď jsem v tom kódu interpretu žádnou chybu nenašel (měl jsem jednu chybu mimo interpret, kdy jsem ve 3 ráno omylem napsal && místo ||). A tady je mimo jiné odpověď na týkající se otázky na "méně kódu" - díky těm typům pak při interpretaci není potřeba kontrolovat, jakého typu jsou vstupy funkcí. Protože prostě mají ten správný typ.
Tohle ale dobře funguje na nízké úrovni, v nějakých knihovnách (kde jsou zároveň nejsilnější i jednotkové testy). Jak se dostáváte výš, deklarativní popis typů by se začal komplikovat a srozumitelnější je použít asserty (i když osobně si myslím, že by programátor měl asserty považovat za deklaraci – ale pořád jsou to výrazy). A na ještě vyšších úrovních už se jenom propojují nějaké komponenty, tam už je řešení pomocí typů úplně nereálné (i kdyby jen proto, že ty komponenty vám dodává někdo jiný, koho nedonutíte detailně nadefinovat typy).
-
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
Ke slovesu pokrytí se váže předmět – tedy pokrytí čeho. Nemá smysl se tady dohadovat a neustále používat nevyjádřený předmět, když je zřejmé, že každý za předmět považuje něco jiného. Obvykle se „pokrytím testy“ myslí pokrytí kódu, tedy 100% pokrytí testy by znamenal pokrytí všech řádků/instrukcí. Které samozřejmě nezaručuje skoro nic, rozhodně nezaručuje bezchybnost. Vy asi myslíte 100% pokrytí všech možných případů, což je u jenom trošku větších věcí nedosažitelné.
-
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...
Zajímavá implikace. Na to jsi přišel matematickými postupy?
Tak pokud bys někomu radil "mějte 100% pokrytí testy", tak vzhledem k tomu, že to definuješ jako program pracuje správně, tak jim radíš "pište programy, které pracují správně"...
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
To samozřejmě můžeš. Stejně jako to, že program používá nějaký typový systém neimplikuje, že program pracuje správně.
-
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...
Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.
To spolu ale nesouvisí. Testy mohou pokrývat 100 % kódu, tj. při spuštění testů se spustí všechny instrukce kódu. To ale vůbec neznamená, že by test duplikoval implementaci. Za „pokrytí testy“ se obvykle označuje právě poměr počtu instrukcí procházených při testech k celkovému počtu instrukcí knihovny či aplikace, protože to se dá změřit. To je reálné (i když to nemusí být nutné, protože chybějící testy mohou nepokrývat nezajímavé části kódu), ale v žádném případě to neříká, že by se testovaly všechny možné vstupy, nebo že by program byl bezchybný, pokud testy projdou. Ukazatel „pokrytí kódu/řádků/instrukcí testy“ má opačný význam – pokud určitá větev programu není testem pokrytá, víme určitě, že pomocí testů určitě nedokážeme poznat, zda v dané části chyba je nebo není.
-
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
100% pokrytí testy nelze dosáhnout ani teoreticky, protože Halting problem: https://en.wikipedia.org/wiki/Halting_problem (https://en.wikipedia.org/wiki/Halting_problem)
Doporučuju, Kite, nastudovat alespoň základy computer science, nebudeš se potom tady na fóru ztrapňovat tak často. A než začneš argumetovat tím, že je to jen teoretická konstrukce a nic takového, jako počítač s nekonečnou pamětí neexistuje, přečti si na wikipedii ten odstavec, který začíná The halting problem is theoretically decidable for linear bounded automata... a pochopíš, že to reálně opravdu udělat nejde.
-
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
Ke slovesu pokrytí se váže předmět – tedy pokrytí čeho. Nemá smysl se tady dohadovat a neustále používat nevyjádřený předmět, když je zřejmé, že každý za předmět považuje něco jiného. Obvykle se „pokrytím testy“ myslí pokrytí kódu, tedy 100% pokrytí testy by znamenal pokrytí všech řádků/instrukcí. Které samozřejmě nezaručuje skoro nic, rozhodně nezaručuje bezchybnost. Vy asi myslíte 100% pokrytí všech možných případů, což je u jenom trošku větších věcí nedosažitelné.
Je to dosažitelné, pokud testované jednotky jsou dostatečně malé a jednoduché (SRP).
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
Nevšiml jsem si, že by tu někdo odmítal moderní technologie. Vidím tu jen nekritické přijímání něčeho, čemu dotyčný moc nerozumí, ale je to pro něj nové (ve skutečnosti to ale ani nic nového není), a má pocit, že to vyřeší všechny problémy světa. Na technologiích není důležité to, jestli jsou nové, ale jaké problémy umí (doopravdy) řešit.
-
No... taková trapárna jako "null pointer exception". Problém je, že u silného typového systému člověk prostě dělá design tak, aby k té chybě vůbec nemohlo dojít už z principu. U testů je velmi jednoduché zapomenout testovat nějakou funkci na to, zda při nějaké konfiguraci vstupů nespadne na null pointer exception.
„Null pointer exception“ je řekl bych ukázkový příklad. Můžu to ošetřit pomocí typů, pomocí assertů a nebo to můžu testovat. BoneFlute tu asserty řadí do typového systému a dospěl k tomu tak, že začal do typů vkládat přímo testy. Asserty jsou přitom záměrně navržené tak, aby jednoduché případy mohl vyhodnocovat už kompilátor (nebo něco k němu přilepeného). Takže dohadovat se, co přesně je ještě součástí kompilace a co už ne je trochu akademická diskuse, protože to záleží na konkrétní implementaci – právě asserty se obvykle vyhodnocují až za běhu (poprvé tedy typicky v testech), ale stejně tak je může vyhodnocovat už kompilátor.
Typ Maybe fakt není assert.
Myslím, že je to opět spíš teoretický příklad. Z praktického hlediska bude k těm „null pointer exception“ docházet i v těch typových programech, protože ty nefungují ve vzduchoprázdnu, ale komunikují s okolím – a z něj ty NIL hodnoty dostávají. A i tam budou případy, kdy to programátor prostě přetypuje bez kontroly. Krásně je to vidět např. na Kotlinu, který nullable typy zavedl, ale když se někde váže na Javu, je to plné vykřičníků (tj. přetypování nullable typu na non-nullable, ze kterého může vypadnout NullPointerException).
Pokud programátor napíše "int x = (unsafeCoerce) 'string'", tak ho fakt nic nezachrání. Ale řekl bych, že je dost velký rozdíl mezi tímto a jazykem, kde člověk může napsat akorát "x = 'string' # comment: x je typu int".
-
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
Ke slovesu pokrytí se váže předmět – tedy pokrytí čeho. Nemá smysl se tady dohadovat a neustále používat nevyjádřený předmět, když je zřejmé, že každý za předmět považuje něco jiného. Obvykle se „pokrytím testy“ myslí pokrytí kódu, tedy 100% pokrytí testy by znamenal pokrytí všech řádků/instrukcí. Které samozřejmě nezaručuje skoro nic, rozhodně nezaručuje bezchybnost. Vy asi myslíte 100% pokrytí všech možných případů, což je u jenom trošku větších věcí nedosažitelné.
Je to dosažitelné, pokud testované jednotky jsou dostatečně malé a jednoduché (SRP).
jak by teda vypadaly testy pro 100% pokrytí tohoto kódu v pythonu:
def x(y, z): return y + z
-
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
100% pokrytí testy nelze dosáhnout ani teoreticky, protože Halting problem: https://en.wikipedia.org/wiki/Halting_problem (https://en.wikipedia.org/wiki/Halting_problem)
Doporučuju, Kite, nastudovat alespoň základy computer science, nebudeš se potom tady na fóru ztrapňovat tak často. A než začneš argumetovat tím, že je to jen teoretická konstrukce a nic takového, jako počítač s nekonečnou pamětí neexistuje, přečti si na wikipedii ten odstavec, který začíná The halting problem is theoretically decidable for linear bounded automata... a pochopíš, že to reálně opravdu udělat nejde.
Nikde jsem netvrdil, že 100% pokrytí testy lze dosáhnout. Stejně tak nelze 100 % funkcionality pokrýt typy.
-
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
Ke slovesu pokrytí se váže předmět – tedy pokrytí čeho. Nemá smysl se tady dohadovat a neustále používat nevyjádřený předmět, když je zřejmé, že každý za předmět považuje něco jiného. Obvykle se „pokrytím testy“ myslí pokrytí kódu, tedy 100% pokrytí testy by znamenal pokrytí všech řádků/instrukcí. Které samozřejmě nezaručuje skoro nic, rozhodně nezaručuje bezchybnost. Vy asi myslíte 100% pokrytí všech možných případů, což je u jenom trošku větších věcí nedosažitelné.
Je to dosažitelné, pokud testované jednotky jsou dostatečně malé a jednoduché (SRP).
Tzn. mají na vstupu málo parametrů (které nejsou typově omezené....) a vevnitř málo podmínek a radši toho moc nevolají... Jinak řečeno pro nějaký normální program nedosažitelné.
-
100% pokrytí testy nelze dosáhnout ani teoreticky, protože Halting problem: https://en.wikipedia.org/wiki/Halting_problem (https://en.wikipedia.org/wiki/Halting_problem)
Doporučuju, Kite, nastudovat alespoň základy computer science, nebudeš se potom tady na fóru ztrapňovat tak často. A než začneš argumetovat tím, že je to jen teoretická konstrukce a nic takového, jako počítač s nekonečnou pamětí neexistuje, přečti si na wikipedii ten odstavec, který začíná The halting problem is theoretically decidable for linear bounded automata... a pochopíš, že to reálně opravdu udělat nejde.
Nikde jsem netvrdil, že 100% pokrytí testy lze dosáhnout. Stejně tak nelze 100 % funkcionality pokrýt typy.
Jsi nějaký nekonzistentní, chlapče:
100% pokrytí všech možných případů, což je u jenom trošku větších věcí nedosažitelné.
Je to dosažitelné, pokud testované jednotky jsou dostatečně malé a jednoduché (SRP).
-
No hlavně pokud 100% pokrytí nelze dosáhnout, tak je možné komukoliv, kdo tvrdí, že má 100% pokrytí říct, že prostě nemá... protože to přece nejde dosáhnout :P
-
Typ Maybe fakt není assert.
Nic takového jsem nepsal. Napsal jsem, že „null pointer exception“ můžete řešit pomocí typů (mít typ, který NIL hodnotu nepřipustí), pomocí assertů (typ připouští NIL, ale na vstupu deklarujete pomocí assertu, že NIL je neplatná vstupní hodnota) a můžete to ošetřit testem (který NIL hodnotu pošle na vstupu a otestuje, zda se kód zachová očekávaným způsobem). To jsou různé způsoby zápisu kódu, a druhá věc je, co s tím pak dělá kompilátor. U typů je to nejjednodušší, tam se tak nějak očekává, že kompilátor tuto informaci použije. Ale kompilátor může použít i jiné informace, třeba z anotací nebo právě assertů – třeba IntelliJ Idea dělá analýzu kódu (je to obohacený kompilátor) a na základě toho odvozuje, zda se jedná o nullable nebo non-null typ. Takže ve zdrojovém kódu ten typ není uveden, při kompilaci se pomocí type inference odvodí, ale pak se dostane ke slovu type erasure a do zkompilovaného kódu se informace o typu opět nedostane (resp. je tam obecnější nullable typ).
Pokud programátor napíše "int x = (unsafeCoerce) 'string'", tak ho fakt nic nezachrání. Ale řekl bych, že je dost velký rozdíl mezi tímto a jazykem, kde člověk může napsat akorát "x = 'string' # comment: x je typu int".
Někdy v tom je velký rozdíl a někdy prakticky žádný. Existují různé problémy, takže i nástroje k jejich řešení jsou různé. Na něco se hodí programovací jazyk s bohatým typovým systémem, na něco typy vůbec nepotřebujete.
-
jak by teda vypadaly testy pro 100% pokrytí tohoto kódu v pythonu:
def x(y, z): return y + z
Stačí jeden test, který selže:
def testX(): assert(x("Ahoj", 42)=="Ahoj42")
Položil jsi otázku chybně. Nemáš funkci x. Zadáním pro test je: Napište funkci x, která sečte hodnoty parametrů. V tomto zadání však chybí specifikace parametrů. Co když na vstup někdo dá dva stringy nebo číslo a string? V posledně jmenovaném případu fuknce, kterou jsi nedůvodně napsal jako první, zahlásí chybu.
-
100% pokrytí (pozor na to že jsou dvě metriky - podle řádek a podle větví!) říká jen to, že všechen kód prošel alespoň jednou. Dává nám jistotu, že v kódu nejsou vyloženě dementní chyby typu překlepů, opačných podmínek, přehozených proměnných stejného typu, použití špatného typu (v případě jazyků bez typové kontroly při překladu) a podobně.
Unittesty rozhodně nezaručí (a v principu nemohou) správnou funkci pro všechny možné hodnoty daných typů, nebo dokonce všechny kombinace. To se dá zajistit typovým systémem, ale ne tím v mainstream jazycích :-)
TLDR: Unittest je nástroj sloužící především autorovi kódu k tomu, aby nebyl za debila.
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
Nevšiml jsem si, že by tu někdo odmítal moderní technologie. Vidím tu jen nekritické přijímání něčeho, čemu dotyčný moc nerozumí, ale je to pro něj nové (ve skutečnosti to ale ani nic nového není), a má pocit, že to vyřeší všechny problémy světa. Na technologiích není důležité to, jestli jsou nové, ale jaké problémy umí (doopravdy) řešit.
mj. jsem narážel na to vaše "sebelepší typový systém nemůže..."
-
jak by teda vypadaly testy pro 100% pokrytí tohoto kódu v pythonu:
def x(y, z): return y + z
Stačí jeden test, který selže:
def testX(): assert(x("Ahoj", 42)=="Ahoj42")
Položil jsi otázku chybně. Nemáš funkci x. Zadáním pro test je: Napište funkci x, která sečte hodnoty parametrů. V tomto zadání však chybí specifikace parametrů. Co když na vstup někdo dá dva stringy nebo číslo a string? V posledně jmenovaném případu fuknce, kterou jsi nedůvodně napsal jako první, zahlásí chybu.
děkuji za odpověď
předpokládejme tu vaši specifikaci ("sečte hodnoty parametrů") a zahoďme moji funkci, jak budou vypadat testy?
-
Kocouři, když se tu hádáte - jste si vědomi toho že "pokrytí" je dost vágní výraz a že se můžeme bavit jak o pokrytí usecasů tak o pokrytí kódu a u pokrytí kódů se zase můžeme, já nevím, snad o tuctu metrik, od function coverage přes branch coverage po statement coverage?
Halting problem se týká univerzálního algoritmu který by dokázal pro jakýkoliv program s jakýmkoliv vstupem rozhodnout, zda dokončí nebo nedokončí běh. Turing nikdy neřekl, že neexistuje algoritmus, který by pro konkrétní program nedokázal rozhodnout, zda dokončí či nedokončí. To je velký rozdíl.
100% coverage (kteréhokoliv druhů) samozřejmě možná je, jen je neskutečně drahá pro cokoliv co není triviální aplikace.
-
Typ Maybe fakt není assert.
Nic takového jsem nepsal. Napsal jsem, že „null pointer exception“ můžete řešit pomocí typů (mít typ, který NIL hodnotu nepřipustí), pomocí assertů (typ připouští NIL, ale na vstupu deklarujete pomocí assertu, že NIL je neplatná vstupní hodnota) a můžete to ošetřit testem (který NIL hodnotu pošle na vstupu a otestuje, zda se kód zachová očekávaným způsobem). To jsou různé způsoby zápisu kódu, a druhá věc je, co s tím pak dělá kompilátor. U typů je to nejjednodušší, tam se tak nějak očekává, že kompilátor tuto informaci použije. Ale kompilátor může použít i jiné informace, třeba z anotací nebo právě assertů – třeba IntelliJ Idea dělá analýzu kódu (je to obohacený kompilátor) a na základě toho odvozuje, zda se jedná o nullable nebo non-null typ. Takže ve zdrojovém kódu ten typ není uveden, při kompilaci se pomocí type inference odvodí, ale pak se dostane ke slovu type erasure a do zkompilovaného kódu se informace o typu opět nedostane (resp. je tam obecnější nullable typ).
Musel jsem si dohledal, na co jsem reagoval a bylo to toto:
I tenhle typ chyby se bude objevovat u sebelepšího typového systému, protože když programátora nenapadne, že to je zajímavý případ a měl by na to udělat test, nenapadne ho ani ošetřit to v typovém systému.
Tak bych si dovolil tvrdit, že programátora v jazyce s ADT null pointer exception chybu řešit fakt napadne, protože tam jinak ten "null" nedostane, zatímco u assertu toho programátor fakt mnohokrát nenapadne tam ten assert vůbec dát. Takže konkrétně nullpointerexception mi připadá jako protipříklad Tvého tvrzení, a nepřipadá mi, že by cokoliv, co jsi napsal poté (byť třeba s tím odstavcem výše souhlasím) jakkoliv tu ideu, že typový systém a unit testy jsou srovnatelné, protože v obojím může udělat programátor chybu, podporovalo.
-
mj. jsem narážel na to vaše "sebelepší typový systém nemůže..."
To ale není odmítání moderních technologií nýbrž pouhé konstatování faktu. Když mne někdo bude přesvědčovat, že má vymyšlený stroj, do kterého nemusí vkládat žádnou energii a ten stroj jí vyrábí, a že už mu to skoro funguje, jenom ještě dořeší nějaké detaily, odmítnu to. Ne proto, že bych odmítal moderní technologie, ale proto, že podle současného stavu poznání perpetuum mobile nelze vyrobit.
-
mj. jsem narážel na to vaše "sebelepší typový systém nemůže..."
To ale není odmítání moderních technologií nýbrž pouhé konstatování faktu. Když mne někdo bude přesvědčovat, že má vymyšlený stroj, do kterého nemusí vkládat žádnou energii a ten stroj jí vyrábí, a že už mu to skoro funguje, jenom ještě dořeší nějaké detaily, odmítnu to. Ne proto, že bych odmítal moderní technologie, ale proto, že podle současného stavu poznání perpetuum mobile nelze vyrobit.
a jste si jistý, že ten současný stav poznání máte podchycený? teď narážím na "dependent types"
-
Halting problem se týká univerzálního algoritmu který by dokázal pro jakýkoliv program s jakýmkoliv vstupem rozhodnout, zda dokončí nebo nedokončí běh. Turing nikdy neřekl, že neexistuje algoritmus, který by pro konkrétní program nedokázal rozhodnout, zda dokončí či nedokončí. To je velký rozdíl.
Zjevně jsi nepřečetl ten odstavec, který jsem doporučoval:
The halting problem is theoretically decidable for linear bounded automata (LBAs) or deterministic machines with finite memory. Minsky warns us, however, that machines such as computers with e.g., a million small parts, each with two states, will have at least 21,000,000 possible states: This is a 1 followed by about three hundred thousand zeroes ... Even if such a machine were to operate at the frequencies of cosmic rays, the aeons of galactic evolution would be as nothing compared to the time of a journey through such a cycle.
V dněšních počítačích a běžných programech je těch stavů ještě o mnoho řádů více. Mnoho štěstí s testováním.
-
...Stoprocentní pokrytí kódu testy znamená, že se při testech projdou všechny „řádky“ (ve skutečnosti instrukce) programu...
Toto je chybné tvrzení. Vy sám jste napsal, že testy nesmějí obsahovat algoritmus, neboli duplikovat implementaci. Úkolem testů není ověření samotné implementace, ale ověření správnosti výstupů pro všechny kombinace možných vstupů, to je 100% pokrytí testem. To je ale obvykle nereálné, takže alespoň jejich části.
To spolu ale nesouvisí. Testy mohou pokrývat 100 % kódu, tj. při spuštění testů se spustí všechny instrukce kódu. To ale vůbec neznamená, že by test duplikoval implementaci. Za „pokrytí testy“ se obvykle označuje právě poměr počtu instrukcí procházených při testech k celkovému počtu instrukcí knihovny či aplikace, protože to se dá změřit. To je reálné (i když to nemusí být nutné, protože chybějící testy mohou nepokrývat nezajímavé části kódu), ale v žádném případě to neříká, že by se testovaly všechny možné vstupy, nebo že by program byl bezchybný, pokud testy projdou. Ukazatel „pokrytí kódu/řádků/instrukcí testy“ má opačný význam – pokud určitá větev programu není testem pokrytá, víme určitě, že pomocí testů určitě nedokážeme poznat, zda v dané části chyba je nebo není.
To se mi nějak nezdá - 100% pokrytím někteří myslí pokrytí celého protokolu objektu, tj. viditelných metod. Že testy nespustí některý vnitřní kód, nemusí znamenat vůbec nic, např. část kódu je nevyužitá (např. před refaktorizací). Nebo si představte, že vytvoříte testy cizí knihovny, do které vůbec nevidíte.
-
Halting problem se týká univerzálního algoritmu který by dokázal pro jakýkoliv program s jakýmkoliv vstupem rozhodnout, zda dokončí nebo nedokončí běh. Turing nikdy neřekl, že neexistuje algoritmus, který by pro konkrétní program nedokázal rozhodnout, zda dokončí či nedokončí. To je velký rozdíl.
Zjevně jsi nepřečetl ten odstavec, který jsem doporučoval:
...
V dněšních počítačích a běžných programech je těch stavů ještě o mnoho řádů více. Mnoho štěstí s testováním.
Phi má recht, obecně to nejde, ale ve speciálních (neřešíme ale, jak často!) ano:
class Vědma:
odpověďNaOtázkuŽivota():
return 42
testVědmy:
assert(Vědma().odpověďNaOtázkuŽivota() == 42)
A je to pokryto. Důkaz sporem.
-
Phi má recht, obecně to nejde, ale ve speciálních (neřešíme ale, jak často!) ano:
Já ale řeším, jak často. Je hezké, že jsi z nekonečného prostoru možných programů vytáhl jeden (který je mimochodem úplně k ničemu), na kterém něco prokážeš. Praktický přínos je nicméně nulový. Pro každý netriviální běžný program, který něco rozumného dělá, tvoje metoda selže. Lidé obvykle chtějí otestovat bežné programy, které mají nějaký užitek. A to neumíme, nedokážeme říct se 100% jistotou, že je program správný, nemáme na to metodu.
-
předpokládejme tu vaši specifikaci ("sečte hodnoty parametrů") a zahoďme moji funkci, jak budou vypadat testy?
Tak především se test nekouká dovnitř, ale zvenčí. A kouká se jen na vlastnosti, které jsou od té funkce požadovány. Pokud je požadavkem "sečíst hodnotu numerických parametrů", tak obvykle stačí třeba:
def testX():
assert(x(3, 5) == 8)
assert(x(-3, 5) == 2)
assert(x(3, -5) == -2)
assert(x(-3, -5) == -8)
Pokud nebudu mít na vstupu např. záporná čísla, mohu odpovídající testy vypustit. Pokud budu chtít touto funkcí spojvat i řetězce nebo posouvat čas o offset, tak je do testu přidám. Pokud potřebuji, aby funkce při výsledku nad hodnotu 100 vyhodila výjimku nebo ten výsledek ořízla (např. životy u her), tak tam takový test také přidám. Dříve definovaná funkce tím přestane procházet a vývojář ji musí upravit.
Tímto způsobem mohu testovat i cizí knihovny, do kterých nevidím, ale očekávám od nich určité chování pro různé očekávané i méně očekávané vstupy. Pokud její autor změní něco, co bude mít vliv na moji aplikaci, dozvím se to.
-
Tak bych si dovolil tvrdit, že programátora v jazyce s ADT null pointer exception chybu řešit fakt napadne, protože tam jinak ten "null" nedostane, zatímco u assertu toho programátor fakt mnohokrát nenapadne tam ten assert vůbec dát.
To záleží na kontextu. Pokud se bude pohybovat v kódu, kde bude většina typů non-null, a výjimečně narazí na nullable typ, ošetří to. Pokud bude z venku neustále dostávat nullable typy a použité typy a typový systém ho budou nutit neustále to přetypovávat, bude to dělat automaticky bez přemýšlení.
Takže bych to upřesnil, že komplexnější typový systém sám o sobě nic nezaručuje, pouze dává větší možnosti. A je na jeho uživatelích, zda ty možnosti využijí – přičemž je potřeba počítat i s tím, že (i podle typů projektů) je různá úroveň programátorů, a nedá se počítat s tím, že ty miliony webových aplikací budou programovat lidé, kteří budou důsledně používat složitý typový systém – bylo by to příliš drahé. Je ale dobré, když se podaří (jako to má třeba Google) využít typový systém v důležitých částech tak, že ty typy nadefinují specialisté, a řádový programátor pak už jen používá typy „obyčejný text“ (který nemůže do HTML vypsat jinak, než escapovaně), a typ „HTML text“, který se při výstupu do HTML neescapuje, ale zase v něm není možné vytvořit nebezpečnou HTML konstrukci (např. náchylnou na XSS).
Takže konkrétně nullpointerexception mi připadá jako protipříklad Tvého tvrzení, a nepřipadá mi, že by cokoliv, co jsi napsal poté (byť třeba s tím odstavcem výše souhlasím) jakkoliv tu ideu, že typový systém a unit testy jsou srovnatelné, protože v obojím může udělat programátor chybu, podporovalo.
Já ale netvrdím, že typový systém a jednotkové testy jsou srovnatelné. Tvrdím, že naopak každý řeší něco jiného, takže obecně nejsou navzájem nahraditelné – i když existuje určitá oblast, kterou je možné řešit oběma způsoby, a když používáte slabší typy, je vhodné danou oblast kontrolovat pomocí jednotkových testů. Jako v tom příkladu s XSS – kdo nepoužívá typy pro bezpečné HTML, jako Google, měl by mít alespoň jednotkové testy snažící se XSS odhalit (což je zrovna dost obtížné a podle mne je snazší řešit to pomocí těch typů).
-
Phi má recht, obecně to nejde, ale ve speciálních (neřešíme ale, jak často!) ano:
Já ale řeším, jak často. Je hezké, že jsi z nekonečného prostoru možných programů vytáhl jeden (který je mimochodem úplně k ničemu), na kterém něco prokážeš. Praktický přínos je nicméně nulový. Pro každý netriviální běžný program, který něco rozumného dělá, tvoje metoda selže. Lidé obvykle chtějí otestovat bežné programy, které mají nějaký užitek. A to neumíme, nedokážeme říct se 100% jistotou, že je program správný, nemáme na to metodu.
Zrovna kontrola, zda mají externí konstanty jednotky správné hodnoty, do testů patří.
-
To se mi nějak nezdá - 100% pokrytím někteří myslí pokrytí celého protokolu objektu, tj. viditelných metod. Že testy nespustí některý vnitřní kód, nemusí znamenat vůbec nic, např. část kódu je nevyužitá (např. před refaktorizací). Nebo si představte, že vytvoříte testy cizí knihovny, do které vůbec nevidíte.
Pokrytí všech instrukcí kódu je to jediné, co se dá relativně snadno změřit, proto to bývá jedna z metrik, které se měří při sestavení projektu. Takže když na nějakém výstupu (třeba od https://codecov.io/) uvidíte metriku „pokrytí testy“, je to právě tohle. Jinak samozřejmě „pokrytí testy“ může znamenat i ledacos jiného, pak by ale každý, kdo to spojení použije, měl uvést, co tím vlastně myslím. Jinak to dopadne jako tady, kde se několik lidí hádá o pokrytí testy, a přitom tím každý myslí něco jiného.
-
Chápu správně, že tvá definice "100% pokrytí" == "kód pracuje správně"?
Je snad jiná definice 100% pokrytí testy? Pokud se test tváří, že pokrývá nějakou vlastnost, ale ve skutečnosti nedělá nic, tak do této statistiky nemůže být zahrnut.
Pokud definuješ 100% pokrytí testy jako "kód pracuje správně", tak pak tvoje rada zní "pište programy správně"...
Zajímavá implikace. Na to jsi přišel matematickými postupy?
Pokud testy prochází a program přitom nepracuje správně, nemohu tvrdit, že má 100% pokrytí testy.
Samozreme, ze muzes. Pokryti testy je jedna metrika, kvalita tech testu vec jina...
-
a jste si jistý, že ten současný stav poznání máte podchycený? teď narážím na "dependent types"
Ano, jsem si tím jistý.
V různých dobách se perpetua mobile vytvářejí na základě v té době moderních věcí – někdy to byl „magnétismus“, někdy „paprsky X“, jindy „elektřina“, dneska to často budou „kvantové jevy“, „energie vakua“ nebo nejnověji nejspíš „temná hmota“. Což nic nemění na tom, že nemožnost konstrukce perpetua mobile plyne z fundamentálních zákonů, a nemusíme znát detailní fungování temné hmoty, nemusíme mít sjednocenou teorii gravitace a kvantové teorie, nemusíme tušit, co se ve fyzice objeví za padesát nebo za sto let, pořád si ale můžeme býti dost jistí, že ani pak nepůjde zkonstruovat perpetuum mobile.
Stejně tak si můžeme být dost jistí, že nepůjde mechanicky zkontrolovat, zda program bude fungovat správně – například i proto, že „správné fungování“ je subjektivní věc, a co může být v jednom případě považováno za správné fungování, v jiném případě tak být nemusí.
Pak je podstatná ještě jedna věc, která tu zatím moc nebyla zmíněna, a to je to, že typový systém může něco užitečného přinést jedině tehdy, když se používá, tedy když ho programátoři chtějí používat. Stačí se podívat na takové malinké vylepšení hloupého typového systému Javy, jakým jsou kontrolované výjimky. Ani tohle drobné typové omezení se prakticky neujalo, a to je velmi jednoduché kontrolované výjimky jak definovat, tak používat. I to připadá většině Java vývojářů jako zbytečně moc práce v porovnání s jejím přínosem. Takže navrhovat nové typy pro masové použití klidně můžete, ale pak se vám také klidně může stát, že budou vznikat a široce se používat knihovny, které budou jako jednu ze svých důležitých vlastností uvádět to, že ruší ten váš typový systém.
-
Tak bych si dovolil tvrdit, že programátora v jazyce s ADT null pointer exception chybu řešit fakt napadne, protože tam jinak ten "null" nedostane, zatímco u assertu toho programátor fakt mnohokrát nenapadne tam ten assert vůbec dát.
To záleží na kontextu. Pokud se bude pohybovat v kódu, kde bude většina typů non-null, a výjimečně narazí na nullable typ, ošetří to. Pokud bude z venku neustále dostávat nullable typy a použité typy a typový systém ho budou nutit neustále to přetypovávat, bude to dělat automaticky bez přemýšlení.
Ano, a to jsem přesně měl na mysli, když jsem říkal, že typ Maybe není totéž co assert. Ukázka (ne-generického) dekódování JSONu s non-null a jedním nullable typem ..
data Obj {
a :: Int
, b :: Text
, c :: [Int]
, d :: NonEmpty Int -- neprazdne pole
, e :: Maybe Double
, f :: UTCTime
}
instance FromJSON Obj where
parseJSON = withObject $ \o ->
Obj <$> o .: "alpha" <*> o .: "beta" <*> o .: "cyril" <*> o .: "delta" <*> o .: "edward" <*> f .: "ftime"
Máš pravdu, když to píšu, tak to píšu bez přemýšlení... až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
Jinak pokud jde o XSS, tak bych neřekl, že je to principálně věc typů.
-
a jste si jistý, že ten současný stav poznání máte podchycený? teď narážím na "dependent types"
Ano, jsem si tím jistý.
z jakých materiálů jste čerpal? popř. v jakém jazyce jste to zkoušel?
-
Jinak pokud jde o XSS, tak bych neřekl, že je to principálně věc typů.
Beru zpět, ano XSS jde řešit typy a zrovna docela hezky.
-
Jinak pokud jde o XSS, tak bych neřekl, že je to principálně věc typů.
Beru zpět, ano XSS jde řešit typy a zrovna docela hezky.
odkaz by nebyl?
-
Pak je podstatná ještě jedna věc, která tu zatím moc nebyla zmíněna, a to je to, že typový systém může něco užitečného přinést jedině tehdy, když se používá, tedy když ho programátoři chtějí používat. Stačí se podívat na takové malinké vylepšení hloupého typového systému Javy, jakým jsou kontrolované výjimky. Ani tohle drobné typové omezení se prakticky neujalo, a to je velmi jednoduché kontrolované výjimky jak definovat, tak používat. I to připadá většině Java vývojářů jako zbytečně moc práce v porovnání s jejím přínosem. Takže navrhovat nové typy pro masové použití klidně můžete, ale pak se vám také klidně může stát, že budou vznikat a široce se používat knihovny, které budou jako jednu ze svých důležitých vlastností uvádět to, že ruší ten váš typový systém.
Kdyby ten system za neco stal, ve smyslu ze pridana hodnota prevysi overhead ktery prinasi, tak by ho programatori radi pouzivali. Jenze tomu tak v jave prave neni.
-
z jakých materiálů jste čerpal? popř. v jakém jazyce jste to zkoušel?
„Ale to je magnétismus, to je úplně nová fyzika, nechoďte na mně s nějakým zastaralým zákonem o zachování energie. Říkám vám, že mi to funguje, jenom maličko točit klikou musíte, ale to se doladí, to už jsou jenom takové maličkosti, jenom najít ten správný mazací olej…“
-
Máš pravdu, když to píšu, tak to píšu bez přemýšlení... až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
Kdybych to psal v dynamickém jazyku, tak asi proto, abych typy nemusel řešit a poradilo si to s co největší škálou různých (i ne zcela správných) vstupů. Podle toho by vypadaly i jednotkové testy – poslal bych do toho JSON, kde by chyběly položky, místo Intu by tam bylo číslo jako text, text nepřevoditelný na číslo, null…
-
Jinak pokud jde o XSS, tak bych neřekl, že je to principálně věc typů.
Beru zpět, ano XSS jde řešit typy a zrovna docela hezky.
odkaz by nebyl?
Jakub Vrána mluvil na Devel.cz o tom, jak to dělají v Googlu – Dokazatelná bezpečnost (https://slideslive.com/38908443/dokazatelna-bezpecnost).
-
z jakých materiálů jste čerpal? popř. v jakém jazyce jste to zkoušel?
„Ale to je magnétismus, to je úplně nová fyzika, nechoďte na mně s nějakým zastaralým zákonem o zachování energie. Říkám vám, že mi to funguje, jenom maličko točit klikou musíte, ale to se doladí, to už jsou jenom takové maličkosti, jenom najít ten správný mazací olej…“
ne magnétismus, "dependent types", jakožto příklad současného stavu věcí
-
Jinak pokud jde o XSS, tak bych neřekl, že je to principálně věc typů.
Beru zpět, ano XSS jde řešit typy a zrovna docela hezky.
odkaz by nebyl?
Nebyl, ale v podstatě to tak řeší všichni - HTML výstup si obalit typem, který lze modifikovat/vytvářet pouze funkcemi, které dělají escaping.
-
nuda, ale zjevně funkční
-
Máš pravdu, když to píšu, tak to píšu bez přemýšlení... až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
Kdybych to psal v dynamickém jazyku, tak asi proto, abych typy nemusel řešit a poradilo si to s co největší škálou různých (i ne zcela správných) vstupů. Podle toho by vypadaly i jednotkové testy – poslal bych do toho JSON, kde by chyběly položky, místo Intu by tam bylo číslo jako text, text nepřevoditelný na číslo, null…
To by mě zajímalo, proč bys zrovna z těchto důvodů tohle psal v dynamickém jazyku.... kvůli tomu zpracování přece v té výsledné struktuře nakonec stejně chceš "Int" a ne text, a když tam nemá být null, tak stejně musíš kontrolovat, že tam není null...
ale zpět - já fakt nesouhlasím s:
To záleží na kontextu. Pokud se bude pohybovat v kódu, kde bude většina typů non-null, a výjimečně narazí na nullable typ, ošetří to. Pokud bude z venku neustále dostávat nullable typy a použité typy a typový systém ho budou nutit neustále to přetypovávat, bude to dělat automaticky bez přemýšlení.
a řekl bych že výše uvedený příklad ukazuje, že to prostě není pravda.
A ze stejných důvodů nesouhlasím s tímto:
I tenhle typ chyby se bude objevovat u sebelepšího typového systému, protože když programátora nenapadne, že to je zajímavý případ a měl by na to udělat test, nenapadne ho ani ošetřit to v typovém systému.
Protože například u té nullpointerexception je prostě používání "Maybe" typu na úplně jiné úrovni než dávat někam asserty a psát k tomu unit testy. V podstatě je to ekvivalentní těm "model checker" systémům. A dost mi to připomíná toto:
There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.
-
Obvykle stačí testovat chování pro limitní a nadlimitní hodnoty vstupů. Testy tak vychází jen asi 2× delší než testovaný kód.
v dynamickém jazce? postněte nějaký jednoduchý příklad (funkce+testy), bylo by zajímavé zkusit co s tím udělá zavedení typů
Zavedení dalších typů s tím neudělá vůbec nic, protože typy nezkoumají funkčnost.
Zkoumají. Už to ty bylo vysvětlováno.
-
předpokládejme tu vaši specifikaci ("sečte hodnoty parametrů") a zahoďme moji funkci, jak budou vypadat testy?
Tak především se test nekouká dovnitř, ale zvenčí. A kouká se jen na vlastnosti, které jsou od té funkce požadovány. Pokud je požadavkem "sečíst hodnotu numerických parametrů", tak obvykle stačí třeba:
def testX():
assert(x(3, 5) == 8)
assert(x(-3, 5) == 2)
assert(x(3, -5) == -2)
assert(x(-3, -5) == -8)
Pokud nebudu mít na vstupu např. záporná čísla, mohu odpovídající testy vypustit. Pokud budu chtít touto funkcí spojvat i řetězce nebo posouvat čas o offset, tak je do testu přidám. Pokud potřebuji, aby funkce při výsledku nad hodnotu 100 vyhodila výjimku nebo ten výsledek ořízla (např. životy u her), tak tam takový test také přidám. Dříve definovaná funkce tím přestane procházet a vývojář ji musí upravit.
Tímto způsobem mohu testovat i cizí knihovny, do kterých nevidím, ale očekávám od nich určité chování pro různé očekávané i méně očekávané vstupy. Pokud její autor změní něco, co bude mít vliv na moji aplikaci, dozvím se to.
dík za doplnění, asi nemá smysl to dál rozebírat, z mojeho pohledu je to slaboučké, nelíbí se mi, že musím doufat, že do toho nikdo nepošle něco s čím jsem nepočítal
-
100% coverage (kteréhokoliv druhů) samozřejmě možná je, jen je neskutečně drahá pro cokoliv co není triviální aplikace.
Já měl funkci, která byla hlášena jako 100% pokryta. Prostě to už někdo napsal.
Druhak, v případě Typového systému máme 100% pokrytí z principu vždy. A kdo zaplatí tu cenu se posouvá od vývojáře aplikace k architektovi typového systému. A tam se samozřejmě rozhoduje, že něco Typama podchycovat nebudeme, protože něco, a pak se to tedy řeší (a nebo taky často ne) testy.
-
Halting problem se týká univerzálního algoritmu který by dokázal pro jakýkoliv program s jakýmkoliv vstupem rozhodnout, zda dokončí nebo nedokončí běh. Turing nikdy neřekl, že neexistuje algoritmus, který by pro konkrétní program nedokázal rozhodnout, zda dokončí či nedokončí. To je velký rozdíl.
Zjevně jsi nepřečetl ten odstavec, který jsem doporučoval:
...
V dněšních počítačích a běžných programech je těch stavů ještě o mnoho řádů více. Mnoho štěstí s testováním.
Phi má recht, obecně to nejde, ale ve speciálních (neřešíme ale, jak často!) ano:
class Vědma:
odpověďNaOtázkuŽivota():
return 42
testVědmy:
assert(Vědma().odpověďNaOtázkuŽivota() == 42)
A je to pokryto. Důkaz sporem.
Počkej, počkej, ještě musíš otestovat negativní případy :-)
-
dík za doplnění, asi nemá smysl to dál rozebírat, z mojeho pohledu je to slaboučké, nelíbí se mi, že musím doufat, že do toho nikdo nepošle něco s čím jsem nepočítal
To nebylo v zadání. Zcela v něm chybělo, jak se ta funkce má chovat, pokud dostane nějaké vstupy, které mají být z nějakého důvodu nevalidní.
-
dík za doplnění, asi nemá smysl to dál rozebírat, z mojeho pohledu je to slaboučké, nelíbí se mi, že musím doufat, že do toho nikdo nepošle něco s čím jsem nepočítal
To nebylo v zadání. Zcela v něm chybělo, jak se ta funkce má chovat, pokud dostane nějaké vstupy, které mají být z nějakého důvodu nevalidní.
no právě, jakékoliv podmínky bych vymyslel, furt musím doufat, že volající je dodrží
-
data Obj {
a :: Int
, b :: Text
, c :: [Int]
, d :: NonEmpty Int -- neprazdne pole
, e :: Maybe Double
, f :: UTCTime
}
instance FromJSON Obj where
parseJSON = withObject $ \o ->
Obj <$> o .: "alpha" <*> o .: "beta" <*> o .: "cyril" <*> o .: "delta" <*> o .: "edward" <*> f .: "ftime"
...až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
Tak především v OOP je (z podstaty) starostí objektu, aby si okontroloval, čím se plní, a naplnění i sám provedl (přestože to tak mnozí nedělají a omrdávají to jakýmisi dírami v implementaci, nebo anemickým modelem). Na to stačí metoda fromJson(json), fromDict(dict) atp. obsahující kontroly (klidně včetně rozsahů hodnot!) a jejich uložení. Jednotkovému testu stačí vyzkoušet, zda objekt pro daná data je možno vytvořit.
P. S.: Co je to zač hen ten paskvil, ve kterém jste to psal, nejde tomu ani rozumět...
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
-
dík za doplnění, asi nemá smysl to dál rozebírat, z mojeho pohledu je to slaboučké, nelíbí se mi, že musím doufat, že do toho nikdo nepošle něco s čím jsem nepočítal
To nebylo v zadání. Zcela v něm chybělo, jak se ta funkce má chovat, pokud dostane nějaké vstupy, které mají být z nějakého důvodu nevalidní.
no právě, jakékoliv podmínky bych vymyslel, furt musím doufat, že volající je dodrží
Jenže to je obráceně. Volající musí definovat, jaké vstupy má funkce předpokládat a které má odmítat. Ani jsi nedefinoval, že vstupy musí být int nebo string. Nic. Není tedy co testovat.
Mám tady i testy, které otestují chování pro rozdílné typy argumentů. Jenže jsi je nechtěl. Proč bych měl dávat do testů podmínky, které nejsou požadovány? Netestuji samotnou funkci, ale jen zda vyhovuje požadavkům na ni kladenou.
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
Tak povídej :-)
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
To jen BoneFlute trolil. Nestála za povšimnutí.
-
Ani jsi nedefinoval, že vstupy musí být int nebo string. Nic. Není tedy co testovat.
Počkej, počkej, máš to otestovat. Ne typovat. Hezky si to otestuj bez použití typů :-P
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
já jsem to pochopil tak, že typová kontrola probíhá vždy nad celým kódem, ne jako test nad malou částí
-
dík za doplnění, asi nemá smysl to dál rozebírat, z mojeho pohledu je to slaboučké, nelíbí se mi, že musím doufat, že do toho nikdo nepošle něco s čím jsem nepočítal
To nebylo v zadání. Zcela v něm chybělo, jak se ta funkce má chovat, pokud dostane nějaké vstupy, které mají být z nějakého důvodu nevalidní.
no právě, jakékoliv podmínky bych vymyslel, furt musím doufat, že volající je dodrží
Jenže to je obráceně. Volající musí definovat, jaké vstupy má funkce předpokládat a které má odmítat. Ani jsi nedefinoval, že vstupy musí být int nebo string. Nic. Není tedy co testovat.
Mám tady i testy, které otestují chování pro rozdílné typy argumentů. Jenže jsi je nechtěl. Proč bych měl dávat do testů podmínky, které nejsou požadovány? Netestuji samotnou funkci, ale jen zda vyhovuje požadavkům na ni kladenou.
však to je přesně ono, není záruka, že volající něco dodrží
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
Tak povídej :-)
Pokryti ceho a cim?
-
To by mě zajímalo, proč bys zrovna z těchto důvodů tohle psal v dynamickém jazyku....
Že je to dynamický jazyk přece bylo vaše zadání. Kdybych chtěl kontrolovat, že jsou tam správné typy, budu to kontrolovat, a jednotkové testy budou dělat to, že budou mít vstupy s různě pokaženými typy a budou testovat, že funkce pro načtení dat skončí správnou chybou. Pak vůbec nezáleží, jaký je typový systém, protože třeba v souboru na disku můžu mít ta data jakákoli, a při načtení musím kontrolovat, že načítaná data jsou validní.
já fakt nesouhlasím s:
To záleží na kontextu. Pokud se bude pohybovat v kódu, kde bude většina typů non-null, a výjimečně narazí na nullable typ, ošetří to. Pokud bude z venku neustále dostávat nullable typy a použité typy a typový systém ho budou nutit neustále to přetypovávat, bude to dělat automaticky bez přemýšlení.
a řekl bych že výše uvedený příklad ukazuje, že to prostě není pravda.
Podle mne se tady nedá na jednom příkladu ukázat, že to není pravda. Vždyť tvrdím, že když donutíte člověka něco dělat opakovaně skoro pokaždé v nějaké situaci, bude to v podobných situacích dělat bez přemýšlení. To je úplně nezávislé na programování, lidé takhle automaticky odklepávají potvrzovací dotazy, pokud se jich aplikace pořád ptá na nějaké nesmysly (třeba jestli má smazat soubor), vjíždí na železniční přejezd, když nebliká červená – a úplně stejně budou do programu automaticky vkládat konstrukci na přetypování na non-null typ, pokud to tak budou používat ve většině případů. Jako příklad budiž třeba implementace escapování jako obrany před SQL injection nebo XSS – pokud se to někde nechalo tak, že si to musel každý ve svém kódu ošetřit sám, bylo vzápětí escapování všude, takže se jeden řetězec escapoval několikrát (což samozřejmě nefungovalo). Dotyčný autor nad tím vůbec nepřemýšlel, jestli je v kontextu kdy musí nebo nesmí escapovat, prostě tu konstrukci bez rozmýšlení mydlil všude.
A ze stejných důvodů nesouhlasím s tímto:
I tenhle typ chyby se bude objevovat u sebelepšího typového systému, protože když programátora nenapadne, že to je zajímavý případ a měl by na to udělat test, nenapadne ho ani ošetřit to v typovém systému.
Protože například u té nullpointerexception je prostě používání "Maybe" typu na úplně jiné úrovni než dávat někam asserty a psát k tomu unit testy.
Rozlišování nullable/non-null typů je myslím extrémní případ, kdy je použití extrémně snadné a pro programátora srozumitelné. Souhlasím s tím, že tohle je případ, kdy je řešení pomocí typů nejlepší řešení. Ale jen o málo složitější věci by typově správně byly nesmírně komplikované, a nebo tam zase musíte povolit potenciální chyby, a programátor to neuhlídá.
Zkuste vzít jako příklad jednoduché porovnání dvou čísel splňující kontrakt „pokud je první číslo větší, vrací zápornou hodnotu, pokud jsou stejná, vrací nulu, pokud je druhé číslo větší, vrací kladnou hodnotu“. Nejjednodušší řešení je čísla odečíst – jenže se může stát, že dojde k přetečení. Může se to ošetřit typově – při sčítání nebo odčítání dvou čísel bude mít návratový typ dvojnásobný rozsah. Jenže se to začne nabalovat, a za chvíli skončíte s datovým typem, který se ani nevejde do paměti. A nebo to budete ošetřovat a pokud by došlo k přetečení typu, vyhodí se výjimka. Jenže pak zase potřebujete jednotkové testy, protože typový systém by vám možná zajistil, že program neudělá skrytě nic špatně, ale raději vyhodí výjimku, ale testy pak potřebujete na to, abyste zkontroloval, že aspoň někdy to skončí jinak, než výjimkou.
-
však to je přesně ono, není záruka, že volající něco dodrží
Zase obráceně. Volaná funkce se musí podřídit tomu, co chce volající. Zde zřejme narážíme na další konflikt FP vs. OOP.
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
Tak povídej :-)
Pokryti ceho a cim?
Měl jsem na mysli trivialitu v tom, že:
fn foo(Byte: x):
je ekvivalentní:
fn foo(x):
fn test_foo():
foreach x in [0, 1, 2, 3, 4, 5 , 6, ... 255]:
foo(x)
fn test_foo_fail_string():
foreach x in ["a", "b", "c", ... "aa", "bb", ...]:
exceptedException
foo(x)
fn test_foo_fail_float():
foreach x in [1.1, 1.2, 1.3, ...]:
exceptedException
foo(x)
a vlastně ten rozvoj je nekonečný...
-
však to je přesně ono, není záruka, že volající něco dodrží
Zase obráceně. Volaná funkce se musí podřídit tomu, co chce volající. Zde zřejme narážíme na další konflikt FP vs. OOP.
možná - "make illegal states unrepresentable"
-
Kdybych to psal v dynamickém jazyku, tak asi proto, abych typy nemusel řešit a poradilo si to s co největší škálou různých (i ne zcela správných) vstupů.
...
To by mě zajímalo, proč bys zrovna z těchto důvodů tohle psal v dynamickém jazyku....
Že je to dynamický jazyk přece bylo vaše zadání.
Nějak nerozumím vašemu logickému uvažování. Giving up.
-
data Obj {
a :: Int
, b :: Text
, c :: [Int]
, d :: NonEmpty Int -- neprazdne pole
, e :: Maybe Double
, f :: UTCTime
}
instance FromJSON Obj where
parseJSON = withObject $ \o ->
Obj <$> o .: "alpha" <*> o .: "beta" <*> o .: "cyril" <*> o .: "delta" <*> o .: "edward" <*> f .: "ftime"
...až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
Tak především v OOP je (z podstaty) starostí objektu, aby si okontroloval, čím se plní, a naplnění i sám provedl (přestože to tak mnozí nedělají a omrdávají to jakýmisi dírami v implementaci, nebo anemickým modelem). Na to stačí metoda fromJson(json), fromDict(dict) atp. obsahující kontroly (klidně včetně rozsahů hodnot!) a jejich uložení. Jednotkovému testu stačí vyzkoušet, zda objekt pro daná data je možno vytvořit.
Ale tohle je diskuze nikoliv OOP vs FP, ale typy vs. unit testy (případně bez typů). Jinak moje praktická zkušnost myslím s "gson"em je ta, že mi to poctivě dávalo "null" do chybějících atributů (při generickém parsingu) a nebylo ochotné se to nechat přesvědčit jinak. Že by to samovolně zareagovalo na @NonNull, tak to už vůbec...
P. S.: Co je to zač hen ten paskvil, ve kterém jste to psal, nejde tomu ani rozumět...
Haskell. To první je deklarace typu. Ta řádka je v podstatě "Obj (o .: "alpha") (o .: "beta") ..", .: je oprátor "najdi v dictionary", akorát to celé běží v nějakém Parser monadu (což tady v podstatě jsou Checked exceptions), proto tam jsou ty divný '<$>' a '<*>' mezi jednotlivýma parametrama. (dá se to napsat i jinak, ale když si to člověk umí "zazávorkovat", tak je to takhle docela přehledné....)
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
Co se týče mě, tak neodmítám, jen jsem si z toho nesedl na zadek, protože to žádná zázračná stříbrná kulka není. Nejspíš na to časem taky přijdeš, obvykle se tak děje když se člověk dostane od učebnicových příkladů k většímu projektu.
-
Ale tohle je diskuze nikoliv OOP vs FP, ale typy vs. unit testy (případně bez typů). Jinak moje praktická zkušnost myslím s "gson"em je ta, že mi to poctivě dávalo "null" do chybějících atributů (při generickém parsingu) a nebylo ochotné se to nechat přesvědčit jinak. Že by to samovolně zareagovalo na @NonNull, tak to už vůbec...
Jenže FP vs. OOP je ve své podstatě totéž jako typy vs. unit testy. OOP se obejde bez typů, FP se obejde bez testů. OOP bez testů je jak FP bez typů. Pro jednoduché úkoly to stačí, ale u složitějších je cítit jejich absence.
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
Co se týče mě, tak neodmítám, jen jsem si z toho nesedl na zadek, protože to žádná zázračná stříbrná kulka není. Nejspíš na to časem taky přijdeš, obvykle se tak děje když se člověk dostane od učebnicových příkladů k většímu projektu.
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
-
Kdybych to psal v dynamickém jazyku, tak asi proto, abych typy nemusel řešit a poradilo si to s co největší škálou různých (i ne zcela správných) vstupů.
...
To by mě zajímalo, proč bys zrovna z těchto důvodů tohle psal v dynamickém jazyku....
Že je to dynamický jazyk přece bylo vaše zadání.
Nějak nerozumím vašemu logickému uvažování. Giving up.
Začalo to takhle:
…
Máš pravdu, když to píšu, tak to píšu bez přemýšlení... až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
-
data Obj {
a :: Int
, b :: Text
, c :: [Int]
, d :: NonEmpty Int -- neprazdne pole
, e :: Maybe Double
, f :: UTCTime
}
instance FromJSON Obj where
parseJSON = withObject $ \o ->
Obj <$> o .: "alpha" <*> o .: "beta" <*> o .: "cyril" <*> o .: "delta" <*> o .: "edward" <*> f .: "ftime"
...až na to, že tohle je kód, který je dost důsledně kontroluje, jestli ve zdrojových datech nechybí atributy, jestli to pole "delta" je fakt neprázdné, jestli tam někde nejsou nully.... a teď mi řekni, jak bys to psal v dynamickém jazyku a jak by vypadaly unit testy....
Tak především v OOP je (z podstaty) starostí objektu, aby si okontroloval, čím se plní, a naplnění i sám provedl (přestože to tak mnozí nedělají a omrdávají to jakýmisi dírami v implementaci, nebo anemickým modelem). Na to stačí metoda fromJson(json), fromDict(dict) atp. obsahující kontroly (klidně včetně rozsahů hodnot!) a jejich uložení. Jednotkovému testu stačí vyzkoušet, zda objekt pro daná data je možno vytvořit.
Ale tohle je diskuze nikoliv OOP vs FP, ale typy vs. unit testy (případně bez typů). Jinak moje praktická zkušnost myslím s "gson"em je ta, že mi to poctivě dávalo "null" do chybějících atributů (při generickém parsingu) a nebylo ochotné se to nechat přesvědčit jinak. Že by to samovolně zareagovalo na @NonNull, tak to už vůbec...
Tak to se omlouvám, ale viděl jsem tam Obj, tak jsem si myslel, že se jedná o OOP. Každopádně jako příklad v dynamickém (netypovém) OO jazyku a s jednotkovými testy to mám správně.
-
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
Co třeba taková kalkulačka? Jenom simulace té nejobyčejnější kalkulačky – zadávání čísel v desítkové soustavě, sčítání, odčítání, násobení a dělení. Žádné priority, žádné paměti, žádné další funkce. Můžete napsat, jaké byste tam použil typy, jak by vypadal kód – a zda byste tam měl nějaké testy, případně jaké?
-
Tak to se omlouvám, ale viděl jsem tam Obj, tak jsem si myslel, že se jedná o OOP. Každopádně jako příklad v dynamickém (netypovém) OO jazyku a s jednotkovými testy to mám správně.
Obj v daném příkladu není objekt, ale typ.
-
...v případě Typového systému máme 100% pokrytí z principu vždy...
Nikoho tu tato věta nevydráždila...?
Tak povídej :-)
Pokryti ceho a cim?
Měl jsem na mysli trivialitu v tom, že:
fn foo(Byte: x):
je ekvivalentní:
fn foo(x):
fn test_foo():
foreach x in [0, 1, 2, 3, 4, 5 , 6, ... 255]:
foo(x)
fn test_foo_fail_string():
foreach x in ["a", "b", "c", ... "aa", "bb", ...]:
exceptedException
foo(x)
fn test_foo_fail_float():
foreach x in [1.1, 1.2, 1.3, ...]:
exceptedException
foo(x)
a vlastně ten rozvoj je nekonečný...
Pokryti testy asi vetsina lidi chape jako (mnozstvi kodu spusteneho behem testovani)/(celkove mnozstvi kodu) a ne jako (mnozstvi testovanych vstupu)/(mnozstvi vsech moznych vstupu).
Nicmene tvuj priklad krasne ukazuje, ze pri pouziti vhodnych typu ztraci smysl vsechny negativni testy. A nejen smysl, ale vlastne ani nejdou napsat/spustit, protoze ta typovane verze funkce proste nejde zavolat s jinym typem argumentu.
A ted se pokusim odpovedet na otazku zivota vesmiru a vubec (a jelikoz nedelam v haskellu tak by to mohlo trknout i Filipa a Kita)
Funkce se da vyjadrit:
- analyticky - o to se vetsina programatoru snazi
- graficky - o to se vetsina programatoru nesnazi, ale mohlo by to byt zajimave
- vyctem hodnot - o to se vlastne snazi BoneFlute, akorat se mu nechce psat vsechny tak "zneuziva" typovy system
A potom je to uz jasne ne? Kdyz mam uz v definici vstupu a vystupu zakodovano chovani funkce (protoze jsem zapis funkce vlastne nahradil lookup tabulkou) tak prece nepotrebuju zadne unit testy ktere overi vysledek pro nejake mizive promile tech moznych vstupu. To je prece jasna duplicita.
A jako bonus dokonce ani nepotrebuju psat telo funkce, protoze vsechno je uz v podpisu.
-
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
Co třeba taková kalkulačka? Jenom simulace té nejobyčejnější kalkulačky – zadávání čísel v desítkové soustavě, sčítání, odčítání, násobení a dělení. Žádné priority, žádné paměti, žádné další funkce. Můžete napsat, jaké byste tam použil typy, jak by vypadal kód – a zda byste tam měl nějaké testy, případně jaké?
nic neslibuju, ale můžu se o to pokusit, asi by bylo ideální abych se o to pokusil v tom jazyce, ve kterém jste si zkoušel dependent types, který že to byl?
-
nic neslibuju, ale můžu se o to pokusit, asi by bylo ideální abych se o to pokusil v tom jazyce, ve kterém jste si zkoušel dependent types, který že to byl?
Bavíme se tu přece teoreticky – nezaznamenal jsem, že by tu BoneFlute jásal, že konečně objevil ten správný jazyk. Takže jsem vám záměrně ponechal volnost, abyste použil jazyk, jaký chcete – předpokládal jsem, že pro to budete muset nadefinovat vlastní jazyk. Ale nemusíte ho definovat nijak podrobně, stačí popsat, jak budou vypadat ty typy a kód. Na konkrétní syntaxi přece nezáleží.
-
nic neslibuju, ale můžu se o to pokusit, asi by bylo ideální abych se o to pokusil v tom jazyce, ve kterém jste si zkoušel dependent types, který že to byl?
Bavíme se tu přece teoreticky – nezaznamenal jsem, že by tu BoneFlute jásal, že konečně objevil ten správný jazyk. Takže jsem vám záměrně ponechal volnost, abyste použil jazyk, jaký chcete – předpokládal jsem, že pro to budete muset nadefinovat vlastní jazyk. Ale nemusíte ho definovat nijak podrobně, stačí popsat, jak budou vypadat ty typy a kód. Na konkrétní syntaxi přece nezáleží.
http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html
-
Nicmene tvuj priklad krasne ukazuje, ze pri pouziti vhodnych typu ztraci smysl vsechny negativni testy.
Což je ovšem dost slabé tvrzení oproti původnímu „nejsou potřeba žádné testy“.
A mimochodem ten BoneFluteův příklad je poněkud nekompletní, protože tam má jenom typ, ale žádnou funkci. Jednotkové testy se ale používají na právě na testování algoritmů. Kdyby se nezabýval jenom tím typem Byte, ale hlavně tou funkcí foo(), hned by měl co testovat.
Funkce se da vyjadrit:
- analyticky - o to se vetsina programatoru snazi
- graficky - o to se vetsina programatoru nesnazi, ale mohlo by to byt zajimave
- vyctem hodnot - o to se vlastne snazi BoneFlute, akorat se mu nechce psat vsechny tak "zneuziva" typovy system
A potom je to uz jasne ne? Kdyz mam uz v definici vstupu a vystupu zakodovano chovani funkce (protoze jsem zapis funkce vlastne nahradil lookup tabulkou) tak prece nepotrebuju zadne unit testy ktere overi vysledek pro nejake mizive promile tech moznych vstupu. To je prece jasna duplicita.
Za prvé je z toho hned vidět, že definovat funkce výčtem hodnot je pro reálné programy v drtivé většině případů nepoužitelné. Až začnete psát o tom, že se to přece dá nějak redukovat a nevypisovat všechny hodnoty, ale nahradit to nějakým předpisem – pak právě přijdou na řadu ty testy, které porovnávají, jestli ten předpis pro některé zajímavé hodnoty dává opravdu tu hodnotu, která by měla být v tom výčtu.
Za druhé, pokud by vám nemožnost udělat úplný výčet připadala jako nějaké dočasné technické omezení, vzpomeňte si třeba na funkce rand() nebo na faktorizaci velkých čísel – kdybychom dokázali ty funkce definovat výčtem hodnot, přestaly by být zajímavé a nikdo by je nepoužíval.
Za třetí, pořád předpokládáte, že výkonný kód i test vzniká stejným způsobem a píše to ten samý programátor. Ve skutečnosti kdyby vám někdo dal funkci (i se zdrojákem) definovanou výčtem hodnot a tvrdil by vám, že ta funkce dělá X, první co byste udělal, že byste si v tom zdrojáku vyhledal pár hodnot a ověřil byste, že alespoň pro tyhle hodnoty opravdu dělá X.
-
nic neslibuju, ale můžu se o to pokusit, asi by bylo ideální abych se o to pokusil v tom jazyce, ve kterém jste si zkoušel dependent types, který že to byl?
Bavíme se tu přece teoreticky – nezaznamenal jsem, že by tu BoneFlute jásal, že konečně objevil ten správný jazyk. Takže jsem vám záměrně ponechal volnost, abyste použil jazyk, jaký chcete – předpokládal jsem, že pro to budete muset nadefinovat vlastní jazyk. Ale nemusíte ho definovat nijak podrobně, stačí popsat, jak budou vypadat ty typy a kód. Na konkrétní syntaxi přece nezáleží.
http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html
Hezký, akorát že to není ta požadovaná kalkulačka, že. Všimněte si, že jeden z implicitních požadavků na program je to, že když dostane nějaký vstup mimo zadání, oznámí chybu. Decimální kalkulačka, do které zadám krf % brf a ona vypíše peklo, asi není úplně bezchybná, nemyslíte?
-
nic neslibuju, ale můžu se o to pokusit, asi by bylo ideální abych se o to pokusil v tom jazyce, ve kterém jste si zkoušel dependent types, který že to byl?
Bavíme se tu přece teoreticky – nezaznamenal jsem, že by tu BoneFlute jásal, že konečně objevil ten správný jazyk. Takže jsem vám záměrně ponechal volnost, abyste použil jazyk, jaký chcete – předpokládal jsem, že pro to budete muset nadefinovat vlastní jazyk. Ale nemusíte ho definovat nijak podrobně, stačí popsat, jak budou vypadat ty typy a kód. Na konkrétní syntaxi přece nezáleží.
http://augustss.blogspot.com/2009/06/more-llvm-recently-someone-asked-me-on.html
Hezký, akorát že to není ta požadovaná kalkulačka, že. Všimněte si, že jeden z implicitních požadavků na program je to, že když dostane nějaký vstup mimo zadání, oznámí chybu. Decimální kalkulačka, do které zadám krf % brf a ona vypíše peklo, asi není úplně bezchybná, nemyslíte?
požadovaná?? tak tohle je asi moje mez, jestli neukážete aspoň trochu snahy porozumět tématu, tak na vás asi nebudu reagovat
-
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
Co třeba taková kalkulačka? Jenom simulace té nejobyčejnější kalkulačky – zadávání čísel v desítkové soustavě, sčítání, odčítání, násobení a dělení. Žádné priority, žádné paměti, žádné další funkce. Můžete napsat, jaké byste tam použil typy, jak by vypadal kód – a zda byste tam měl nějaké testy, případně jaké?
https://gist.github.com/ondrap/69fa2162bc2516469642e5380b379f5c (https://gist.github.com/ondrap/69fa2162bc2516469642e5380b379f5c) (v reálu by tam byl zvlášť typ na operátor a Show instance pro jednodušší debugování, která se bohužel u toho ExprF nenageneruje sama)
Testy obvykle dělám na parsing, a pak asi nějaký test, že to nepočítá úplnou haluz (i.e. 100% code coverage, tady že jsem se neuklep v těch operátorech). Ono tam teda moc co testovat není.... jinak parser na "normální" výrazy není o moc delší, jen jsem línej to hledat... tam by se asi pak řešilo v testech, jestli se korektně respektuje priorita operátorů.
No, ale v podstatě je to to, co jsem psal - parsing typově moc obsáhnout nejde, vlastní výpočet má v podstatě 3 řádky a není moc co tam splést.... aritmetika na Double je poměrně "totální", takže tam taky není moc co řešit...
-
Nicmene tvuj priklad krasne ukazuje, ze pri pouziti vhodnych typu ztraci smysl vsechny negativni testy.
Což je ovšem dost slabé tvrzení oproti původnímu „nejsou potřeba žádné testy“.
Ja ani tak nerikam, nejsou potreba, ale spis nejdou napsat. Je to uplne odlisny vyrok. Nedaval bych to do souvislosti.
Za prvé je z toho hned vidět, že definovat funkce výčtem hodnot je pro reálné programy v drtivé většině případů nepoužitelné. Až začnete psát o tom, že se to přece dá nějak redukovat a nevypisovat všechny hodnoty, ale nahradit to nějakým předpisem – pak právě přijdou na řadu ty testy, které porovnávají, jestli ten předpis pro některé zajímavé hodnoty dává opravdu tu hodnotu, která by měla být v tom výčtu.
A ja myslel, ze sem se vyjadril fakt pochopitelne. Asi ne.
Za druhé, pokud by vám nemožnost udělat úplný výčet připadala jako nějaké dočasné technické omezení, vzpomeňte si třeba na funkce rand() nebo na faktorizaci velkých čísel – kdybychom dokázali ty funkce definovat výčtem hodnot, přestaly by být zajímavé a nikdo by je nepoužíval.
Mohl bych videt prosim nejaky unit test na "funkci" rand?
Za třetí, pořád předpokládáte, že výkonný kód i test vzniká stejným způsobem a píše to ten samý programátor. Ve skutečnosti kdyby vám někdo dal funkci (i se zdrojákem) definovanou výčtem hodnot a tvrdil by vám, že ta funkce dělá X, první co byste udělal, že byste si v tom zdrojáku vyhledal pár hodnot a ověřil byste, že alespoň pro tyhle hodnoty opravdu dělá X.
Urcite ne.
-
Pokryti testy asi vetsina lidi chape jako (mnozstvi kodu spusteneho behem testovani)/(celkove mnozstvi kodu) a ne jako (mnozstvi testovanych vstupu)/(mnozstvi vsech moznych vstupu).
To, že otestuju tři hodnoty, a prohlásím, že kód je otestovaný, přičemž u čtvrté hodnoty to chcípne, to je poněkud smutné, nemyslíš?
Nicmene tvuj priklad krasne ukazuje, ze pri pouziti vhodnych typu ztraci smysl vsechny negativni testy. A nejen smysl, ale vlastne ani nejdou napsat/spustit, protoze ta typovane verze funkce proste nejde zavolat s jinym typem argumentu.
Tak :-)
Funkce se da vyjadrit:
- analyticky - o to se vetsina programatoru snazi
- graficky - o to se vetsina programatoru nesnazi, ale mohlo by to byt zajimave
- vyctem hodnot - o to se vlastne snazi BoneFlute, akorat se mu nechce psat vsechny tak "zneuziva" typovy system
Asi bych se nespokojil s tím, že chápu funkci jen jako výčet hodnot, ale uznávám, že většina mejch ukázek je o tom.
Ale to grafické vyjádření funkce by mě zajímalo. Můžeš to prosím rozvést?
-
požadovaná?? tak tohle je asi moje mez, jestli neukážete aspoň trochu snahy porozumět tématu, tak na vás asi nebudu reagovat
Myslím, že tématu rozumím docela dobře. Téma je, že vy jste moderní borec a každý, kdo zpochybní vaše tvrzení, je zpátečník. A jakmile máte ukázat něco konkrétního, začnete se kroutit a vymlouvat, že tomu nikdo nerozumí. Přitom se po vás chce tak banální věc, abyste podle jednoduchého zadání napsal kód, u kterého nebude dávat žádný smysl něco testovat. Bez toho zadání se to samozřejmě neobejde, protože se testuje soulad se zadáním – kód bez zadání opravdu nemá smysl testovat.
-
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
Co třeba taková kalkulačka? Jenom simulace té nejobyčejnější kalkulačky – zadávání čísel v desítkové soustavě, sčítání, odčítání, násobení a dělení. Žádné priority, žádné paměti, žádné další funkce. Můžete napsat, jaké byste tam použil typy, jak by vypadal kód – a zda byste tam měl nějaké testy, případně jaké?
https://gist.github.com/ondrap/69fa2162bc2516469642e5380b379f5c (https://gist.github.com/ondrap/69fa2162bc2516469642e5380b379f5c) (v reálu by tam byl zvlášť typ na operátor a Show instance pro jednodušší debugování, která se bohužel u toho ExprF nenageneruje sama)
Testy obvykle dělám na parsing, a pak asi nějaký test, že to nepočítá úplnou haluz (i.e. 100% code coverage, tady že jsem se neuklep v těch operátorech). Ono tam teda moc co testovat není.... jinak parser na "normální" výrazy není o moc delší, jen jsem línej to hledat... tam by se asi pak řešilo v testech, jestli se korektně respektuje priorita operátorů.
No, ale v podstatě je to to, co jsem psal - parsing typově moc obsáhnout nejde, vlastní výpočet má v podstatě 3 řádky a není moc co tam splést.... aritmetika na Double je poměrně "totální", takže tam taky není moc co řešit...
Na tomhle se shodneme. Tak třeba to teď konečně vezme v nebo BoneFlute a upraví ten kód tak, aby byly zbytečné všechny testy.
-
https://gist.github.com/ondrap/69fa2162bc2516469642e5380b379f5c (https://gist.github.com/ondrap/69fa2162bc2516469642e5380b379f5c) (v reálu by tam byl zvlášť typ na operátor a Show instance pro jednodušší debugování, která se bohužel u toho ExprF nenageneruje sama)
Testy obvykle dělám na parsing, a pak asi nějaký test, že to nepočítá úplnou haluz (i.e. 100% code coverage, tady že jsem se neuklep v těch operátorech). Ono tam teda moc co testovat není.... jinak parser na "normální" výrazy není o moc delší, jen jsem línej to hledat... tam by se asi pak řešilo v testech, jestli se korektně respektuje priorita operátorů.
No, ale v podstatě je to to, co jsem psal - parsing typově moc obsáhnout nejde, vlastní výpočet má v podstatě 3 řádky a není moc co tam splést.... aritmetika na Double je poměrně "totální", takže tam taky není moc co řešit...
Moc pěkný. Díky!
-
Ja ani tak nerikam, nejsou potreba, ale spis nejdou napsat. Je to uplne odlisny vyrok. Nedaval bych to do souvislosti.
Ovšem celou dobu se tu řeší, zda je pravdivé tvrzení, že testy (v případě dobrého typového systému) vůbec nejsou potřeba. To tvrzení je samozřejmě možné dokázat i metodou, že vyjmenujete různé skupiny testů, u nich ukážete, že jsou zbytečné (nebo že ani nejdou zkompilovat), a pak ukážete, že jste takhle „vyřídil“ všechny skupiny testů. Ale nemá smysl dokazovat jenom tvrzení, že některé testy nebudou potřeba (nebo nepůjdou zkompilovat), protože to tady nikdo nerozporoval.
A ja myslel, ze sem se vyjadril fakt pochopitelne. Asi ne.
Jestli jste to myslel jako reálné řešení problému, pak vás zklamu, ale paměť dnešních počítačů je na tohle stále malá, takže úplným výčtem byste mohl řešit jen velmi jednoduché problémy. Ale zase je ta paměť dost velká na to, aby vás popis toho problému úplným výčtem možností přestal bavit mnohem dřív, než ta paměť dojde.
Mohl bych videt prosim nejaky unit test na "funkci" rand?
Zrovna testování náhodnosti není nic snadného, ale u důležitých systémů (třeba generátory pro kryptografii) se to samozřejmě dělá. Nejjednodušší test by mohl získat třeba 1000 náhodných hodnot, normalizovat je do rozsahu <0, 1) a otestovat, že se průměrná hodnota neliší od 0,5 o víc než nějaké delta. Rozumnější test by kontroloval i distribuci hodnot.
Urcite ne.
Takže věříte tomu, co je napsané v dokumentaci? A pokud něco není v dokumentaci jasně popsané, tak tu službu vůbec nepoužíváte? Nebo si všechno píšete sám, od jádra operačního systému?
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
Co se týče mě, tak neodmítám, jen jsem si z toho nesedl na zadek, protože to žádná zázračná stříbrná kulka není. Nejspíš na to časem taky přijdeš, obvykle se tak děje když se člověk dostane od učebnicových příkladů k většímu projektu.
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
No a závěr je teda jaký? Že bych si z toho měl sednout na zadek, protože... co?
-
trochu offtopic, ale nemáte někdo nějakou teorii tohohle vehementního odmítání moderních technologií?
Co se týče mě, tak neodmítám, jen jsem si z toho nesedl na zadek, protože to žádná zázračná stříbrná kulka není. Nejspíš na to časem taky přijdeš, obvykle se tak děje když se člověk dostane od učebnicových příkladů k většímu projektu.
můžete uvést nějaký příklad menšího většího projektu? třeba ten typově bezpečný AST jsem úspěšně aplikoval na reálný programovací jazyk (IEC61131 STL), je to učebnicový příklad?
No a závěr je teda jaký? Že bych si z toho měl sednout na zadek, protože... co?
dílčí závěr je, že sezení na zadku apod. není předmětem této diskuze (BoneFlute mě kdyžtak opraví), více možná až odpovíte na položené dotazy
-
Na tomhle se shodneme. Tak třeba to teď konečně vezme v nebo BoneFlute a upraví ten kód tak, aby byly zbytečné všechny testy.
[/quote]
proč by to vůbec někdo dělal?
-
proč by to vůbec někdo dělal?
Například proto, aby dokázal pravdivost tvrzení, kterým celé tohle téma odstartovalo – a jehož pravdivost tady mnoho lidí zpochybnilo. BoneFlute na jeho pravdivosti stále trvá (zatím bez důkazu), tak by bylo hezké mít alespoň jeden příklad, kdy to platí.
-
Pokryti testy asi vetsina lidi chape jako (mnozstvi kodu spusteneho behem testovani)/(celkove mnozstvi kodu) a ne jako (mnozstvi testovanych vstupu)/(mnozstvi vsech moznych vstupu).
To, že otestuju tři hodnoty, a prohlásím, že kód je otestovaný, přičemž u čtvrté hodnoty to chcípne, to je poněkud smutné, nemyslíš?
Ale jo, ale to pokryti zajima spis management nez programatory. Je to nejaka metrika ktere si mysli, ze rozumi. Ja na svem projektu rozhodne zadne pokryti nemerim.
Funkce se da vyjadrit:
- analyticky - o to se vetsina programatoru snazi
- graficky - o to se vetsina programatoru nesnazi, ale mohlo by to byt zajimave
- vyctem hodnot - o to se vlastne snazi BoneFlute, akorat se mu nechce psat vsechny tak "zneuziva" typovy system
Asi bych se nespokojil s tím, že chápu funkci jen jako výčet hodnot, ale uznávám, že většina mejch ukázek je o tom.
Ale to grafické vyjádření funkce by mě zajímalo. Můžeš to prosím rozvést?
Nemuzu. Nerozumim tomu :-). Vychazel jsem jen z toho, ze v matematice lze funkci vyjadrit tremi zpusoby. Dva z nich jsou pouzitelne i v programovani, tak proc ne ten treti?
Jedine co si dovedu predstavit je nejake vzorkovani, ktere problem redukuje na vycet hodnot, takze vlastne nuda.
-
proč by to vůbec někdo dělal?
Například proto, aby dokázal pravdivost tvrzení, kterým celé tohle téma odstartovalo – a jehož pravdivost tady mnoho lidí zpochybnilo. BoneFlute na jeho pravdivosti stále trvá (zatím bez důkazu), tak by bylo hezké mít alespoň jeden příklad, kdy to platí.
zase to překrucujete, BoneFlute se ptal na příklad kdy to nejde
-
To, že otestuju tři hodnoty, a prohlásím, že kód je otestovaný, přičemž u čtvrté hodnoty to chcípne, to je poněkud smutné, nemyslíš?
Ano, je to smutné, že programují i lidé, kterým to moc nejde, a běžně nedokážou určit ani ty potenciálně problematické vstupní hodnoty. Že na to nenapíší test je ten menší problém – horší je, že když o tom problému nevědí, neošetří ho ani v tom výkonném kódu.
-
zase to překrucujete, BoneFlute se ptal na příklad kdy to nejde
Ano, a jeden takový příklad, kdy to nejde, tu právě máme. Pokud někdo tvrdí, že to jde vždy, očekával bych, že ten příklad nějak zpochybní, třeba že u jednotlivých testů dokáže, že jsou zbytečné.
-
zase to překrucujete, BoneFlute se ptal na příklad kdy to nejde
Ano, a jeden takový příklad, kdy to nejde, tu právě máme. Pokud někdo tvrdí, že to jde vždy, očekával bych, že ten příklad nějak zpochybní, třeba že u jednotlivých testů dokáže, že jsou zbytečné.
který příklad? v jakém systému a proč to nejde? vy furt opakujete, že to nejde, ale zatím váš jedinný argument byl, že to nejde
-
Funkce se da vyjadrit:
- analyticky - o to se vetsina programatoru snazi
- graficky - o to se vetsina programatoru nesnazi, ale mohlo by to byt zajimave
- vyctem hodnot - o to se vlastne snazi BoneFlute, akorat se mu nechce psat vsechny tak "zneuziva" typovy system
Asi bych se nespokojil s tím, že chápu funkci jen jako výčet hodnot, ale uznávám, že většina mejch ukázek je o tom.
Ale to grafické vyjádření funkce by mě zajímalo. Můžeš to prosím rozvést?
Nemuzu. Nerozumim tomu :-). Vychazel jsem jen z toho, ze v matematice lze funkci vyjadrit tremi zpusoby. Dva z nich jsou pouzitelne i v programovani, tak proc ne ten treti?
Jedine co si dovedu predstavit je nejake vzorkovani, ktere problem redukuje na vycet hodnot, takze vlastne nuda.
Asi ne vždy, ale jde to i graficky. Vygeneruje se více testovacích hodnot a místo porovnání výsledků se vynesou do grafu. Pohledem na graf nebo srovnáním s etalonem můžeme snadno ověřit, zda funkce funguje jak má. Něco podobného jsem používal na vyhodnocení výsledků adaptivní metody Runge-Kutta pro různé velikosti základního kroku.
-
který příklad? v jakém systému a proč to nejde? vy furt opakujete, že to nejde, ale zatím váš jedinný argument byl, že to nejde
Ten příklad, kterým začalo tohle vlákno diskuse, na které reagujete (https://forum.root.cz/index.php?topic=18804.msg271808#msg271808). Když už si to nepamatujete, máte v prohlížeči po straně takové táhlo, za to když potáhnete, bude se vám posouvat stránka na obrazovce, a tak se dostanete i k předchozím komentářům v tomto vlákně, můžete si je přečíst – jsou stále ještě na jedné obrazovce.
Máme tam příklad a v komentáři jsou popsané nějaké testy. Pokud jsou podle vás ty testy zbytečné, napište, čím byste je nahradil. Můj argument, proč to nahradit nejde (už jsem to vysvětloval, ale zřejmě jste to nepochopil), je dostatečný – vy jste zatím neuvedl jediný protipříklad, jak to tedy udělat, místo toho se pořád jen na něco vymlouváte.
Shrnu to pro vás ještě jednou – když máte příklad s testy, a tvrdíte, že testy nejsou potřeba a i bez nich je možné získat minimálně stejnou míru jistoty o správné funkčnosti, předveďte to a upravte ten příklad tak, aby v něm žádné testy nebyly. Pak se můžeme bavit o tom, jestli ty vaše úpravy zaručují stejnou jistotu správné funkčnosti. Dokud to neuděláte, jenom tu plácáte.
-
Nicmene tvuj priklad krasne ukazuje, ze pri pouziti vhodnych typu ztraci smysl vsechny negativni testy.
Což je ovšem dost slabé tvrzení oproti původnímu „nejsou potřeba žádné testy“.
Ja ani tak nerikam, nejsou potreba, ale spis nejdou napsat. Je to uplne odlisny vyrok. Nedaval bych to do souvislosti.
Z toho ale zároveň plyne jedna velká nepříjemnost. Dost blbě se ověřuje, že nějaký obrat opravdu nejde zkompilovat. Spouštět nějakým scriptem kompilaci kousků kódu a testovat jestli to opravdu zdechne je nešikovné.
-
příklad jsem tu uváděl, pokud jste ho ignoroval, vaše škoda
-
Nicmene tvuj priklad krasne ukazuje, ze pri pouziti vhodnych typu ztraci smysl vsechny negativni testy.
Což je ovšem dost slabé tvrzení oproti původnímu „nejsou potřeba žádné testy“.
Ja ani tak nerikam, nejsou potreba, ale spis nejdou napsat. Je to uplne odlisny vyrok. Nedaval bych to do souvislosti.
Z toho ale zároveň plyne jedna velká nepříjemnost. Dost blbě se ověřuje, že nějaký obrat opravdu nejde zkompilovat. Spouštět nějakým scriptem kompilaci kousků kódu a testovat jestli to opravdu zdechne je nešikovné.
tohle je zajímavý problém, existuje taková knihovna pro ghc, která se to pokouší řešit https://hackage.haskell.org/package/should-not-typecheck
-
příklad jsem tu uváděl, pokud jste ho ignoroval, vaše škoda
Tak dlouho tu trollujete, až jste vytrollil sám sebe.
-
Testy obvykle dělám na parsing, a pak asi nějaký test, že to nepočítá úplnou haluz (i.e. 100% code coverage, tady že jsem se neuklep v těch operátorech). Ono tam teda moc co testovat není.... jinak parser na "normální" výrazy není o moc delší, jen jsem línej to hledat... tam by se asi pak řešilo v testech, jestli se korektně respektuje priorita operátorů.
No, ale v podstatě je to to, co jsem psal - parsing typově moc obsáhnout nejde, vlastní výpočet má v podstatě 3 řádky a není moc co tam splést.... aritmetika na Double je poměrně "totální", takže tam taky není moc co řešit...
Jaktože tam není co testovat? Zde jsou testy efektivní - pro různé kombinace řetězcových výrazů (včetně chybných, s různými mezerami, závorkami atd.) můžu pokrýt mnoho jevů a otestovat, zda z kalkulačky padá, co má.
-
Mohl bych videt prosim nejaky unit test na "funkci" rand?
Psát to sem nebudu, popis musí stačit: Lze testovat např. typ hodnot, interval, rozložení, shodu posloupností v případě implementace se seedem, ...
-
Testy obvykle dělám na parsing, a pak asi nějaký test, že to nepočítá úplnou haluz (i.e. 100% code coverage, tady že jsem se neuklep v těch operátorech). Ono tam teda moc co testovat není.... jinak parser na "normální" výrazy není o moc delší, jen jsem línej to hledat... tam by se asi pak řešilo v testech, jestli se korektně respektuje priorita operátorů.
No, ale v podstatě je to to, co jsem psal - parsing typově moc obsáhnout nejde, vlastní výpočet má v podstatě 3 řádky a není moc co tam splést.... aritmetika na Double je poměrně "totální", takže tam taky není moc co řešit...
Jaktože tam není co testovat? Zde jsou testy efektivní - pro různé kombinace řetězcových výrazů (včetně chybných, s různými mezerami, závorkami atd.) můžu pokrýt mnoho jevů a otestovat, zda z kalkulačky padá, co má.
Do není pochopitelné na "testy dělám na parsing"?
A co chcete testovat na:
compute :: Expr -> Double
compute = cata go
where
go (Num n) = n
go (Op op a1 a2) = op a1 a2
Pokud bychom do jazyka přidali prioritu a závorky, tak to je všechno věc parsingu, na tohle to nebude mít žádný vliv.
-
A co chcete testovat na:
compute :: Expr -> Double
compute = cata go
where
go (Num n) = n
go (Op op a1 a2) = op a1 a2
Pokud bychom do jazyka přidali prioritu a závorky, tak to je všechno věc parsingu, na tohle to nebude mít žádný vliv.
Testovat můžeš například to, jestli jsi omylem nezaměnil operátory, jestli jsi dal závorky tam, kam patří, jestli omylem nevoláš nevhodnou funkci z knihovny, jestli jsi nezaměnil proměnné nebo pořadí parametrů stejného typu,... Jistě, u jednoduchého příkladu se bez testů obejdeš, podobně jako v OOP, ale neprogramujeme jen jednoduché kalkulačky.
-
A co chcete testovat na:
compute :: Expr -> Double
compute = cata go
where
go (Num n) = n
go (Op op a1 a2) = op a1 a2
Pokud bychom do jazyka přidali prioritu a závorky, tak to je všechno věc parsingu, na tohle to nebude mít žádný vliv.
Testovat můžeš například to, jestli jsi omylem nezaměnil operátory, jestli jsi dal závorky tam, kam patří, jestli omylem nevoláš nevhodnou funkci z knihovny, jestli jsi nezaměnil proměnné nebo pořadí parametrů stejného typu,... Jistě, u jednoduchého příkladu se bez testů obejdeš, podobně jako v OOP, ale neprogramujeme jen jednoduché kalkulačky.
Reagoval jsem na:
Jaktože tam není co testovat? Zde jsou testy efektivní - pro různé kombinace řetězcových výrazů (včetně chybných, s různými mezerami, závorkami atd.) můžu pokrýt mnoho jevů a otestovat, zda z kalkulačky padá, co má.
Takže rozumíme si, že na výše uvedeném kódu toho fakt k testování moc není?
-
Mohl bych videt prosim nejaky unit test na "funkci" rand?
Psát to sem nebudu, popis musí stačit: Lze testovat např. typ hodnot, interval, rozložení, shodu posloupností v případě implementace se seedem, ...
Nemel by prave typ hodnot podchytit typovy system? To same interval. Shodu s posloupnosti si taky dovedu predstavit.
-
A co chcete testovat na:
compute :: Expr -> Double
compute = cata go
where
go (Num n) = n
go (Op op a1 a2) = op a1 a2
Pokud bychom do jazyka přidali prioritu a závorky, tak to je všechno věc parsingu, na tohle to nebude mít žádný vliv.
Testovat můžeš například to, jestli jsi omylem nezaměnil operátory, jestli jsi dal závorky tam, kam patří, jestli omylem nevoláš nevhodnou funkci z knihovny, jestli jsi nezaměnil proměnné nebo pořadí parametrů stejného typu,... Jistě, u jednoduchého příkladu se bez testů obejdeš, podobně jako v OOP, ale neprogramujeme jen jednoduché kalkulačky.
Reagoval jsem na:
Jaktože tam není co testovat? Zde jsou testy efektivní - pro různé kombinace řetězcových výrazů (včetně chybných, s různými mezerami, závorkami atd.) můžu pokrýt mnoho jevů a otestovat, zda z kalkulačky padá, co má.
Takže rozumíme si, že na výše uvedeném kódu toho fakt k testování moc není?
Psal jsem, co všechno na tomhle můžeš otestovat. Pokud místo posledního řádku omylem napíšeš
go (Op op a1 a2) = op a2 a1
tak to kompilátor sežere i s chlupama a přitom to bude špatně.
-
go (Op op a1 a2) = op a2 a1
tak to kompilátor sežere i s chlupama a přitom to bude špatně.
dalo by se to napsat jako
data Expr a where
Op :: (x -> y -> z) -> Expr x -> Expr y -> Expr z
ale nevím jestli to jde s tím rekurzním schématem
-
go (Op op a1 a2) = op a2 a1
tak to kompilátor sežere i s chlupama a přitom to bude špatně.
dalo by se to napsat jako
data Expr a where
Op :: (x -> y -> z) -> Expr x -> Expr y -> Expr z
ale nevím jestli to jde s tím rekurzním schématem
Pokud jsem dobře pochopil, tak se tohle dělá jen teoreticky. Stejně jako mnozí, kteří dělají testy také jen teoreticky - jenže na ně jsou aspoň metriky, u kterých je nepraktické podvádět.
-
Pokryti testy asi vetsina lidi chape jako (mnozstvi kodu spusteneho behem testovani)/(celkove mnozstvi kodu) a ne jako (mnozstvi testovanych vstupu)/(mnozstvi vsech moznych vstupu).
To, že otestuju tři hodnoty, a prohlásím, že kód je otestovaný, přičemž u čtvrté hodnoty to chcípne, to je poněkud smutné, nemyslíš?
Ale jo, ale to pokryti zajima spis management nez programatory. Je to nejaka metrika ktere si mysli, ze rozumi. Ja na svem projektu rozhodne zadne pokryti nemerim.
Mám na mysli takové to, když vývojář napíše těch pár testů a posílá na produkci. Tím gestem říká, že je to otestované. Nemluvil jsem vysloveně o ceverage.
Nemuzu. Nerozumim tomu :-). Vychazel jsem jen z toho, ze v matematice lze funkci vyjadrit tremi zpusoby. Dva z nich jsou pouzitelne i v programovani, tak proc ne ten treti?
Jedine co si dovedu predstavit je nejake vzorkovani, ktere problem redukuje na vycet hodnot, takze vlastne nuda.
No já v matematice poněkud plavu, ale měl jsem za to, že ten algoritmus je funkce, která počítá hodnoty, ze kterých se dá udělat taková ta křivka ukazující charakteristiku, jak ty hodnoty jdou.
Asi bych si dovedl představit, že někdo bude "programovat" funkci tím, že ji myší vytáhne v nějakém prostoru, a kompiler z toho odvodí funkci. Ale nedovedu si představit, že by to bylo praktické.
Četl jsem zajímavej článek o tom, že máme matematiku řeckou, založenou na algoritmu, a babylonskou, založenou na tabulce (třeba takové ty tabulky odmocnin, co nám dávali na základce).
Máme reálnou množinu všech možných trojúhelníků.
Babyloňan z té množiny udělá podmnožinu několika pravoúhlých trojúhelníků, a tobě to musí stačit. Pythagoras vymyslí vzorec, kterým vytáhne libovolný pravúhlý trojúhelník jen na základě argumentů (vytvoří funktor? mezi množinou trojúhelníků a množinou těch argumentů).
Na tom typování je vtipné právě to, že na rozdíl od testování se pokouší o vytvoření těch ultimátních vzorečků díky kterým dosáhnu ultimátní jistoty.
-
go (Op op a1 a2) = op a2 a1
tak to kompilátor sežere i s chlupama a přitom to bude špatně.
dalo by se to napsat jako
data Expr a where
Op :: (x -> y -> z) -> Expr x -> Expr y -> Expr z
ale nevím jestli to jde s tím rekurzním schématem
Pokud jsem dobře pochopil, tak se tohle dělá jen teoreticky. Stejně jako mnozí, kteří dělají testy také jen teoreticky - jenže na ně jsou aspoň metriky, u kterých je nepraktické podvádět.
jak teoreticky? je to normální, nudný haskell (-XGADTs)
-
Na tom typování je vtipné právě to, že na rozdíl od testování se pokouší o vytvoření těch ultimátních vzorečků díky kterým dosáhnu ultimátní jistoty.
… ultimátní jistoty v tom, že se ten vzoreček trefí do správného oboru hodnot. Ale neříká to vůbec nic o tom, jestli konkrétní vypočtené hodnoty jsou ty, které by člověk čekal.
To je ale pořád dokola.
-
Mohl bych videt prosim nejaky unit test na "funkci" rand?
Psát to sem nebudu, popis musí stačit: Lze testovat např. typ hodnot, interval, rozložení, shodu posloupností v případě implementace se seedem, ...
Nemel by prave typ hodnot podchytit typovy system? To same interval. Shodu s posloupnosti si taky dovedu predstavit.
Samozřejmě že ano, to jsem dopsal jen proto, že to není problém a jde to. Problém pro typový systém už ale jsou to rozložení a opakovatelnost, to by mě zajímalo!
-
Mohl bych videt prosim nejaky unit test na "funkci" rand?
Psát to sem nebudu, popis musí stačit: Lze testovat např. typ hodnot, interval, rozložení, shodu posloupností v případě implementace se seedem, ...
Nemel by prave typ hodnot podchytit typovy system? To same interval. Shodu s posloupnosti si taky dovedu predstavit.
Samozřejmě že ano, to jsem dopsal jen proto, že to není problém a jde to. Problém pro typový systém už ale jsou to rozložení a opakovatelnost, to by mě zajímalo!
Obvykle se rand vystrkává do side-effektů.
-
go (Op op a1 a2) = op a2 a1
tak to kompilátor sežere i s chlupama a přitom to bude špatně.
dalo by se to napsat jako
data Expr a where
Op :: (x -> y -> z) -> Expr x -> Expr y -> Expr z
ale nevím jestli to jde s tím rekurzním schématem
Já zrovna tohle řešil v tom Mapboxu (ale nepotřeboval jsem to, tak jsem se na to vybod), kde by to bylo zhruba takhle:
Op :: Callable (Function paramlist z) => Function paramlist z -> Args paramlist -> Expr z
Ono to sazmozřejmě nezabrání tomu, aby člověk někde nenapsal '("sin", sin), ("cos", sin)', ale tak to je pak otázka nakolik mají unit testy (který by měly kontrolovat tu nejmenší část kódu) kontrolovat konstanty... (našel jsem jeden bug tohoto typu přímo v GHC...) možná někde v raketovém výzkumu, kde jeden tým píše a druhý kontroluje, jinak mi to nedává moc smysl.
Unittesty/typy jsou prostě nástroj, díky kterému můžeme psát programy s méně chybama - a od nějakého momentu dost nedávají smysl. A díky těm typům lze dosáhnout výrazně vyšší kvality s výrazně menším použitím i těch testů (ta kalkulačka je pravděpodobně kvalitnější bez jakéhokoliv testu než co by většina lidí spáchala v JS/pythonu/... i s unit testama).
-
Pokryti testy asi vetsina lidi chape jako (mnozstvi kodu spusteneho behem testovani)/(celkove mnozstvi kodu) a ne jako (mnozstvi testovanych vstupu)/(mnozstvi vsech moznych vstupu).
To, že otestuju tři hodnoty, a prohlásím, že kód je otestovaný, přičemž u čtvrté hodnoty to chcípne, to je poněkud smutné, nemyslíš?
Ale jo, ale to pokryti zajima spis management nez programatory. Je to nejaka metrika ktere si mysli, ze rozumi. Ja na svem projektu rozhodne zadne pokryti nemerim.
Mám na mysli takové to, když vývojář napíše těch pár testů a posílá na produkci. Tím gestem říká, že je to otestované. Nemluvil jsem vysloveně o ceverage.
Doufam, ze ve vetsine pripadu jeste do nejakeho testovaciho prostredi kde se na to koukne nekdo z QA. Ale i tak, mas pravdu. Nemelo by mu to stacit.
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Nemuzu. Nerozumim tomu :-). Vychazel jsem jen z toho, ze v matematice lze funkci vyjadrit tremi zpusoby. Dva z nich jsou pouzitelne i v programovani, tak proc ne ten treti?
Jedine co si dovedu predstavit je nejake vzorkovani, ktere problem redukuje na vycet hodnot, takze vlastne nuda.
No já v matematice poněkud plavu, ale měl jsem za to, že ten algoritmus je funkce, která počítá hodnoty, ze kterých se dá udělat taková ta křivka ukazující charakteristiku, jak ty hodnoty jdou.
Asi bych si dovedl představit, že někdo bude "programovat" funkci tím, že ji myší vytáhne v nějakém prostoru, a kompiler z toho odvodí funkci. Ale nedovedu si představit, že by to bylo praktické.
Dovedu si treba predstavit pripad, ze nejaky program generuje jako jeden z vystupu nejaky graf kam vynasi body ktere oznacuji nejaky konkretni pripad pouziti. Prijde business analytik a v grafu za posledni mesic vyznaci body, ktere jsou nezadouci. V pripade, ze se body pripadu pouziti budou shlukovat vhodne podle stejneho kriteria jako pouzije business analytik, muze byt prakticke nakreslit krivku ktera oddeli zadouci a nezadouci body a nechat si vyhodnotit funkci predpis kompilatorem. Ale jak kdysi rekl jeden mudrc: " na prakticnost vam prdim" :-)
-
data Expr a where
Op :: (x -> y -> z) -> Expr x -> Expr y -> Expr z
ale nevím jestli to jde s tím rekurzním schématem
Zas blbě :) Jo, jde to i s tím rekurzivním schématem: http://www.timphilipwilliams.com/posts/2013-01-16-fixing-gadts.html (http://www.timphilipwilliams.com/posts/2013-01-16-fixing-gadts.html)
-
A díky těm typům lze dosáhnout výrazně vyšší kvality s výrazně menším použitím i těch testů (ta kalkulačka je pravděpodobně kvalitnější bez jakéhokoliv testu než co by většina lidí spáchala v JS/pythonu/... i s unit testama).
Zahráváš si s ohněm :D
-
data Expr a where
Op :: (x -> y -> z) -> Expr x -> Expr y -> Expr z
ale nevím jestli to jde s tím rekurzním schématem
Zas blbě :) Jo, jde to i s tím rekurzivním schématem: http://www.timphilipwilliams.com/posts/2013-01-16-fixing-gadts.html (http://www.timphilipwilliams.com/posts/2013-01-16-fixing-gadts.html)
hezké, díky
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Domnívám se, že v tomto případě jde spíše o automaticky generované testy. Což je taky dobrý. Ale typy jsou imho o něčem jiném. Viz ta ukázka https://forum.root.cz/index.php?topic=18804.msg271719#msg271719
Můžeš udělat typy, které se budou checkovat třeba týden. Ale udělat testy na bambilion vstupů budou ještě mnohem horší s horší efektivitou.
Ale jak kdysi rekl jeden mudrc: " na prakticnost vam prdim" :-)
Au :-D Na svou obranu musím říct, že to bylo prohlášení uvedené v zoufalství ze zaspamování této diskuse, kdy se ani věci znalí lidé nechtěli bavit k tématu ze strachu z trollů.
-
Ale jak kdysi rekl jeden mudrc: " na prakticnost vam prdim" :-)
Au :-D Na svou obranu musím říct, že to bylo prohlášení uvedené v zoufalství ze zaspamování této diskuse, kdy se ani věci znalí lidé nechtěli bavit k tématu ze strachu z trollů.
Sorry, ale za to zatrollení diskuze si můžeš IMO primárně sám. Většina téhle diskuze je o tom, že ostatní šijou do tvých kategorických tvrzení.
-
Sorry, ale za to zatrollení diskuze si můžeš IMO primárně sám. Většina téhle diskuze je o tom, že ostatní šijou do tvých kategorických tvrzení.
Ale no tak!
Takže když napíšu "Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém." je to přes čáru? A místní smetánka, která věci sice nerozumí, ale má tím pádem právo mě trollit? To jako vážně?!
-
Sorry, ale za to zatrollení diskuze si můžeš IMO primárně sám. Většina téhle diskuze je o tom, že ostatní šijou do tvých kategorických tvrzení.
Ale no tak!
Takže když napíšu "Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém." je to přes čáru? A místní smetánka, která věci sice nerozumí, ale má tím pádem právo mě trollit? To jako vážně?!
Je to kategorické tvrzení. Taková přímo svádějí k vyvracení. A když místní smetánce otloukáš o hlavu že tomu nerozumí, tak si o to přímo říkáš. Obzvlášť když to vypadá, že jsi ani nepochopil jejich argumenty.
-
Sorry, ale za to zatrollení diskuze si můžeš IMO primárně sám. Většina téhle diskuze je o tom, že ostatní šijou do tvých kategorických tvrzení.
Ale no tak!
Takže když napíšu "Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém." je to přes čáru? A místní smetánka, která věci sice nerozumí, ale má tím pádem právo mě trollit? To jako vážně?!
Je to kategorické tvrzení. Taková přímo svádějí k vyvracení. A když místní smetánce otloukáš o hlavu že tomu nerozumí, tak si o to přímo říkáš. Obzvlášť když to vypadá, že jsi ani nepochopil jejich argumenty.
Vyvracení není trollení.
Já nejsem ten, který tu na potkání tvrdí, že ten druhý je úplně blbej, a že tomu nerozumí, a že by měl to a to. Si mě s někým pleteš.
A co se týče argumentů, byl bych s něčím takovým výrazně méně kategorický. Ano, uznávám, že příspěvky Kita a Filipa Jirsáka nečtu. Určitě chápeš proč.
-
Vyvracení není trollení.
Začalo to kultivovaným vyvracením. A to i ze strany Kitta a Jirsáka.
Já nejsem ten, který tu na potkání tvrdí, že ten druhý je úplně blbej, a že tomu nerozumí, a že by měl to a to. Si mě s někým pleteš.
Nepletu. Já napsal něco jiného. Prosím nevkládej mi do příspěvků něco, co tam není.
A co se týče argumentů, byl bych s něčím takovým výrazně méně kategorický. Ano, uznávám, že příspěvky Kita a Filipa Jirsáka nečtu. Určitě chápeš proč.
Minimálně příspěvky Filipa Jirsáka jsi četl a reagoval jsi na ně. A dost arogantně. Např:
Sorry, tvé příspěvky nejsou vůbec inspirativní. Nebudu se tedy tebou již zabejvat.
Ano, jeho argument byl jednoduchý, ale velmi relevantní.
-
...
Je vidět, že naše metriky se zásadně liší. To je vše, co k tomu mohu říct.
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Domnívám se, že v tomto případě jde spíše o automaticky generované testy. Což je taky dobrý. Ale typy jsou imho o něčem jiném. Viz ta ukázka https://forum.root.cz/index.php?topic=18804.msg271719#msg271719
Můžeš udělat typy, které se budou checkovat třeba týden. Ale udělat testy na bambilion vstupů budou ještě mnohem horší s horší efektivitou.
Ja to vidim nekde mezi. V clojure (ale i v dalsich lispech) je totiz "write time" = runtime. To znamena, ze kazdy vyraz ktery napisu hned evaluuju a mam ho k dispozici v bezicim REPLu. Takze kdyz treba pisu funkci a jeji specifikaci viz https://clojure.org/guides/spec#_spec_ing_functions (https://clojure.org/guides/spec#_spec_ing_functions) muzu klidne tam kde ji volam pomoci valid? nebo conform overit jestli je dane volani odpovida specifikaci. A kdyz si to budu nechavat instrumentovat abych to nemusel zkouset rucne tak se blizim typovemu systemu. (popravde ja to tak nedelam, ale ja taky uz dneska moc kodu nenapisu...)
To ze z toho generuju testy je side effect, ale velmi prijemny. Podle me to prave preklenuje tu mezeru kterou zpusobuji prakticka omezeni na strane unit testu a typoveho systemu. Tam kde by typova specifikace zacinala byt neprakticka a pri tom nebyla kriticka muzu nechat generator chroustat misto abych ja musel cucat z prstu hodnoty ktere se maji vyzkouset.
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Domnívám se, že v tomto případě jde spíše o automaticky generované testy. Což je taky dobrý. Ale typy jsou imho o něčem jiném. Viz ta ukázka https://forum.root.cz/index.php?topic=18804.msg271719#msg271719
Můžeš udělat typy, které se budou checkovat třeba týden. Ale udělat testy na bambilion vstupů budou ještě mnohem horší s horší efektivitou.
Ja to vidim nekde mezi. V clojure (ale i v dalsich lispech) je totiz "write time" = runtime. To znamena, ze kazdy vyraz ktery napisu hned evaluuju a mam ho k dispozici v bezicim REPLu. Takze kdyz treba pisu funkci a jeji specifikaci viz https://clojure.org/guides/spec#_spec_ing_functions (https://clojure.org/guides/spec#_spec_ing_functions) muzu klidne tam kde ji volam pomoci valid? nebo conform overit jestli je dane volani odpovida specifikaci. A kdyz si to budu nechavat instrumentovat abych to nemusel zkouset rucne tak se blizim typovemu systemu. (popravde ja to tak nedelam, ale ja taky uz dneska moc kodu nenapisu...)
Já jsem to clojure spec viděl zatím jen z rychlíku (princip REPL ale znám). Když si tedy trochu zaspekuluju: buť tam tedy narve kontrolu na typ, něco jako (v jiném jazyce, chápu že v lispu se to zapíše jinak):
fn inc(a):
assert(a, "int:1..100")
...
případně tam můžu narvat klasickej test aka:
fn inc(a):
...
with:
assert inc(1) == 2
assert inc(99) == 100
nebo
fn inc(a):
...
with:
foreach x in datasample.rangeint(1..100):
assert inc(x) == x + 1
Tak nějak?
V prvém případě se to chová jako typ s tím, že blbě vytáhnu signaturu tý funkce (což je ale asi jen otázka řešení toho spec-u, nikoliv principielní problém). V tom druhém a třetím případě je to klasický unittest s výhodami a nevýhodami, které testy mají.
Na druhou stranu je to kompaktní :-)
Výhodu toho spec-u bych viděl v tom, že by měl být deklarativní, tudíž čitelnější než klasické testy, a dají se na to udělat nějaká vizualizovátka, metriky a podobně. Souhlas?
To ze z toho generuju testy je side effect, ale velmi prijemny. Podle me to prave preklenuje tu mezeru kterou zpusobuji prakticka omezeni na strane unit testu a typoveho systemu. Tam kde by typova specifikace zacinala byt neprakticka a pri tom nebyla kriticka muzu nechat generator chroustat misto abych ja musel cucat z prstu hodnoty ktere se maji vyzkouset.
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
Jestli tě chápu dobře - u typů je někdy blbá ta ultimátnost. Že člověku se prostě někdy hodí tu kontrolu vypnout (ve výsledku často zjistí, že to byl blbej nápad, ale což). Nebo že vyžaduje příliš přemýšlení, když potřebuju jen něco vyzkoušet.
-
V prvém případě se to chová jako typ s tím, že blbě vytáhnu signaturu tý funkce (což je ale asi jen otázka řešení toho spec-u, nikoliv principielní problém). V tom druhém a třetím případě je to klasický unittest s výhodami a nevýhodami, které testy mají.
Na druhou stranu je to kompaktní :-)
Podle me spis prvni pripad:
(ns spec-example.core
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest])
(:gen-class))
;; definuju predikat a ulozim do registru => znovupouzitelnost
;; taky je videt ze to hezky komponuje skladam predikat z mensich predikatu
(s/def ::small-pos-int (s/and pos-int? #(<= % 100)))
;; definice funkce
(defn -inc
[a]
(+ a 1))
;; specifikace ktera zatim nic nedela
(s/fdef -inc
:args (s/cat :a ::small-pos-int) ;; validace vstupu
:ret pos-int? ;; validace vystupu
:fn #(> (:ret %) (-> % :args :a))) ;; trivialni a neuplna validace vystupu vzhledem ke vstupum
;; zapnu instrumentaci
;; od ted se budou pred exekuci funkce validovat vstupy
;; :ret a :fn samozrejme vyzaduje aby byla funkce provedena,
;; protoze potrebuju navratovou hodnotu
;; takze to uz spada spis do testu nez do typu
(stest/instrument `-inc)
;; nekde v kodu budu chti funkci pouzit
(let [a 105]
(-inc a))
;; vyhodi mi to:
;; ExceptionInfo Call to #'spec-example.core/-inc did not conform to spec:
;; In: [0] val: 105 fails spec: :spec-example.core/small-pos-int at: [:args :a] predicate: (<= % 100)
;; clojure.core/ex-info (core.clj:4739)
;; drivejsi verze tusim dokonce vyhazovala CompilerException
;; coz mozna jeste vic dava najevo, ze funkce vlastne vubec nebyla spustena
Výhodu toho spec-u bych viděl v tom, že by měl být deklarativní, tudíž čitelnější než klasické testy, a dají se na to udělat nějaká vizualizovátka, metriky a podobně. Souhlas?
Asi uplne nerozumim, ale mozna ze ten priklad na to odpovida sam
To ze z toho generuju testy je side effect, ale velmi prijemny. Podle me to prave preklenuje tu mezeru kterou zpusobuji prakticka omezeni na strane unit testu a typoveho systemu. Tam kde by typova specifikace zacinala byt neprakticka a pri tom nebyla kriticka muzu nechat generator chroustat misto abych ja musel cucat z prstu hodnoty ktere se maji vyzkouset.
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
Cet sem tady na rootu clanek od tisnika o gherkin a domnivam se, ze v budoucnosti budou psat specifikaci testu business analitici ve forme given/when/then a potom uz se toho chytne automat
Jestli tě chápu dobře - u typů je někdy blbá ta ultimátnost. Že člověku se prostě někdy hodí tu kontrolu vypnout (ve výsledku často zjistí, že to byl blbej nápad, ale což). Nebo že vyžaduje příliš přemýšlení, když potřebuju jen něco vyzkoušet.
Spis mam na mysli to premysleni. To nekdy boli.
Takze u nekriticke casti aplikace specifikuju jen do chvile nez to zacne bolet a na zbytek pustim generator testu.
-
(ns spec-example.core
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest])
(:gen-class))
;; definuju predikat a ulozim do registru => znovupouzitelnost
;; taky je videt ze to hezky komponuje skladam predikat z mensich predikatu
(s/def ::small-pos-int (s/and pos-int? #(<= % 100)))
;; definice funkce
(defn -inc
[a]
(+ a 1))
;; specifikace ktera zatim nic nedela
(s/fdef -inc
:args (s/cat :a ::small-pos-int) ;; validace vstupu
:ret pos-int? ;; validace vystupu
:fn #(> (:ret %) (-> % :args :a))) ;; trivialni a neuplna validace vystupu vzhledem ke vstupum
;; zapnu instrumentaci
;; od ted se budou pred exekuci funkce validovat vstupy
;; :ret a :fn samozrejme vyzaduje aby byla funkce provedena,
;; protoze potrebuju navratovou hodnotu
;; takze to uz spada spis do testu nez do typu
(stest/instrument `-inc)
;; nekde v kodu budu chti funkci pouzit
(let [a 105]
(-inc a))
;; vyhodi mi to:
;; ExceptionInfo Call to #'spec-example.core/-inc did not conform to spec:
;; In: [0] val: 105 fails spec: :spec-example.core/small-pos-int at: [:args :a] predicate: (<= % 100)
;; clojure.core/ex-info (core.clj:4739)
;; drivejsi verze tusim dokonce vyhazovala CompilerException
;; coz mozna jeste vic dava najevo, ze funkce vlastne vubec nebyla spustena
Budu se muset do toho spec-u ponořit. Díky za inspiraci.
-
Jestli tě chápu dobře - u typů je někdy blbá ta ultimátnost.
A co je to vlastně ta "ultimátnost"? S tím slovem jsem se ještě nesetkal.
-
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
Jednotkové testy, tedy alespoň jejich boilerplates, ve Vimu generuji už dávno. Podobně mi generuje i signatury v Haskellu. Není třeba čekat na budoucnost.
-
Sorry, ale za to zatrollení diskuze si můžeš IMO primárně sám. Většina téhle diskuze je o tom, že ostatní šijou do tvých kategorických tvrzení.
Ale no tak!
Takže když napíšu "Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém." je to přes čáru? A místní smetánka, která věci sice nerozumí, ale má tím pádem právo mě trollit? To jako vážně?!
Není to přes čáru. Je to názor, o kterém tu polemizujeme. Z opačné strany je můj názor, že statický typový systém není potřebný, pokud mám kvalitní testování. Pokud je někdo přesvědčen o svém názoru, musí být připraven na protiargumenty oponentů. Prohrává ten, kdo svého oponenta začne ponižovat, protože to je jasným důkazem, že mu došly argumenty.
-
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
Jednotkové testy, tedy alespoň jejich boilerplates, ve Vimu generuji už dávno.
A pak je mažeš?
-
Pokud je někdo přesvědčen o svém názoru, musí být připraven na protiargumenty oponentů. Prohrává ten, kdo svého oponenta začne ponižovat, protože to je jasným důkazem, že mu došly argumenty.
Když začnu oponenta ponižovat ukazuje to nedostatek mého charakteru. Třeba nedostatek sebeovládání.
A jsou i jiné důvody, proč člověk vzdá diskusi, než jen to, že by došli argumenty.
-
Pokud je někdo přesvědčen o svém názoru, musí být připraven na protiargumenty oponentů. Prohrává ten, kdo svého oponenta začne ponižovat, protože to je jasným důkazem, že mu došly argumenty.
Když začnu oponenta ponižovat ukazuje to nedostatek mého charakteru. Třeba nedostatek sebeovládání.
A jsou i jiné důvody, proč člověk vzdá diskusi, než jen to, že by došli argumenty.
Když vzdáš diskuzi, tak to ještě nemusí být prohra. Prostě jste se nedobrali konsenzu, to se stává.
-
Jestli tě chápu dobře - u typů je někdy blbá ta ultimátnost.
A co je to vlastně ta "ultimátnost"? S tím slovem jsem se ještě nesetkal.
Asi takhle. Pomocí testů můžeš otestovat pár vhodných případů, ale nemůžeš otestovat všechny. Nejen, že by si se upsal, ale u negativních to třeba vůbec nejde (https://forum.root.cz/index.php?topic=18804.msg271719#msg271719). Pomocí typů zajistíš naprosto bez výjimky všechny případy.
-
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
Jednotkové testy, tedy alespoň jejich boilerplates, ve Vimu generuji už dávno.
A pak je mažeš?
Ne. Stávají se součástí dokumentace. Pouze je rozšiřuji a modifikuji, aby lépe testovaly okrajové stavy a různé výjimky.
-
Asi takhle. Pomocí testů můžeš otestovat pár vhodných případů, ale nemůžeš otestovat všechny. Nejen, že by si se upsal, ale u negativních to třeba vůbec nejde (https://forum.root.cz/index.php?topic=18804.msg271719#msg271719). Pomocí typů zajistíš naprosto bez výjimky všechny případy.
Testy na negativní případy se naopak píší zcela běžně, podle mne dokonce převažují nad pozitivními případy. Pokud metoda má vyhazovat tři výjimky při chybných vstupech, musím otestovat všechny.
-
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
Jednotkové testy, tedy alespoň jejich boilerplates, ve Vimu generuji už dávno.
A pak je mažeš?
Ne. Stávají se součástí dokumentace.
Tak to pak není to co mám na mysli.
Moje prognóza je, že IDE (nebo jakýkoliv jiný nástroj) perfektně rozumí kódu a je schopen na požádání vygenerovat ukázky kódu. Žádný další smysl nemají. Tudíž nebude mít smysl je uchovávat.
-
Asi takhle. Pomocí testů můžeš otestovat pár vhodných případů, ale nemůžeš otestovat všechny. Nejen, že by si se upsal, ale u negativních to třeba vůbec nejde (https://forum.root.cz/index.php?topic=18804.msg271719#msg271719). Pomocí typů zajistíš naprosto bez výjimky všechny případy.
Testy na negativní případy se naopak píší zcela běžně, podle mne dokonce převažují nad pozitivními případy. Pokud metoda má vyhazovat tři výjimky při chybných vstupech, musím otestovat všechny.
Ty chybné vstupy nejsu tři, ale nekonečno.
Můžeš si všimnout, že v mém příspěvku nepíši o tom, že by se negativní testy nepsali vůbec.
-
Moje prognóza je, že IDE (nebo jakýkoliv jiný nástroj) perfektně rozumí kódu a je schopen na požádání vygenerovat ukázky kódu. Žádný další smysl nemají. Tudíž nebude mít smysl je uchovávat.
To není problém, protože už v první fázi překladu získáš derivační strom, který je základem pro jeho pochopení strojem. Když to interpretuješ jiným derivačním stromem, dostaneš výslednou aplikaci nebo testy. Dosud se však nevyplatilo vytváření derivačního stromu pro generování testů, neboť se do něj stejně musí doplnit okrajové podmínky.
V praxi to pak bude vypadat tak, že v záhlaví testované metody budou definovány tyto okrajové podmínky. Pak už nebude nutné testy generovat do dalších souborů, ale budou se přímo interpretovat z těchto záhlaví. Přiblíží se tak k typovým signaturám, ale budou dokonalejší. Pro některé jazyky to už více či méně funguje.
-
Přiblíží se tak k typovým signaturám, ale budou dokonalejší. Pro některé jazyky to už více či méně funguje.
Tak, o tom to celé je.
-
Jinak tohle neznám, ale co jsem pochopil, tak je to automatické dokazování některých vlastností (refinement types)..
https://ucsd-progsys.github.io/liquidhaskell-blog/ (https://ucsd-progsys.github.io/liquidhaskell-blog/)
-
Jinak tohle neznám, ale co jsem pochopil, tak je to automatické dokazování některých vlastností (refinement types)..
https://ucsd-progsys.github.io/liquidhaskell-blog/ (https://ucsd-progsys.github.io/liquidhaskell-blog/)
Hezký, díky.
-
Jestli tě chápu dobře - u typů je někdy blbá ta ultimátnost.
A co je to vlastně ta "ultimátnost"? S tím slovem jsem se ještě nesetkal.
Takové slovo vůbec neexistuje.
Ultimus znamená latinsky poslední.
-
Jestli tě chápu dobře - u typů je někdy blbá ta ultimátnost.
A co je to vlastně ta "ultimátnost"? S tím slovem jsem se ještě nesetkal.
Takové slovo vůbec neexistuje.
Ultimus znamená latinsky poslední.
He, to jsem ani netušil :-)
-
Jinak tohle neznám, ale co jsem pochopil, tak je to automatické dokazování některých vlastností (refinement types)..
https://ucsd-progsys.github.io/liquidhaskell-blog/ (https://ucsd-progsys.github.io/liquidhaskell-blog/)
Hezký, díky.
připomělo mi to tohle https://github.com/hwayne/lets-prove-leftpad
verze v idrisu je zajímavě stručná
-
Jak nahradim unit test, kdyz chci otestovat funkci pro vypocet kvadraticke rovnice a spletu se ve vzorci?
Typovy system mi moc nepomuze, ne?
-
Jak nahradim unit test, kdyz chci otestovat funkci pro vypocet kvadraticke rovnice a spletu se ve vzorci?
Typovy system mi moc nepomuze, ne?
Možná by stačilo vypočtené kořeny dosadit do té kvadratické rovnice, což snad půjde také provést v těch typech.
-
Jak nahradim unit test, kdyz chci otestovat funkci pro vypocet kvadraticke rovnice a spletu se ve vzorci?
Typovy system mi moc nepomuze, ne?
Možná by stačilo vypočtené kořeny dosadit do té kvadratické rovnice, což snad půjde také provést v těch typech.
Nevím, jak dobře půjde symbolicky kontrolovat floatové výpočty. Má to vycházet pro ideální reálná čísla, nebo pro floaty včetně nekonečen a nanů? A s jakou přesností?
-
Jak nahradim unit test, kdyz chci otestovat funkci pro vypocet kvadraticke rovnice a spletu se ve vzorci?
Typovy system mi moc nepomuze, ne?
Možná by stačilo vypočtené kořeny dosadit do té kvadratické rovnice, což snad půjde také provést v těch typech.
Jenže kompilátor neví nic o kvadratických rovnicích, takže to z typů nijak neodvodí. Ale to je právě ten spor, který tady vedeme – existují určité doménové znalosti, a část z nich je přenesena do kódu, ať už v podobě příkazů nebo pravidel. Jednotkové testy nejsou nic jiného, než snaha nezávislým způsobem ověřit, že jsou ty doménové znalosti přenesené do kódu správně. Vedlejším efektem těchto testů je, že se zkontroluje, zda vůbec dává smysl kód sám o sobě – jestli se třeba nepokouší provádět nedefinovanou operaci (třeba násobení textů nebo dělení nulou). Někteří zde ovšem tento vedlejší efekt testů považují za jejich hlavní a jediný účel, z čehož plyne jejich přesvědčení, že by se jednotkové testy vlastně daly úplně zrušit.
Mimochodem, k představě, že všechny jednotkové testy bude umět vytvořit nějaký automat, je vhodné dodat, že až ten automat bude umět pochopit danou doménu a napsat testy, bude umět naprogramovat i ten výkonný kód.
-
Jak nahradim unit test, kdyz chci otestovat funkci pro vypocet kvadraticke rovnice a spletu se ve vzorci?
Typovy system mi moc nepomuze, ne?
Možná by stačilo vypočtené kořeny dosadit do té kvadratické rovnice, což snad půjde také provést v těch typech.
v celých číslech si to docela umím představit (sčítání a násobení je jednoduché, už jsem tu dával odkaz, několikrát), s reálnýma si to představit už neumím :)
-
Jak nahradim unit test, kdyz chci otestovat funkci pro vypocet kvadraticke rovnice a spletu se ve vzorci?
Typovy system mi moc nepomuze, ne?
Možná by stačilo vypočtené kořeny dosadit do té kvadratické rovnice, což snad půjde také provést v těch typech.
v celých číslech si to docela umím představit (sčítání a násobení je jednoduché, už jsem tu dával odkaz, několikrát), s reálnýma si to představit už neumím :)
S reálnými čísly by to šlo taky, pokud by program skutečně pracoval s reálnými hodnotami. S něčím takovým jsem se setkal pouze u analogového počítače, což už je docela historie.
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Nepopisujete nic jiného než obdobu typového systému či jednotkového testu - z popisu nejde pozdnat, čemu je to blíže. Představa, že za vás nějaký jednoduchý systém bezpracně otestuje funkcionalitu, je nesmyslná.
-
S reálnými čísly by to šlo taky, pokud by program skutečně pracoval s reálnými hodnotami. S něčím takovým jsem se setkal pouze u analogového počítače, což už je docela historie.
Co přesně myslíš těma "reálnýma hodnotama"? I analogové počítače měly jenom omezenou přesnost, takže i tam může nastat ztráta přesnosti.
-
S reálnými čísly by to šlo taky, pokud by program skutečně pracoval s reálnými hodnotami. S něčím takovým jsem se setkal pouze u analogového počítače, což už je docela historie.
Co přesně myslíš těma "reálnýma hodnotama"? I analogové počítače měly jenom omezenou přesnost, takže i tam může nastat ztráta přesnosti.
Správně. V tom případě mohu s klidným svědomím prohlásit, že současné počítače s reálnými čísly nepracují. Pouze s čísly celými a racionálními. Racionální čísla jsou podílem celých čísel. Že se používají pojmy integer, decimal, float nebo complex znamená jen to, že jsme je potřebovali rozlišit v dřevních dobách, kdy se šetřilo každým bajtem. Dnešní programy však už umí pracovat s racionálními čísly téměř s neomezenou přesností. Otázkou však zůstává, k čemu by to bylo.
-
V praxi to pak bude vypadat tak, že v záhlaví testované metody budou definovány tyto okrajové podmínky. Pak už nebude nutné testy generovat do dalších souborů, ale budou se přímo interpretovat z těchto záhlaví. Přiblíží se tak k typovým signaturám, ale budou dokonalejší. Pro některé jazyky to už více či méně funguje.
To jako toto? https://en.wikipedia.org/wiki/Design_by_contract (https://en.wikipedia.org/wiki/Design_by_contract) To je jen chytřejší variantou jednoduchých typů. Jednotkové testy tím nejde nahradit, protože tím nejde udělat test "když je na vstupu něco, bude na výstupu něco".
-
Jenže kompilátor neví nic o kvadratických rovnicích, takže to z typů nijak neodvodí. Ale to je právě ten spor, který tady vedeme – existují určité doménové znalosti, a část z nich je přenesena do kódu, ať už v podobě příkazů nebo pravidel. Jednotkové testy nejsou nic jiného, než snaha nezávislým způsobem ověřit, že jsou ty doménové znalosti přenesené do kódu správně. Vedlejším efektem těchto testů je, že se zkontroluje, zda vůbec dává smysl kód sám o sobě – jestli se třeba nepokouší provádět nedefinovanou operaci (třeba násobení textů nebo dělení nulou). Někteří zde ovšem tento vedlejší efekt testů považují za jejich hlavní a jediný účel, z čehož plyne jejich přesvědčení, že by se jednotkové testy vlastně daly úplně zrušit.
Mimochodem, k představě, že všechny jednotkové testy bude umět vytvořit nějaký automat, je vhodné dodat, že až ten automat bude umět pochopit danou doménu a napsat testy, bude umět naprogramovat i ten výkonný kód.
Tento komentář považuju za shrnující. Nenapadá mě, co dodat.
-
Jenže kompilátor neví nic o kvadratických rovnicích, takže to z typů nijak neodvodí. Ale to je právě ten spor, který tady vedeme – existují určité doménové znalosti, a část z nich je přenesena do kódu, ať už v podobě příkazů nebo pravidel. Jednotkové testy nejsou nic jiného, než snaha nezávislým způsobem ověřit, že jsou ty doménové znalosti přenesené do kódu správně. Vedlejším efektem těchto testů je, že se zkontroluje, zda vůbec dává smysl kód sám o sobě – jestli se třeba nepokouší provádět nedefinovanou operaci (třeba násobení textů nebo dělení nulou). Někteří zde ovšem tento vedlejší efekt testů považují za jejich hlavní a jediný účel, z čehož plyne jejich přesvědčení, že by se jednotkové testy vlastně daly úplně zrušit.
Mimochodem, k představě, že všechny jednotkové testy bude umět vytvořit nějaký automat, je vhodné dodat, že až ten automat bude umět pochopit danou doménu a napsat testy, bude umět naprogramovat i ten výkonný kód.
Tento komentář považuju za shrnující. Nenapadá mě, co dodat.
naopak by šlo ubrat, stačila by jenom první věta
-
V praxi to pak bude vypadat tak, že v záhlaví testované metody budou definovány tyto okrajové podmínky. Pak už nebude nutné testy generovat do dalších souborů, ale budou se přímo interpretovat z těchto záhlaví. Přiblíží se tak k typovým signaturám, ale budou dokonalejší. Pro některé jazyky to už více či méně funguje.
To jako toto? https://en.wikipedia.org/wiki/Design_by_contract (https://en.wikipedia.org/wiki/Design_by_contract) To je jen chytřejší variantou jednoduchých typů. Jednotkové testy tím nejde nahradit, protože tím nejde udělat test "když je na vstupu něco, bude na výstupu něco".
Ne, v daném případě mám na mysli tohle:
<?php
class Calculator {
/**
* @assert (0, 0) == 0
* @assert (3, 5) == 8
* @assert (-3, 5) == 2
* @assert (3, -5) == -2
* @assert (-3, -5) == 8
*/
public function sum($a, $b) {
return $a + $b;
}
}
Z tohoto kódu se dnes běžně generují testy, ovšem stejně dobře se z toho dají přímo interpretovat.
-
Správně. V tom případě mohu s klidným svědomím prohlásit, že současné počítače s reálnými čísly nepracují. Pouze s čísly celými a racionálními. Racionální čísla jsou podílem celých čísel. Že se používají pojmy integer, decimal, float nebo complex znamená jen to, že jsme je potřebovali rozlišit v dřevních dobách, kdy se šetřilo každým bajtem. Dnešní programy však už umí pracovat s racionálními čísly téměř s neomezenou přesností. Otázkou však zůstává, k čemu by to bylo.
No ale o to mi jde. Jak pak ten typový systém může porovnávat nějaké výpočty? Jak může zkontrolovat že nějaký vzoreček tu kvadratickou rovnici opravdu řeší? Symbolickým dosazováním nějaké katastrofické krácení neodhalí.
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Nepopisujete nic jiného než obdobu typového systému či jednotkového testu - z popisu nejde pozdnat, čemu je to blíže. Představa, že za vás nějaký jednoduchý systém bezpracně otestuje funkcionalitu, je nesmyslná.
Nechapu. Prece tam sam pisu ze je to neco jako typovy system. A nemam ani zminovanou predstavu.
-
Jenže kompilátor neví nic o kvadratických rovnicích, takže to z typů nijak neodvodí
Ale kompilátor může vědět něco o symbolické matematice a nějaké další matematické axiomy ho můžeme naučit. Pokud bychom měli typový systém, který by uměl symolickou matematiku, tak jaký je problém napsat něco typu:
resKvadRovnici :: a : Num -> b : Num -> c : Num -> [x] | a * x^2 + b * x + c * x = 0
A systémy, které umí symbolickou matematiku tady máme a když se jich zeptáme, jestli daný vzoreček řeší kvadratickou rovnici, tak jsou schopny na to dát jasnou odpověď. Ne vždycky (halting problem), ale o to nejde.
Konec konců, ten příklad s leftPad je moc hezký - copak typový systém ví něco o zarovnávání z leva? Ale dá se mu to vysvětlit.
Ale myslím, že je trošku nepochopení, k čemu typový systém je. Byl tady dotaz, že jak testovat v tom mém příkladu, že u:
Num op a b = op a b
nedošlo k prohození "a" a b". Jenomže to jde otestovat leda tak, že se napíše specifikace, která bude vypadat přesně stejně. Takže se problém chyby přesune od kódu ke specifikaci a vůbec nic to nevyřeší, jen místo toho, zda kód je správně budeme řešit, jestli specifikace je správně. IMO typový systém (nebo obecně dokazování) má smysl tam, kde specifikace a kód není totéž. Ale jinak bych zopakoval, že u všech těchto věcí (testy, typy) je vhodné si položit otázku, zda se to vyplatí - a při dobrém využití typů (na doméně, kde to funguje dobře) výhoda těch testů dost klesá, protože těch chyb je tam z principu výrazně méně.
-
Ne, v daném případě mám na mysli tohle:
<?php
class Calculator {
/**
* @assert (0, 0) == 0
* @assert (3, 5) == 8
* @assert (-3, 5) == 2
* @assert (3, -5) == -2
* @assert (-3, -5) == 8
*/
public function sum($a, $b) {
return $a + $b;
}
}
Z tohoto kódu se dnes běžně generují testy, ovšem stejně dobře se z toho dají přímo interpretovat.
Supr, tak se začínáme blížit k těm jednotkovým testům, ale ještě tam nejsme, protože tato notace neřeší stav objektu, na kterém je výsledek té metody/funkce závislý (myšleno obecně, ne této triviální funkcičky). Generátor Rand tím taky neotestujete.
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Nepopisujete nic jiného než obdobu typového systému či jednotkového testu - z popisu nejde pozdnat, čemu je to blíže. Představa, že za vás nějaký jednoduchý systém bezpracně otestuje funkcionalitu, je nesmyslná.
Nechapu. Prece tam sam pisu ze je to neco jako typovy system. A nemam ani zminovanou predstavu.
Ale ten my už máme, teď potřebujeme nějaký lepší (ale snesitelně složitý!), ze kterého si sedneme na pr-del a zavrhneme jednotkové testy jako překonané (na to se přece v této diskusi čeká).
Hromadná kontrola se dá udělat několika způsoby:
- ručně tam ty páry vstup-výstup naboucháte - to nechcete
- použijete data driven testing, to je ale to samé, protože to taky odněkud ta data potřebuje získat - taky k hovnu
- znovuimplementujete výpočet stejně - bude to tentokrát bezchybné?
- znovuimplementujete výpočet jinak - to samé jako výše
Takže s tou o řád vyšší kvalitou protestování bych byl opatrný.
-
Supr, tak se začínáme blížit k těm jednotkovým testům, ale ještě tam nejsme, protože tato notace neřeší stav objektu, na kterém je výsledek té metody/funkce závislý (myšleno obecně, ne této triviální funkcičky). Generátor Rand tím taky neotestujete.
Tohle je jen primitivní ukázka, jak se dají jednotkové testy vložit do jazyka, který s nimi původně vůbec nepočítal. Tahle testuje bezstavovou metodu. Není to test jednotkový, ale vývojářský. Podobný test, tentokrát jednotkový a stavový, se dá vložit do záhlaví třídy. Nevýhodou tohoto řešení však je, že testy bývají zhruba 2× delší než produkční kód, po kompilaci na produkci v něm stále překáží - jsou součástí binárky.
V Javě je to o něco lepší - tam se dá test vložit přes statickou vnitřní třídu, která však do produkce nejde. Ovšem už se to nepodobá zmíněným typům.
-
Ale kompilátor může vědět něco o symbolické matematice a nějaké další matematické axiomy ho můžeme naučit.
Ano, některé věci můžeme schovat do knihoven a knihovny klidně do kompilátoru nebo až do procesoru. Ty pak bereme za dané a podle míry jejich složitosti už je ani netestujeme. Programátoři dnes obvykle neprogramují, jak sečíst dvě 32bitová čísla, ale spoléhají na to, že to instrukce procesoru děla správně. Pořád je ale potřeba programátor na to, aby procesoru „vysvětlil“, že když má v jednom registru částku a v druhém registru DPH, cenu s DPH spočítá právě sečtením těch dvou registrů.
A systémy, které umí symbolickou matematiku tady máme a když se jich zeptáme, jestli daný vzoreček řeší kvadratickou rovnici, tak jsou schopny na to dát jasnou odpověď. Ne vždycky (halting problem), ale o to nejde.
Ano, ale k tomu musíme umět tou symbolickou matematikou popsat, co je to kvadratická rovnice. A pokud tomu systému popíšu kvadratickou rovnici jako součet násobku druhé mocniny proměnné a násobku proměnné, tj. zapomenu na to, že v kvadratické rovnici může být také konstanta, ten systém to nijak nezjistí. V systému symbolické matematiky je taková rovnice možná, je to podmnožina kvadratických rovnic. A není to chyba toho systému ani odvozování, je to chyba v převodu mezi reálným světem a formálním jazykem (v tomto případě symbolickou matematikou).
Konec konců, ten příklad s leftPad je moc hezký - copak typový systém ví něco o zarovnávání z leva? Ale dá se mu to vysvětlit.
Ano, naprogramovat se dá leccos, i mnohem složitější věci, než je zarovnávání zleva :-) A jsou různé způsoby, jak to naprogramovat, dá se to naprogramovat imperativně i deklarativně a je to vzájemně převoditelné. Rozdíl není na straně počítače (i když fakticky se nakonec vše převádí na imperativní, protože tak pracují dnešní procesory), rozdíl je na straně lidí – některé věci se nám lépe vyjadřují deklarativně, některé raději vyjadřujeme imperativně.
Ale myslím, že je trošku nepochopení, k čemu typový systém je.
Taky si myslím. Typový systém je jen jiný způsob vyjádření, nic míň, ale ani nic víc.
Jenomže to jde otestovat leda tak, že se napíše specifikace, která bude vypadat přesně stejně. Takže se problém chyby přesune od kódu ke specifikaci a vůbec nic to nevyřeší, jen místo toho, zda kód je správně budeme řešit, jestli specifikace je správně.
Ano, to tvrdím od začátku. Takhle se to ale dá odsouvat do nekonečna, a o správnosti se nedozvíme nikdy nic. Proto se často testuje to, že vezmu něco mnohem jednoduššího, než specifikaci, o čem ale vím, že je to správně, a otestuju jenom tyhle zaručeně správné případy. Tím nezískám odpověď na otázku, zda je to celé správně, ale dozvím se alespoň to, že tam je aspoň něco správně.
IMO typový systém (nebo obecně dokazování) má smysl tam, kde specifikace a kód není totéž. Ale jinak bych zopakoval, že u všech těchto věcí (testy, typy) je vhodné si položit otázku, zda se to vyplatí - a při dobrém využití typů (na doméně, kde to funguje dobře) výhoda těch testů dost klesá, protože těch chyb je tam z principu výrazně méně.
A stejně tak existují domény, kde nesou potřeba žádné složité typy a kde zároveň největší množství chyb vzniká při převodu mezi neformálním zadáním a formálním programovacím jazykem. A tam je zase minimum chyb, které by bylo možné odstranit lepšími typy.
-
Halting problem se týká univerzálního algoritmu který by dokázal pro jakýkoliv program s jakýmkoliv vstupem rozhodnout, zda dokončí nebo nedokončí běh. Turing nikdy neřekl, že neexistuje algoritmus, který by pro konkrétní program nedokázal rozhodnout, zda dokončí či nedokončí. To je velký rozdíl.
Zjevně jsi nepřečetl ten odstavec, který jsem doporučoval:
The halting problem is theoretically decidable for linear bounded automata (LBAs) or deterministic machines with finite memory. Minsky warns us, however, that machines such as computers with e.g., a million small parts, each with two states, will have at least 21,000,000 possible states: This is a 1 followed by about three hundred thousand zeroes ... Even if such a machine were to operate at the frequencies of cosmic rays, the aeons of galactic evolution would be as nothing compared to the time of a journey through such a cycle.
V dněšních počítačích a běžných programech je těch stavů ještě o mnoho řádů více. Mnoho štěstí s testováním.
A drtivá většina z těch stavů je irrelevantních nebo je lze považovat za víceméně duplicity.
Při testování mne typicky nezajímá, jestli je program otestován při kompilaci na na adresu 0, na adresu 1, na adresu 2 nebo na adresu 10000000. Stejně tak mne nezajímá, jestli je o testován na jádru 1, na jádru 2, nebo kam nahrál OS runtime knihovny. Zajímají mne stavy možné v doméně jazyka v kterém programuji.
Jiný příklad je ten random(), ten se taky netestuje výčtem stavů, ale tím že na vzorku pustím statistické testy. Překvapivě to funguje, i když podle vás by nemělo.
-
Proto me se libi treba clojure.spec. I kdyz je clojure dynamicky jazyk tak spec mu pridava neco jako "velmi silny typovy system" (Neni to primo v jazyku takze jsou potreba nejake nastroje na instrumentaci, proto "neco jako"). A krasne to integruje s testcheckem takze tomu muzu rict aby se pri buildu nahodne vygenerovalo bambilion vstupu odpovidajicich SPECifikaci a projelo se to funkci a vyhodnotilo jestli vystup taky odpovida specifikaci(a do znacne miry i jestli je spravne vzhledem ke konkretnim vstupum). Takze nemusim napsat jedinny unit test a mam pokryto radove lepe nez s unit testy.
Nepopisujete nic jiného než obdobu typového systému či jednotkového testu - z popisu nejde pozdnat, čemu je to blíže. Představa, že za vás nějaký jednoduchý systém bezpracně otestuje funkcionalitu, je nesmyslná.
Nechapu. Prece tam sam pisu ze je to neco jako typovy system. A nemam ani zminovanou predstavu.
Ale ten my už máme, teď potřebujeme nějaký lepší (ale snesitelně složitý!), ze kterého si sedneme na pr-del a zavrhneme jednotkové testy jako překonané (na to se přece v této diskusi čeká).
Hromadná kontrola se dá udělat několika způsoby:
- ručně tam ty páry vstup-výstup naboucháte - to nechcete
- použijete data driven testing, to je ale to samé, protože to taky odněkud ta data potřebuje získat - taky k hovnu
- znovuimplementujete výpočet stejně - bude to tentokrát bezchybné?
- znovuimplementujete výpočet jinak - to samé jako výše
Takže s tou o řád vyšší kvalitou protestování bych byl opatrný.
Myslim, ze u rady problemu je overeni spravnosti vypoctu trivialni kdezto vypocet samotny je slozity.
A kdyz zakomponuju overeni spravnosti do konstrukce navratoveho typu zarucim tim ze nepujde vytvorit navratovy typ obsahujici nespravny vysledek.
Ano je to v podstate znovuimplementace jinak, a da se v tom taky udelat chyba, ale pokud je to overeni opravdu radove jednodussi dava mi to vetsi smysl, nez napsat par testu rucne.
-
Myslim, ze u rady problemu je overeni spravnosti vypoctu trivialni kdezto vypocet samotny je slozity.
A kdyz zakomponuju overeni spravnosti do konstrukce navratoveho typu zarucim tim ze nepujde vytvorit navratovy typ obsahujici nespravny vysledek.
Jistě existuje řada takových problémů, ale podle mne se to netýká drtivé většiny problémů řešených dnešními programy. Navíc to ověření správnosti zabere nějaký výkon za běhu – lepší je (obvykle) ověřit správnost v době vytváření programu a za běhu se už jen spoléhat na to, že to prostě je správně.
-
....
Jenže kompilátor neví nic o kvadratických rovnicích, takže to z typů nijak neodvodí. Ale to je právě ten spor, který tady vedeme – existují určité doménové znalosti, a část z nich je přenesena do kódu, ať už v podobě příkazů nebo pravidel. Jednotkové testy nejsou nic jiného, než snaha nezávislým způsobem ověřit, že jsou ty doménové znalosti přenesené do kódu správně. Vedlejším efektem těchto testů je, že se zkontroluje, zda vůbec dává smysl kód sám o sobě – jestli se třeba nepokouší provádět nedefinovanou operaci (třeba násobení textů nebo dělení nulou). Někteří zde ovšem tento vedlejší efekt testů považují za jejich hlavní a jediný účel, z čehož plyne jejich přesvědčení, že by se jednotkové testy vlastně daly úplně zrušit.
Mimochodem, k představě, že všechny jednotkové testy bude umět vytvořit nějaký automat, je vhodné dodat, že až ten automat bude umět pochopit danou doménu a napsat testy, bude umět naprogramovat i ten výkonný kód.
+1
(obdivuji Tvou trpělivost)
-
...
A kdyz zakomponuju overeni spravnosti do konstrukce navratoveho typu zarucim tim ze nepujde vytvorit navratovy typ obsahujici nespravny vysledek.
Huh?
Ano je to v podstate znovuimplementace jinak, ...
Asi tak.
-
Tak já se obecně domnívám, že ruční psaní unittestů je jen mezistupeň a v budocnosti to nahradí automatika.
nebo automatika nahradí psaní programů a zůstane jen psaní testů (generování testových dat), ze kterých se budou učit neuronové sítě.
-
Mimochodem, k představě, že všechny jednotkové testy bude umět vytvořit nějaký automat, je vhodné dodat, že až ten automat bude umět pochopit danou doménu a napsat testy, bude umět naprogramovat i ten výkonný kód.
Což je cíl, ke kterému směřujeme.
-
Ale myslím, že je trošku nepochopení, k čemu typový systém je. Byl tady dotaz, že jak testovat v tom mém příkladu, že u:
Num op a b = op a b
nedošlo k prohození "a" a b".
Nutno zopakovat, že to, že došlo k prohození "a" a "b" se v Typu neopodchytí, stejně jako se nepodchytí toto prohození v Unittestech. Tudíž vzhledem k námětu tohoto vlákna je tento dotaz irelevantní.
-
Ale kompilátor může vědět něco o symbolické matematice a nějaké další matematické axiomy ho můžeme naučit.
Ano, některé věci můžeme schovat do knihoven a knihovny klidně do kompilátoru nebo až do procesoru. Ty pak bereme za dané a podle míry jejich složitosti už je ani netestujeme. Programátoři dnes obvykle neprogramují, jak sečíst dvě 32bitová čísla, ale spoléhají na to, že to instrukce procesoru děla správně. Pořád je ale potřeba programátor na to, aby procesoru „vysvětlil“, že když má v jednom registru částku a v druhém registru DPH, cenu s DPH spočítá právě sečtením těch dvou registrů.
Nějak jsem nepochopil, co to má společného s tím, že když naučíme compiler pracovat se symbolickou matematikou, tak pro něj není problém odvodit, že standardní řešení kvadratické rovnice splňuje specifikace požadovanou po té funkci. Je to asi tak na stejné úrovni, jako že ten Liquid haskell je pro (některé) programy schopen dovodit, že výsledkem funkce je neprázdné pole.
Takže reakce na tebe:
Jenže kompilátor neví nic o kvadratických rovnicích, takže to z typů nijak neodvodí.
Kompilátor, který neví nic o kvadratických rovnicích, ale umí pracovat s matematickými výrazy (nepovažoval bych za vyloučené, že by tím směrem ty idrisy a spol. ohnout šly), je schopen dokázat, že daná funkce tu kvadratickou rovnici řeší.
-
Ale myslím, že je trošku nepochopení, k čemu typový systém je. Byl tady dotaz, že jak testovat v tom mém příkladu, že u:
Num op a b = op a b
nedošlo k prohození "a" a b".
Nutno zopakovat, že to, že došlo k prohození "a" a "b" se v Typu neopodchytí, stejně jako se nepodchytí toto prohození v Unittestech. Tudíž vzhledem k námětu tohoto vlákna je tento dotaz irelevantní.
Jednotkové testy to právě odhalí velmi rychle už při odečítání.
-
Ale myslím, že je trošku nepochopení, k čemu typový systém je. Byl tady dotaz, že jak testovat v tom mém příkladu, že u:
Num op a b = op a b
nedošlo k prohození "a" a b".
Nutno zopakovat, že to, že došlo k prohození "a" a "b" se v Typu neopodchytí, stejně jako se nepodchytí toto prohození v Unittestech. Tudíž vzhledem k námětu tohoto vlákna je tento dotaz irelevantní.
Jednotkové testy to právě odhalí velmi rychle už při odečítání.
Narážíš-li na komutativitu, tak tímto způsobem to zase odhalí i Typ.
-
Ale myslím, že je trošku nepochopení, k čemu typový systém je. Byl tady dotaz, že jak testovat v tom mém příkladu, že u:
Num op a b = op a b
nedošlo k prohození "a" a b".
Nutno zopakovat, že to, že došlo k prohození "a" a "b" se v Typu neopodchytí, stejně jako se nepodchytí toto prohození v Unittestech. Tudíž vzhledem k námětu tohoto vlákna je tento dotaz irelevantní.
Jednotkové testy to právě odhalí velmi rychle už při odečítání.
Narážíš-li na komutativitu, tak tímto způsobem to zase odhalí i Typ.
Jak ten typ bude vypadat?
-
Myslim, ze u rady problemu je overeni spravnosti vypoctu trivialni kdezto vypocet samotny je slozity.
A kdyz zakomponuju overeni spravnosti do konstrukce navratoveho typu zarucim tim ze nepujde vytvorit navratovy typ obsahujici nespravny vysledek.
Jistě existuje řada takových problémů, ale podle mne se to netýká drtivé většiny problémů řešených dnešními programy. Navíc to ověření správnosti zabere nějaký výkon za běhu – lepší je (obvykle) ověřit správnost v době vytváření programu a za běhu se už jen spoléhat na to, že to prostě je správně.
Ten prispevek je prece o generativnim testovani u dynamicky typovaneho jazyka.
Za behu prece nebudu zapinat "typovou" instrumentaci.
-
Narážíš-li na komutativitu, tak tímto způsobem to zase odhalí i Typ.
Jak ten typ bude vypadat?
Přiznávám se bez mučení, že zde mé znalosti končí. Ale mám rámcovou představu, jak by to mělo jít: pokud vím, že operátor sčítání je, a operátor odčítání není komutativní, tak IMHO není problém to kompilátoru říct. Jak konkrétně by se to zapsalo, to netuším. Mám toho ještě hodně k nastudování.
-
Nějak jsem nepochopil, co to má společného s tím, že když naučíme compiler pracovat se symbolickou matematikou, tak pro něj není problém odvodit, že standardní řešení kvadratické rovnice splňuje specifikace požadovanou po té funkci. Je to asi tak na stejné úrovni, jako že ten Liquid haskell je pro (některé) programy schopen dovodit, že výsledkem funkce je neprázdné pole.
Jenom jsem upřesnil, že to, co popisujete, je jenom vytčení něčeho jednoduchého do knihovny nebo kompilátoru, které pak jako programátor používáte už bez testování. To ale není nic nového. Takhle už máte něco implementováno třeba v C kompilátoru nebo standardní knihovně – a ty implementace se zase testují.
Kompilátor, který neví nic o kvadratických rovnicích, ale umí pracovat s matematickými výrazy (nepovažoval bych za vyloučené, že by tím směrem ty idrisy a spol. ohnout šly), je schopen dokázat, že daná funkce tu kvadratickou rovnici řeší.
Ne, kompilátor není schopen dokázat, že daná funkce řeší kvadratickou rovnici. Kompilátor je schopen dokázat, že daná funkce řeší něco, co programátor prohlašuje za kvadratickou rovnici.
-
Ten prispevek je prece o generativnim testovani u dynamicky typovaneho jazyka.
Za behu prece nebudu zapinat "typovou" instrumentaci.
Jak zakomponujete ověření správnosti výsledku do konstukce návratového typu, aby se to ověření nedělalo až za běhu, ale už při překladu?
-
...
A kdyz zakomponuju overeni spravnosti do konstrukce navratoveho typu zarucim tim ze nepujde vytvorit navratovy typ obsahujici nespravny vysledek.
Huh?
Ano je to v podstate znovuimplementace jinak, ...
Asi tak.
Nekde tady byla otazka na kvadratickou rovnici.
Zkusim tu myslenku v te citaci ukazat na tom.
Podotykam moji myslenku z te citace a ne kompletne problem reseny v tomto vlakne.
BoneFlute se z toho osype, protoze to neni ani zdaleka to o cem mluvil on.
A taky protoze to bude v jazyce velmi podobnem jave :-)
Vlastne jedinny rozdil proti jave je, ze umi presne floating point operace.
final static RuntimeException up = new IllegalArgumentException("Does not compute");
private static Result getRoots(double a, double b, double c){
double detBody = b*b - 4*a*c;
if(detBody < 0){
throw new IllegalArgumentException("Fuck it! I don't have imaginary friends. " + detBody);
}
double det = Math.sqrt(detBody);
double root1 = (-b + det)/2*a;
double root2 = (-b - det)/2*a;
return new Result(a,b,c,root1,root2);
}
static class Result {
double root1; double root2;
Result (double a, double b, double c, double root1, double root2){
if(root1 + root2 != -(b/a) || root1*root2 != c/a) throw up;
this.root1 = root1;
this.root2 = root2;
}
}
-
Ten prispevek je prece o generativnim testovani u dynamicky typovaneho jazyka.
Za behu prece nebudu zapinat "typovou" instrumentaci.
Jak zakomponujete ověření správnosti výsledku do konstukce návratového typu, aby se to ověření nedělalo až za běhu, ale už při překladu?
To prece delat nechci. Ja chci napsat tu specifikaci a pak na to pustit ten generator testu.
-
To prece delat nechci. Ja chci napsat tu specifikaci a pak na to pustit ten generator testu.
Pak tedy nebude ověření správnosti sioučástí typu, ale bude v tom testu.
-
To prece delat nechci. Ja chci napsat tu specifikaci a pak na to pustit ten generator testu.
Pak tedy nebude ověření správnosti sioučástí typu, ale bude v tom testu.
Ne. Bude v te specifikaci podle ktere se testy vygeneruji.
-
Narážíš-li na komutativitu, tak tímto způsobem to zase odhalí i Typ.
Jak ten typ bude vypadat?
Přiznávám se bez mučení, že zde mé znalosti končí. Ale mám rámcovou představu, jak by to mělo jít: pokud vím, že operátor sčítání je, a operátor odčítání není komutativní, tak IMHO není problém to kompilátoru říct. Jak konkrétně by se to zapsalo, to netuším. Mám toho ještě hodně k nastudování.
Mám to chápat tak, že netušíš, jak by se to dalo udělat? Ale trváš na tom, že to jde?
Nejde o to, jestli je nebo není komutativní. Jde o to, že ve chvíli kdy to odčítání nebude brát dva stejné typy, tak najednou nemáme grupu. To je kapku drsná cena.
-
Nekde tady byla otazka na kvadratickou rovnici.
Zkusim tu myslenku v te citaci ukazat na tom.
Podotykam moji myslenku z te citace a ne kompletne problem reseny v tomto vlakne.
BoneFlute se z toho osype, protoze to neni ani zdaleka to o cem mluvil on.
A taky protoze to bude v jazyce velmi podobnem jave :-)
Vlastne jedinny rozdil proti jave je, ze umi presne floating point operace.
final static RuntimeException up = new IllegalArgumentException("Does not compute");
private static Result getRoots(double a, double b, double c){
double detBody = b*b - 4*a*c;
if(detBody < 0){
throw new IllegalArgumentException("Fuck it! I don't have imaginary friends. " + detBody);
}
double det = Math.sqrt(detBody);
double root1 = (-b + det)/2*a;
double root2 = (-b - det)/2*a;
return new Result(a,b,c,root1,root2);
}
static class Result {
double root1; double root2;
Result (double a, double b, double c, double root1, double root2){
if(root1 + root2 != -(b/a) || root1*root2 != c/a) throw up;
this.root1 = root1;
this.root2 = root2;
}
}
Nejvíc bych tomu vytknoul, že si nedovedu představit, že by z takového zápisu byl stroj schopen "pochopit" tu kvadratickou rovnici. Takže nemůže (hypoteticky) "vyvinout" jinou, alternativní implementaci. Zdá se mi to jako algoritmus, který musím "otestovat".
-
Přiznávám se bez mučení, že zde mé znalosti končí. Ale mám rámcovou představu, jak by to mělo jít: pokud vím, že operátor sčítání je, a operátor odčítání není komutativní, tak IMHO není problém to kompilátoru říct. Jak konkrétně by se to zapsalo, to netuším. Mám toho ještě hodně k nastudování.
Mám to chápat tak, že netušíš, jak by se to dalo udělat?
Píšu, že mám rámcovou představu takže evidentně tuším.
-
Nekde tady byla otazka na kvadratickou rovnici.
Zkusim tu myslenku v te citaci ukazat na tom.
Podotykam moji myslenku z te citace a ne kompletne problem reseny v tomto vlakne.
BoneFlute se z toho osype, protoze to neni ani zdaleka to o cem mluvil on.
A taky protoze to bude v jazyce velmi podobnem jave :-)
Vlastne jedinny rozdil proti jave je, ze umi presne floating point operace.
final static RuntimeException up = new IllegalArgumentException("Does not compute");
private static Result getRoots(double a, double b, double c){
double detBody = b*b - 4*a*c;
if(detBody < 0){
throw new IllegalArgumentException("Fuck it! I don't have imaginary friends. " + detBody);
}
double det = Math.sqrt(detBody);
double root1 = (-b + det)/2*a;
double root2 = (-b - det)/2*a;
return new Result(a,b,c,root1,root2);
}
static class Result {
double root1; double root2;
Result (double a, double b, double c, double root1, double root2){
if(root1 + root2 != -(b/a) || root1*root2 != c/a) throw up;
this.root1 = root1;
this.root2 = root2;
}
}
Nejvíc bych tomu vytknoul, že si nedovedu představit, že by z takového zápisu byl stroj schopen "pochopit" tu kvadratickou rovnici. Takže nemůže (hypoteticky) "vyvinout" jinou, alternativní implementaci. Zdá se mi to jako algoritmus, který musím "otestovat".
Ano. Je to tak. Pokud bude funkce getRoots spatne tak se vyhodi RuntimeException coz je na produkci stejne nezadouci.
Melo to jen ilustrovat to overeni v ramci konstruktoru navratoveho typu tem co mluvi javistinou.
Ale kdyz si vygeneruju ten bambilion vstupu tak jen odchytim vyjimku a nemusim do testu na tvrdo psat hodnoty.
-
Nějak jsem nepochopil, co to má společného s tím, že když naučíme compiler pracovat se symbolickou matematikou, tak pro něj není problém odvodit, že standardní řešení kvadratické rovnice splňuje specifikace požadovanou po té funkci. Je to asi tak na stejné úrovni, jako že ten Liquid haskell je pro (některé) programy schopen dovodit, že výsledkem funkce je neprázdné pole.
Jenom jsem upřesnil, že to, co popisujete, je jenom vytčení něčeho jednoduchého do knihovny nebo kompilátoru, které pak jako programátor používáte už bez testování. To ale není nic nového. Takhle už máte něco implementováno třeba v C kompilátoru nebo standardní knihovně – a ty implementace se zase testují.
???? Vůbec nerozumím. Celý tenhle thread je o tom, že mám k dispozici kompilátor, který "něco"(typy) umí, a zda s pomocí toho "něčeho" jsem schopen nějaký další program verifikovat tak, že unit testy potřebovat nebudu. Takže když píšu, že pokud bychom měli kompilátor schopný řešit matematické výrazy, tak to umí i verifikovat řešení kvadratické rovnice. Vůbec nechápu, co s tím má společného,
Kompilátor, který neví nic o kvadratických rovnicích, ale umí pracovat s matematickými výrazy (nepovažoval bych za vyloučené, že by tím směrem ty idrisy a spol. ohnout šly), je schopen dokázat, že daná funkce tu kvadratickou rovnici řeší.
Ne, kompilátor není schopen dokázat, že daná funkce řeší kvadratickou rovnici. Kompilátor je schopen dokázat, že daná funkce řeší něco, co programátor prohlašuje za kvadratickou rovnici.
Jako chcete říct, že když programátor kompilátoru nesdělí, aby kontroloval kvadratickou rovnici, tak to kompilátor neudělá...?
-
Kompilátor, který neví nic o kvadratických rovnicích, ale umí pracovat s matematickými výrazy (nepovažoval bych za vyloučené, že by tím směrem ty idrisy a spol. ohnout šly), je schopen dokázat, že daná funkce tu kvadratickou rovnici řeší.
Tohle umí třeba Coq.
-
chvíli kdy to odčítání nebude brát dva stejné typy, tak najednou nemáme grupu. To je kapku drsná cena.
To by byla sice drsná cena, akorát to ale není pravda.
-
Ne. Bude v te specifikaci podle ktere se testy vygeneruji.
To už je jenom nepodstatný detail, čemu přesně říkáte „test“. Já říkám „testy“ celé části kódu, která stojí vedle hlavního kódu a je určená pro testování. Vy asi myslíte nějaký konkrétní testovací framework a „testem“ myslíte například jednu jeho funkci. Na principu to ale nic nemění.
-
???? Vůbec nerozumím. Celý tenhle thread je o tom, že mám k dispozici kompilátor, který "něco"(typy) umí, a zda s pomocí toho "něčeho" jsem schopen nějaký další program verifikovat tak, že unit testy potřebovat nebudu. Takže když píšu, že pokud bychom měli kompilátor schopný řešit matematické výrazy, tak to umí i verifikovat řešení kvadratické rovnice. Vůbec nechápu, co s tím má společného,
Kompilátor, který umí řešit matematické výrazy, je jenom knihovna kódu, který programátor používá, ale netestuje. Nic jiného. Kompilátory běžných jazyků například umí zpracovávat základní algebraické výrazy, tj. umí transformovat sčítáí, odčítání, násobení a dělení na instrukce procesoru, umí správně zpracovat prioritu těch operátorů.
Jako chcete říct, že když programátor kompilátoru nesdělí, aby kontroloval kvadratickou rovnici, tak to kompilátor neudělá...?
Ne, chci říct, že kompilátor nezná pojem „kvadratická rovnice“. Ten pojem nijak neplyne z matematického aparátu, ten název tomu dali lidé, klidně by se to mohlo jmenovat třeba „malá rovnice“ nebo „druhá věta“. Jenže lidé to chtějí používat pod názvem „kvadratické rovnice“, takže musí nějaký člověk přijít a kompilátoru vysvětlit, že to, co má tyhle a tyhle vlastnisti, se nazývá „kvadratická rovnice“. A tenhle popis vlastností je to, kde se často dělají chyby a co je nutné testovat. Kvadratickou rovnici dá asi většina programátorů správně, ale dnešní programy obvykle řeší jiné problémy, než jsou přesně definované matematické funkce.
Pořád jde jen o to, že kompilátor dokáže vyřešit jenom to, co má formálně a bezrosporně zadané. Jenže takováhle zadání programátoři obvykle nemají, ostatně je to jejich práce převádět neformální a neúplné zadání popsané přirozeným jazykem do formální a přesné řeči počítačů. V tomhle převodu se dělají chyby a je snaha těm chybám předcházet, mimo jiné i testováním.
-
Ne. Bude v te specifikaci podle ktere se testy vygeneruji.
To už je jenom nepodstatný detail, čemu přesně říkáte „test“. Já říkám „testy“ celé části kódu, která stojí vedle hlavního kódu a je určená pro testování. Vy asi myslíte nějaký konkrétní testovací framework a „testem“ myslíte například jednu jeho funkci. Na principu to ale nic nemění.
Testovaci framework je spis ten testcheck. Spec je podle me spis neco jako typovy system. Ale to uz jsem psal vyse. To jak to spolu hezky integruje je bonus.
-
???? Vůbec nerozumím. Celý tenhle thread je o tom, že mám k dispozici kompilátor, který "něco"(typy) umí, a zda s pomocí toho "něčeho" jsem schopen nějaký další program verifikovat tak, že unit testy potřebovat nebudu. Takže když píšu, že pokud bychom měli kompilátor schopný řešit matematické výrazy, tak to umí i verifikovat řešení kvadratické rovnice. Vůbec nechápu, co s tím má společného,
Kompilátor, který umí řešit matematické výrazy, je jenom knihovna kódu, který programátor používá, ale netestuje. Nic jiného. Kompilátory běžných jazyků například umí zpracovávat základní algebraické výrazy, tj. umí transformovat sčítáí, odčítání, násobení a dělení na instrukce procesoru, umí správně zpracovat prioritu těch operátorů.
No..vždyť jo. Bavíme se o tom, že tu máme kompilátor, který něco umí (typy) a BoneFlute se ptá, jestli tímto nástrojem (typy) lze nahradit unit testy při ověřování, že ten kód je správně. Což nemá nutně nic společného s tím, jestli to pak skutečně počítá to, co má (z důvodu chyby HW, kompileru apod.).
Jako chcete říct, že když programátor kompilátoru nesdělí, aby kontroloval kvadratickou rovnici, tak to kompilátor neudělá...?
Ne, chci říct, že kompilátor nezná pojem „kvadratická rovnice“. Ten pojem nijak neplyne z matematického aparátu, ten název tomu dali lidé, klidně by se to mohlo jmenovat třeba „malá rovnice“ nebo „druhá věta“. Jenže lidé to chtějí používat pod názvem „kvadratické rovnice“, takže musí nějaký člověk přijít a kompilátoru vysvětlit, že to, co má tyhle a tyhle vlastnisti, se nazývá „kvadratická rovnice“. A tenhle popis vlastností je to, kde se často dělají chyby a co je nutné testovat. Kvadratickou rovnici dá asi většina programátorů správně, ale dnešní programy obvykle řeší jiné problémy, než jsou přesně definované matematické funkce.
Kvadratická rovnice je definovaná jako ax^2 + bx +c = 0. Takže když se člověk zeptá "kompilátore, řeší tenhle vzoreček ax^2+bx+c=0, tak se ptá, jestli řeší kvadratickou rovnici jazykem, kterému kompilátor rozumí. Když tam dá jiný (neekvivalentní) vzoreček, tak se na to neptá.
Pořád jde jen o to, že kompilátor dokáže vyřešit jenom to, co má formálně a bezrosporně zadané. Jenže takováhle zadání programátoři obvykle nemají, ostatně je to jejich práce převádět neformální a neúplné zadání popsané přirozeným jazykem do formální a přesné řeči počítačů. V tomhle převodu se dělají chyby a je snaha těm chybám předcházet, mimo jiné i testováním.
No, takže fakt říkáte, že když kompilátor nepožádám, aby ověřil, že funkce řeší kvadratickou rovnici, tak to kompilátor neověří. Bingo.
-
Kvadratická rovnice je definovaná jako ax^2 + bx +c = 0. Takže když se člověk zeptá "kompilátore, řeší tenhle vzoreček ax^2+bx+c=0, tak se ptá, jestli řeší kvadratickou rovnici jazykem, kterému kompilátor rozumí. Když tam dá jiný (neekvivalentní) vzoreček, tak se na to neptá.
Pořád jde jen o to, že kompilátor dokáže vyřešit jenom to, co má formálně a bezrosporně zadané. Jenže takováhle zadání programátoři obvykle nemají, ostatně je to jejich práce převádět neformální a neúplné zadání popsané přirozeným jazykem do formální a přesné řeči počítačů. V tomhle převodu se dělají chyby a je snaha těm chybám předcházet, mimo jiné i testováním.
No, takže fakt říkáte, že když kompilátor nepožádám, aby ověřil, že funkce řeší kvadratickou rovnici, tak to kompilátor neověří. Bingo.
Spíš se ptáme, jak ten kompilátor požádám, aby ověřil, že funkce řeší kvadratickou rovnici. Typem nebo testem? Jak bude vypadat zápis?
-
Tohle je jen primitivní ukázka, jak se dají jednotkové testy vložit do jazyka, který s nimi původně vůbec nepočítal. Tahle testuje bezstavovou metodu. Není to test jednotkový, ale vývojářský. Podobný test, tentokrát jednotkový a stavový, se dá vložit do záhlaví třídy. Nevýhodou tohoto řešení však je, že testy bývají zhruba 2× delší než produkční kód, po kompilaci na produkci v něm stále překáží - jsou součástí binárky.
V Javě je to o něco lepší - tam se dá test vložit přes statickou vnitřní třídu, která však do produkce nejde. Ovšem už se to nepodobá zmíněným typům.
Ale k čemu je to dobré, když jednotkové testy můžete vytvořit v jakémkoliv jazyku bez potřeby doplnění syntaxe či preprocesoru, a to při větší vyjadřovací schopnosti, protože není třeba vytvářet nový (aťto deklarativní či imperativní) jazyk, ale stačí ten vlastní.
Ono asi to (nepovinné) vyčlenění testů do extra kódu bude mít něco do sebe...
-
Kvadratická rovnice je definovaná jako ax^2 + bx +c = 0. Takže když se člověk zeptá "kompilátore, řeší tenhle vzoreček ax^2+bx+c=0, tak se ptá, jestli řeší kvadratickou rovnici jazykem, kterému kompilátor rozumí. Když tam dá jiný (neekvivalentní) vzoreček, tak se na to neptá.
Pořád jde jen o to, že kompilátor dokáže vyřešit jenom to, co má formálně a bezrosporně zadané. Jenže takováhle zadání programátoři obvykle nemají, ostatně je to jejich práce převádět neformální a neúplné zadání popsané přirozeným jazykem do formální a přesné řeči počítačů. V tomhle převodu se dělají chyby a je snaha těm chybám předcházet, mimo jiné i testováním.
No, takže fakt říkáte, že když kompilátor nepožádám, aby ověřil, že funkce řeší kvadratickou rovnici, tak to kompilátor neověří. Bingo.
Spíš se ptáme, jak ten kompilátor požádám, aby ověřil, že funkce řeší kvadratickou rovnici. Typem nebo testem? Jak bude vypadat zápis?
No uměl bych si představit něco takového (hypoteticky):
getRoots :: a : Num -> b : Num -> c : Num -> [x] : [Num] | a * (x * x) + b * x + c = 0
Tohle je reálný příklad nějaké "vlastnosti" v liquid haskellu:
{-@ type NonEmpty a = {v:[a] | 0 < len v} @-}
{-@ group :: (Eq a) => [a] -> [ NonEmpty a ] @-}
group [] = []
group (x:xs) = (x:ys) : group zs
where
(ys,zs) = span (x ==) xs
-
Kvadratická rovnice je definovaná jako ax^2 + bx +c = 0. Takže když se člověk zeptá "kompilátore, řeší tenhle vzoreček ax^2+bx+c=0, tak se ptá, jestli řeší kvadratickou rovnici jazykem, kterému kompilátor rozumí. Když tam dá jiný (neekvivalentní) vzoreček, tak se na to neptá.
No, a když si programátor bude myslet, že kvadratická rovnice je definovaná jako ax^2 + bx = 0, tak se zeptá „kompilátore, řeší tenhle vzoreček ax^2+bx=0?“, tak si bude myslet, že se ptá, jestli řeší kvadratickou rovnici, jazykem, kterému kompilátor rozumí. Programátor pak odevzdá naprogramovanou funkci pro výpočet kvadratické rovnice, kompilátor nebude hlásit žádnou chybu – akorát ta funkce bude ve spoustě případů počítat špatně.
No, takže fakt říkáte, že když kompilátor nepožádám, aby ověřil, že funkce řeší kvadratickou rovnici, tak to kompilátor neověří. Bingo.
Ne, kompilátor nepožádáte, aby ověřil, že funkce řeší kvadratickou rovnici. Protože kompilátor neví, co je kvadratická rovnice. Kompilátor ví, co je ax^2 + bx = 0 nebo ax^2 + bx + c = 0. Že něco z toho je kvadratická rovnice mu musí říct programátor. A může mu to říct špatně.
-
Kvadratická rovnice je definovaná jako ax^2 + bx +c = 0. Takže když se člověk zeptá "kompilátore, řeší tenhle vzoreček ax^2+bx+c=0, tak se ptá, jestli řeší kvadratickou rovnici jazykem, kterému kompilátor rozumí. Když tam dá jiný (neekvivalentní) vzoreček, tak se na to neptá.
No, a když si programátor bude myslet, že kvadratická rovnice je definovaná jako ax^2 + bx = 0, tak se zeptá „kompilátore, řeší tenhle vzoreček ax^2+bx=0?“, tak si bude myslet, že se ptá, jestli řeší kvadratickou rovnici, jazykem, kterému kompilátor rozumí. Programátor pak odevzdá naprogramovanou funkci pro výpočet kvadratické rovnice, kompilátor nebude hlásit žádnou chybu – akorát ta funkce bude ve spoustě případů počítat špatně.
Zatimco testem se to da vyresit lip, protoze ten co pise test prece vi, ze vysledek kvadraticke rovnice je (7, 10) nebo (12.333, -1).
-
No uměl bych si představit něco takového (hypoteticky):
getRoots :: a : Num -> b : Num -> c : Num -> [x] : [Num] | a * (x * x) + b * x + c = 0
Tak pro inty by to fungovat hypoteticky mohlo. Ale pro floaty si nedokážu představit ani to, jak bych takovýhle předpis ověřoval sám. Minimálně bych tam musel přidat hromadu dalších předpokladů o vstupech a o požadované toleranci.
-
Zatimco testem se to da vyresit lip, protoze ten co pise test prece vi, ze vysledek kvadraticke rovnice je (7, 10) nebo (12.333, -1).
V testu se hlavně porovnávají dva diametrálně odlišné popisy. Tam je přece jenom menší šance, že by programátor udělal 2x podobnou chybu.
-
Tato diskuse už tu nějaký ten den jede. Čím déle nad tím přemýšlím...
Pozor, další myšlenka!:
Použiju-li pro kontrolu jednoduchý typový systém, bude implementačně snadný, ale zároveň vlivem jeho širokých kategorií bude schopen POUZE v rámci těchto kategorií (tj. s jejich přesností) určit správnost výpočtu, což může dostačovat pouze na to, abych zjistil, zda jsem někde neudělal KONCEPČNÍ chybu.
Dokonalý typový systém (bez rozdílu na jeho druh), tj. takový, který přesně rozpozná chybu, by tedy musel mít kategorie mnohem užší (třeba až do kategorie pro každou hodnotu; včetně jejich vztahů), tedy by NĚJAKÝM způsobem musel duplikovat/nahrazovat testovaný výpočet, jinak by nebyl schopen posoudit správnost. Zduplikuju-li onen výpočet (bez ohledu na to, zda bude onen typový systém zapsaný deklarativně či imperativně), pak
1. to má smysl pouze tehdy, bude-li se to lišit, takže půjde o test porovnáním různých implementací,
2. musím počítat s obdobnou složitostí jako u původního výpočtu,
3. vlivem oné složitosti bude pravděpodobněji v tomto typovém systému chyba,
4. každopádně dělám 2x to samé (i když jinak)
ALE!
Jednotkový test sice jde napsat jako znovuimplementace výpočtu, ale nikdy takhle nebyl zamýšlen, protože by trpěl stejnými nevýhodami jako dokonalý typový systém. Proto na to jde opačně - nesnaží se o úplnost, tj. pokrytí všech vstupních kombinací, ale jen těch, u kterých s vysokou pravděpodobností očekává chybu, nebo které reprezentují typické hodnoty, a to tím nejpřímočařejším způsobem, tj. ověření konkrétního výstupu pro konkrétní vstup, čímž dosahuje vysoké efektivity vzhledem k složitosti potřebného aparátu.
Hadžime!
-
Spíš se ptáme, jak ten kompilátor požádám, aby ověřil, že funkce řeší kvadratickou rovnici. Typem nebo testem? Jak bude vypadat zápis?
Ne, neptáme. Ptáme se kompilátoru typem. Tak zní zadání.
Ono asi to (nepovinné) vyčlenění testů do extra kódu bude mít něco do sebe...
A otázka zní, jaké to tedy má výhody? A dá se to napsat jinak? Typem?
Jednotkový test sice jde napsat jako znovuimplementace výpočtu, ale nikdy takhle nebyl zamýšlen, protože by trpěl stejnými nevýhodami jako dokonalý typový systém. Proto na to jde opačně - nesnaží se o úplnost, tj. pokrytí všech vstupních kombinací, ale jen těch, u kterých s vysokou pravděpodobností očekává chybu, nebo které reprezentují typické hodnoty, a to tím nejpřímočařejším způsobem, tj. ověření konkrétního výstupu pro konkrétní vstup, čímž dosahuje vysoké efektivity vzhledem k složitosti potřebného aparátu.
V testu se hlavně porovnávají dva diametrálně odlišné popisy. Tam je přece jenom menší šance, že by programátor udělal 2x podobnou chybu.
Ano, křížová kontrola, to jsem unittestům přiznal jako bod :-) To si moc nedovedu představit jak by se dělalo jinak. Ale třeba časem :-)
Ale k čemu je to dobré, když jednotkové testy můžete vytvořit v jakémkoliv jazyku bez potřeby doplnění syntaxe či preprocesoru, a to při větší vyjadřovací schopnosti, protože není třeba vytvářet nový (aťto deklarativní či imperativní) jazyk, ale stačí ten vlastní.
Viděl jsem spoustu testů. A nedomnívám se, že by to byl nějaký zázrak. Je to ukecané, nudlovité, neexpresivní, nedostatečné.
-
A otázka zní, jaké to tedy má výhody? A dá se to napsat jinak? Typem?
funguje to se současnými technologiemi, nejen s nějakým sci-fi překladačem.
-
není jenom java a coq, výběr je větší a metod k potlačení chyb taky můžeme použíc víc než jednu (QuickCheck třeba ještě)
-
není jenom java a coq, výběr je větší a metod k potlačení chyb taky můžeme použíc víc než jednu (QuickCheck třeba ještě)
O žádné konkrétní implementaci jsem nemluvil. Všechno jsou to jen variace na dané téma.
-
Ano, křížová kontrola, to jsem unittestům přiznal jako bod :-) To si moc nedovedu představit jak by se dělalo jinak. Ale třeba časem :-)
Možná tak v době, kdy si účetní pokecá s AI, přidá k tomu sbírku zákonů a ven vypadne hotový soft.
Seznam ukázkových příkladů je blízko neformálnímu popisu problému. Dokonce ho může dodat i klient s minimální představou o programování. Jakýkoliv typový systém je už o úroveň abstrakce dál. Takže i když už programátoři nebudou hrnout kód, ale jenom formální specifikace, tak budou testy užitečné.
-
Seznam ukázkových příkladů je blízko neformálnímu popisu problému. ... Jakýkoliv typový systém je už o úroveň abstrakce dál. Takže i když už programátoři nebudou hrnout kód, ale jenom formální specifikace, tak budou testy užitečné.
Přijde mi zajímavější, aby ukázkové příklady generoval nástroj na základě specifikace. Včetně okamžiku vývoje.
Dokonce ho může dodat i klient s minimální představou o programování.
No já nevim. To už je otázka spíše psychologická. Veškeré mé zkušenosti s takto neznalími klienty bylo, že mi to museli vysvětlit ústně, protože sami jinak nehli prstem.
-
A otázka zní, jaké to tedy má výhody? A dá se to napsat jinak? Typem?
funguje to se současnými technologiemi, nejen s nějakým sci-fi překladačem.
Dobře, máš pravdu. Ale vzhledem k námětu tohoto vlákna nás zajímá právě ten sci-fi překladač.
Takže, dá se to napsat jinak? Typem?
-
Přijde mi zajímavější, aby ukázkové příklady generoval nástroj na základě specifikace.
Což ovšem význam ukázkových příkladů staví na hlavu. Ukázkové příklady mají ten význam, že je velmi jednoduché je vytvořit a pochopit, řádově jednodušší, než vytvořit správnou specifikaci. Proto je u nich také mnohem větší pravděpodobnost, že budou správně. Když se budou tvořit z té složité specifikace, budou pro její kontrolu k ničemu. Kdybyste chtěl vygenerovat ze specifikace hezké ukázkové příklady, které zkontroluje někdo neznalý programování, bude to ještě podstatně složitější (jak automaticky poznáte ty „hezké“ příklady?), a i pokud by se vám to podařilo, bude existovat velké nebezpečí, že programátor sestaví specifikaci tak, aby mu vycházely ty hezké příklady, a zbytek bude špatně. To je přece známý problém testů (a velké problémy s tím má třeba školství nebo věda), že když něco testujete stále stejnými testy, má to tendency degenerovat a uzpůsobit se tak, aby to perfektně procházelo těmi testy – a nic jiného rozumného to nedělá.
-
Přijde mi zajímavější, aby ukázkové příklady generoval nástroj na základě specifikace. Včetně okamžiku vývoje.
Filip Jirsák to v
Což ovšem význam...
celkem vystihl.
Pokud bych psal např. daňový soft, tak mi dává smysl sednout si s účetní a spočítat si pár ukázkových lidí. Zároveň si tak utřídím vlastní představu o problému. Pak ty ukázky překlopím na testy. Jestli nebudou testy sedět, tak budu kontrolovat i kód a když nic nenajdu tak pak případně ručně přepočítáme pro kontrolu i ty ukázky.
Přijde mi to spolehlivější než kdybychom ručně kontrolovali něco nagenerovaného. Hledání chyb v cizích výsledcích mi nikdy moc nešlo. A taky to svádí k tomu, jenom to prolítnout. Pokud to nebude moc velký úlet, tak ta chyba může projít.
-
Dobře, máš pravdu. Ale vzhledem k námětu tohoto vlákna nás zajímá právě ten sci-fi překladač.
Takže, dá se to napsat jinak? Typem?
jestli tomu rozumím správně, vy překladači zadáte dva vzorce a on ověří, že jsou ekvivalentní. Jak to souvisí s typem?
-
v unittestu ty vzorce mohu otestoval nějak tak
from sympy import solve, symbols, var, sqrt, simplify
a, b, c = symbols('a b c')
x = var('x')
def roots():
return [simplify((-b + sqrt(-4*a*c + b**2))/(2*a)),
simplify(-(b + sqrt(-4*a*c + b**2))/(2*a))]
def test():
assert roots() == solve(a*x**2 + b*x + c, x)
chci vidět, jak to stejné otestuješ typovým systémem
-
No uměl bych si představit něco takového (hypoteticky):
getRoots :: a : Num -> b : Num -> c : Num -> [x] : [Num] | a * (x * x) + b * x + c = 0
Tak pro inty by to fungovat hypoteticky mohlo. Ale pro floaty si nedokážu představit ani to, jak bych takovýhle předpis ověřoval sám. Minimálně bych tam musel přidat hromadu dalších předpokladů o vstupech a o požadované toleranci.
Právě že by to fungovalo symbolicky pro reálná čísla. Zda by to pak při konkrétní implementaci třeba pro "Num=Double" bylo numericky stabilní je druhá věc.
Dokonalý typový systém (bez rozdílu na jeho druh), tj. takový, který přesně rozpozná chybu, by tedy musel mít kategorie mnohem užší (třeba až do kategorie pro každou hodnotu; včetně jejich vztahů), tedy by NĚJAKÝM způsobem musel duplikovat/nahrazovat testovaný výpočet, jinak by nebyl schopen posoudit správnost.
Třeba ta kvadratická rovnice je zrovna ukázka, že tomu tak vůbec být nemusí.
Na druhou stranu ta ukázka:
Op op a b -> op a b
Tak tady je specifikace a konkrétní řešení identické.
Dneska je tendence když mám zadání alespoň trochu formálně popsané zadání to řešit tak, že si napíšu DSL, a v tom DSL pak popíšu tu specifikaci. A samozřejmě tam většina věcí bude vypadat jako to "op a b" - to prostě "je" ta specifikace. A tam se pak dostáváme k otázce, jak otestovat, že ta specifikace je správně - a tam nějaké testy (nevím, jestli zrovna "unit" testy) jsou asi jediné možné řešení.
-
něco ostřejšího https://ncatlab.org/nlab/show/completion+monad ?
-
v unittestu ty vzorce mohu otestoval nějak tak
from sympy import solve, symbols, var, sqrt, simplify
a, b, c = symbols('a b c')
x = var('x')
def roots():
return [simplify((-b + sqrt(-4*a*c + b**2))/(2*a)),
simplify(-(b + sqrt(-4*a*c + b**2))/(2*a))]
def test():
assert roots() == solve(a*x**2 + b*x + c, x)
chci vidět, jak to stejné otestuješ typovým systémem
Ja jsem prave myslel, ze unit test pro kvadratickou rovnici bude obsahovat
asserty pro a,b,c <0, = 0, >0, cili nejakych 8 assertu, ktere si vytvorim manualne...
-
Spíš se ptáme, jak ten kompilátor požádám, aby ověřil, že funkce řeší kvadratickou rovnici. Typem nebo testem? Jak bude vypadat zápis?
Ne, neptáme. Ptáme se kompilátoru typem. Tak zní zadání.
Ukázka by nebyla? Chci se tedy zeptat kompilátoru typem, zda daná funkce řeší kvadratickou rovnici. Jak to bude vypadat?
-
Kvadratická rovnice je definovaná jako ax^2 + bx +c = 0. Takže když se člověk zeptá "kompilátore, řeší tenhle vzoreček ax^2+bx+c=0, tak se ptá, jestli řeší kvadratickou rovnici jazykem, kterému kompilátor rozumí. Když tam dá jiný (neekvivalentní) vzoreček, tak se na to neptá.
Pořád jde jen o to, že kompilátor dokáže vyřešit jenom to, co má formálně a bezrosporně zadané. Jenže takováhle zadání programátoři obvykle nemají, ostatně je to jejich práce převádět neformální a neúplné zadání popsané přirozeným jazykem do formální a přesné řeči počítačů. V tomhle převodu se dělají chyby a je snaha těm chybám předcházet, mimo jiné i testováním.
No, takže fakt říkáte, že když kompilátor nepožádám, aby ověřil, že funkce řeší kvadratickou rovnici, tak to kompilátor neověří. Bingo.
Spíš se ptáme, jak ten kompilátor požádám, aby ověřil, že funkce řeší kvadratickou rovnici. Typem nebo testem? Jak bude vypadat zápis?
Takový příklad je uveden v článku “If monads are the answer, what’s the question?” (který je jinak o něčem úplně jiném). Tamní typový systém umí líně vyhodnocovat a má něco jako “statické jednotkové testy” - to je tak trochu protimluv, překladač v podstatě umožňuje specifikovat podmínky integrity, které se symbolicky ověřují během překladu. Vychází to z nějaké disertace, jejíž název si už nevybavuji (je stará, 80.-90. léta, což naznačuje, že jsme se za pár desetiletí moc daleko neposunuli).
-
Nedavno jsem zmenil projekt a po trech mesicich na tom novem mi doslo k cemu vlastne jsou unit testy a vzpomel sem si na tohle vlakno. Rikal jsem si, ze ho doplnim.
Tak pro me je hlavni duvod proc pisu unit testy:
"Ochrana meho kodu pred neuvazenymi zmenami ostatnich"
Kdekdo mi hrabe do "mych" funkci a ohyba si je pro svuj use case a je mu jedno, ze tim rozbije ten muj.
Kdyz nenapisu testy tak mi pristanou defekty a ja budu slozite hledat kde,kdo a co rozbil.
Kdyz testy mam tak "ohybac" musi zmenit i ty testy aby prosel build a tim padem se snad lepe zamysli.
A kdyz se nezamysli (jako treba ze cele vnitrky testu zakomentuje) tak mam aspon dukazy jakej to je lempl...
Myslim, ze tohle typovy system nedokaze podchytit.
-
Nedavno jsem zmenil projekt a po trech mesicich na tom novem mi doslo k cemu vlastne jsou unit testy a vzpomel sem si na tohle vlakno. Rikal jsem si, ze ho doplnim.
Tak pro me je hlavni duvod proc pisu unit testy:
"Ochrana meho kodu pred neuvazenymi zmenami ostatnich"
Kdekdo mi hrabe do "mych" funkci a ohyba si je pro svuj use case a je mu jedno, ze tim rozbije ten muj.
Kdyz nenapisu testy tak mi pristanou defekty a ja budu slozite hledat kde,kdo a co rozbil.
Kdyz testy mam tak "ohybac" musi zmenit i ty testy aby prosel build a tim padem se snad lepe zamysli.
A kdyz se nezamysli (jako treba ze cele vnitrky testu zakomentuje) tak mam aspon dukazy jakej to je lempl...
Myslim, ze tohle typovy system nedokaze podchytit.
Toto je velice zajímavý postřeh. +1
-
...
Myslim, ze tohle typovy system nedokaze podchytit.
Je to myslím moc pěkný usecase, ač už jsem na něco podobného tuším reagoval.
Zdá se, že mnoho přispěvovatelů si tu vyláme zuby na rozdílu mezi "tohle typový systém nedokáže podchytit protože princip" versus "nesetkal jsem se s typovým systémem, který by to dokázal podchytit".
Například jazyk Elm by toto mohl dát. Jakmile někdo vezme funkci, a ohne si ji, tak se změní major verze té funkce a už nepůjde napasovat, a celé to nepůjde zkompilovat. Což je IMHO právě ta ochrana (ochrana rozhodně užitečná), o které mluvíš.
-
Dobře, máš pravdu. Ale vzhledem k námětu tohoto vlákna nás zajímá právě ten sci-fi překladač.
Takže, dá se to napsat jinak? Typem?
jestli tomu rozumím správně, vy překladači zadáte dva vzorce a on ověří, že jsou ekvivalentní.
Ano. Taky.
Jak to souvisí s typem?
Proč se ptáš?
-
Například jazyk Elm by toto mohl dát. Jakmile někdo vezme funkci, a ohne si ji, tak se změní major verze té funkce a už nepůjde napasovat, a celé to nepůjde zkompilovat. Což je IMHO právě ta ochrana (ochrana rozhodně užitečná), o které mluvíš.
Při popisu toho, proč se používají testy, jste popsal jenom jednu možnou změnu. Druhá možná změna je, že někdo vezme funkci, zachová její API na kterém závisí ostatní a které testují testy, ale upraví její implementaci (např. funkci optimalizuje). Užitečnost ochrany testy spočívá i v tom, že testy dále úspěšně procházejí, přestože se implementace změnila. Testy nejsou určené k tomu, aby nacházely změny, ale aby nacházely takové změny, které něco rozbijí.
-
Například jazyk Elm by toto mohl dát. Jakmile někdo vezme funkci, a ohne si ji, tak se změní major verze té funkce a už nepůjde napasovat, a celé to nepůjde zkompilovat. Což je IMHO právě ta ochrana (ochrana rozhodně užitečná), o které mluvíš.
Při popisu toho, proč se používají testy, jste popsal jenom jednu možnou změnu. Druhá možná změna je, že někdo vezme funkci, zachová její API na kterém závisí ostatní a které testují testy, ale upraví její implementaci (např. funkci optimalizuje). Užitečnost ochrany testy spočívá i v tom, že testy dále úspěšně procházejí, přestože se implementace změnila. Testy nejsou určené k tomu, aby nacházely změny, ale aby nacházely takové změny, které něco rozbijí.
Ale ne. On ma BoneFlute zase pravdu. Uz mi to doslo.
Kdyz bude funkce ochranena typem tam nepujde ohnout aniz by se zmenil ten typ a tudiz kompilator stejne zarve protoze tam kde ji volam ja bude typ nekompatibilni.
-
Například jazyk Elm by toto mohl dát. Jakmile někdo vezme funkci, a ohne si ji, tak se změní major verze té funkce a už nepůjde napasovat, a celé to nepůjde zkompilovat. Což je IMHO právě ta ochrana (ochrana rozhodně užitečná), o které mluvíš.
Při popisu toho, proč se používají testy, jste popsal jenom jednu možnou změnu. Druhá možná změna je, že někdo vezme funkci, zachová její API na kterém závisí ostatní a které testují testy, ale upraví její implementaci (např. funkci optimalizuje). Užitečnost ochrany testy spočívá i v tom, že testy dále úspěšně procházejí, přestože se implementace změnila. Testy nejsou určené k tomu, aby nacházely změny, ale aby nacházely takové změny, které něco rozbijí.
Ale ne. On ma BoneFlute zase pravdu. Uz mi to doslo.
Kdyz bude funkce ochranena typem tam nepujde ohnout aniz by se zmenil ten typ a tudiz kompilator stejne zarve protoze tam kde ji volam ja bude typ nekompatibilni.
Něco podobného je popsáno v Seven more languages in seven weeks.
-
Kdyz bude funkce ochranena typem tam nepujde ohnout aniz by se zmenil ten typ a tudiz kompilator stejne zarve protoze tam kde ji volam ja bude typ nekompatibilni.
Ano, přesně tak.
Mimochodem docela inspirativní, a dokonce z produkce je jazyk Rust a jeho borrows. Což je zase něco jiného než s čím se obvykle setkáváme. Je zajímavé, kolik chyb je schopen při kompilaci najít.
-
Kdyz bude funkce ochranena typem tam nepujde ohnout aniz by se zmenil ten typ a tudiz kompilator stejne zarve protoze tam kde ji volam ja bude typ nekompatibilni.
Nechápu, proč to píšete jako reakci na můj komentář, když jste jen znovu napsal to, na co jsem já reagoval. Já jsem psal o opačném případu, kdy používané API funkce zůstane stejné, ale implementace se změní (což nemusí nutně znamenat, že nová implementace bude ekvivalentní té původní – nesmí se změnit API, ale vlastnosti, na kterých nic nezávisí, se změnit mohou).
-
zatím se tu neobjevil jediný kus fungujícího kódu.
-
Kdyz bude funkce ochranena typem tam nepujde ohnout aniz by se zmenil ten typ a tudiz kompilator stejne zarve protoze tam kde ji volam ja bude typ nekompatibilni.
Nechápu, proč to píšete jako reakci na můj komentář, když jste jen znovu napsal to, na co jsem já reagoval. Já jsem psal o opačném případu, kdy používané API funkce zůstane stejné, ale implementace se změní (což nemusí nutně znamenat, že nová implementace bude ekvivalentní té původní – nesmí se změnit API, ale vlastnosti, na kterých nic nezávisí, se změnit mohou).
Mozna proto, ze ten typovy system muze zajistit, ze (breaking) zmena implementace nepujde udelat beze zmeny API?
-
Mozna proto, ze ten typovy system muze zajistit, ze (breaking) zmena implementace nepujde udelat beze zmeny API?
Zkusím to ještě potřetí: aby to mohlo nahradit jednotkové testy, musel by ten typový systém zároveň zajistit, že změna implementace, která nezmění používané API, nic nerozbije – tedy že např. nedojde k nekompatibilní změně typů. Pro jistotu ještě explicitně uvedu, že „nemění používané API“ neznamená, že se nijak nezmění chování té funkce navenek. Např. pokud se ta funkce používala jen pro vstupní hodnoty 1–10, když se změní výsledek, který vrací pro 11, není to změna používaného API.
-
Je to jenom jiný úhel pohledu pořád na totéž:
Formální správnost programu vs. zamýšlená funkčnost.
...zatímco nepřátelé jednotkových testů přitom marně čekají na akademický důkaz, že obojí typový systém NEzvládne, aby se mohli při tom čekání chlácholit tím, že do té doby mají pravdu...
Takhle tu budete v tom případě asi debatovat ještě hodně dlouho...
-
Pro jistotu ještě explicitně uvedu, že „nemění používané API“ neznamená, že se nijak nezmění chování té funkce navenek. Např. pokud se ta funkce používala jen pro vstupní hodnoty 1–10, když se změní výsledek, který vrací pro 11, není to změna používaného API.
Pokud je vstupni typ funkce integer 1 - 10 tak aby zacala vracet i pro 11 budu muset zmenit typ vstupu. Takze API.
-
Pokud je vstupni typ funkce integer 1 - 10
Není. Opravdu je nutné to explicitně psát, není to zřejmé z předchozího komentáře?
-
zatím se tu neobjevil jediný kus fungujícího kódu.
Bez ohledu na to, zda máte pravdu, toto nebylo požadavkem.
-
Je to jenom jiný úhel pohledu pořád na totéž:
Formální správnost programu vs. zamýšlená funkčnost.
...zatímco nepřátelé jednotkových testů přitom marně čekají na akademický důkaz, že obojí typový systém NEzvládne, aby se mohli při tom čekání chlácholit tím, že do té doby mají pravdu...
Takhle tu budete v tom případě asi debatovat ještě hodně dlouho...
Já si pamatuju na kdysi, kdysi nějaký vlákno fóra, kde se rozebíralo statické typování, haskell, python. Bylo to dlouhý, a hodně inspirativní. Třeba jen od tohoto vlákna očekáváš něco, co není jeho cílem. Někteří z nás tu třeba nechtějí najít univerzální rozhodnutí, nebo si nepotřebují nic dokazovat. Jen se pokoušíme zjistit, co kdo k tomu ví zajímavého. Můžeš k tomu pomoct. (Ale taky nemusíš :-) )
-
Pro jistotu ještě explicitně uvedu, že „nemění používané API“ neznamená, že se nijak nezmění chování té funkce navenek. Např. pokud se ta funkce používala jen pro vstupní hodnoty 1–10, když se změní výsledek, který vrací pro 11, není to změna používaného API.
Pokud je vstupni typ funkce integer 1 - 10 tak aby zacala vracet i pro 11 budu muset zmenit typ vstupu. Takze API.
Jen doplním, že ten Elm si zjistí, zda došlo k nekompatabilní změně algoritmu, a tuto změnu propíše do API jako tu major verzi. Takže ten semver je součástí toho typu. Vzhledem k tomu, že Elm je téměř pure, tak to nepřekvapí. Bylo by zajímavé zjistit, kde má hranice (já jsem se tomu žel nevěnoval tolik, kolik bych chtěl - zatím).
-
Jen doplním, že ten Elm si zjistí, zda došlo k nekompatabilní změně algoritmu, a tuto změnu propíše do API jako tu major verzi.
Jak už jsem několikrát psal, naposledy v komentáři, na který reagujete, ne každá nekompatibilní změna algoritmu je nekompatibilní i z hlediska API.
-
Jen doplním, že ten Elm si zjistí, zda došlo k nekompatabilní změně algoritmu, a tuto změnu propíše do API jako tu major verzi.
Jak už jsem několikrát psal, naposledy v komentáři, na který reagujete, ne každá nekompatibilní změna algoritmu je nekompatibilní i z hlediska API.
A to prave nemusi byt pravda.
-
Jak už jsem několikrát psal, naposledy v komentáři, na který reagujete, ne každá nekompatibilní změna algoritmu je nekompatibilní i z hlediska API.
A to prave nemusi byt pravda.
Asi jste můj komentář špatně přečetl. Psal jsem, že existují takové nekompatibilní změny implementace, které nemění API. Tvrzení o existenci se vyvrací tvrzením, že neexistuje žádný takový případ. Tedy žádné „nemusí“, ale „nemůže existovat“.
Nezapomínejte na to, že definice API nemusí být jenom to, co je v kódu, ale mohou to být další podmínky nebo omezení popsané třeba v dokumentaci. A tu si žádný kompilátor nepřečte.
-
Jak už jsem několikrát psal, naposledy v komentáři, na který reagujete, ne každá nekompatibilní změna algoritmu je nekompatibilní i z hlediska API.
A to prave nemusi byt pravda.
Asi jste můj komentář špatně přečetl. Psal jsem, že existují takové nekompatibilní změny implementace, které nemění API. Tvrzení o existenci se vyvrací tvrzením, že neexistuje žádný takový případ. Tedy žádné „nemusí“, ale „nemůže existovat“.
Nezapomínejte na to, že definice API nemusí být jenom to, co je v kódu, ale mohou to být další podmínky nebo omezení popsané třeba v dokumentaci. A tu si žádný kompilátor nepřečte.
Ja nechci vyvracet to tvrzeni, ze takove zmeny existuji. To je samozrejme, jelikoz existuji jazyky se slabym typovym systemem.
Ja se snazim jenom rict, ze kdyz budu mit silny typovy system tam muzu napsat funkci tak, ze kazda nekompatibilni zmena nutne zmeni API.
-
Ja nechci vyvracet to tvrzeni, ze takove zmeny existuji. To je samozrejme, jelikoz existuji jazyky se slabym typovym systemem.
Ja se snazim jenom rict, ze kdyz budu mit silny typovy system tam muzu napsat funkci tak, ze kazda nekompatibilni zmena nutne zmeni API.
Já jsem ale nepsal o žádných jazycích se slabým typovým systémem. Psal jsem o tom bájném BoneFluteovu jazyku s nejsilnějším možným typovým systémem.
Rozumím tomu, co se snažíte říct. A už po několikáté se vám snažím vysvětlit, že ne každá nekompatibilní změna implementace znamená i nekompatibilní změnu API. Příklad takové funkce už jsem uváděl. Pokud taková změna, která nezpůsobuje nekompatibilní změnu API, vyvolá konflikt (chybu překladu v extra silném typovém systému, selhání testu u slabších typových systémů), je to špatně. Protože pak bude muset programátor neustále řešit tyhle neexistující chyby, bude to dělat automaticky a udělá to i tehdy, když změna vyvolá nekompatibilní změnu API. Mimochodem, to, jestli daná změna je nebo není nekompatibilní změnou API, je v mnoha případech věcí názoru. Takže to opravdu žádný typový systém nevyřeší, protože dva typy nemohou být navzájem kompatibilní u jednoho programátora, a nekompatibilní u jiného, který na to má jiný názor.
-
On existuje aj zlý typový systém? A vtedy akože treba unit testy? Alebo ako to myslíš? Môžeš byť konkrétnejší? Lebo ja som sa ešte so zlým typovým systémom nestretol a tak ani nechápem, čo si mám pod tým predstaviť.
-
Prieskum, porovnanie či má statický typový systém navrch oproti dynamicky typovaným jazykom nepreukázal pozitívny vplyv na hustotu výskytu chýb. Z čoho jasne vyplýva, že je jedno aký druh jazyka použiješ, testy by si mal písať tak či onak. A ak tým svojim zistením máš na mysli klasický flame TS vs JS, tak realita je taká, že si môžeš dovoliť vynechať TS, ale nie testy. Vynechať testy na úkor TS je naprosto neodporúčané práve z dôvodu, že použiť čisto TS ti dá akurát tak falošný pocit bezpečia. Ergo, TDD je reálny "problem solver", nie TS.
-
Prieskum, porovnanie či má statický typový systém navrch oproti dynamicky typovaným jazykom nepreukázal pozitívny vplyv na hustotu výskytu chýb.
Jaký průzkum? Někde na salaši v Hornouhrách?
-
A už po několikáté se vám snažím vysvětlit, že ne každá nekompatibilní změna implementace znamená i nekompatibilní změnu API.
A ja uz se po nekolikate snazim rict, ze to nemusi byt pravda. Kdyz budu mit vhodny typovy system a budu chtit, tak muzu zaridit aby kazda nekompatibilni zmena implementace nutne znamenala zmenu API.
Pokud taková změna, která nezpůsobuje nekompatibilní změnu API, vyvolá konflikt (chybu překladu v extra silném typovém systému, selhání testu u slabších typových systémů), je to špatně. Protože pak bude muset programátor neustále řešit tyhle neexistující chyby, bude to dělat automaticky a udělá to i tehdy, když změna vyvolá nekompatibilní změnu API.
Chyba kompilace mi neprijde jako neexistujici chyba.
Mimochodem, to, jestli daná změna je nebo není nekompatibilní změnou API, je v mnoha případech věcí názoru. Takže to opravdu žádný typový systém nevyřeší, protože dva typy nemohou být navzájem kompatibilní u jednoho programátora, a nekompatibilní u jiného, který na to má jiný názor.
To rekne kompilator co je kompatibilni a co je nekompatibilni. To nemuze byt vec nazoru.
-
A ja uz se po nekolikate snazim rict, ze to nemusi byt pravda. Kdyz budu mit vhodny typovy system a budu chtit, tak muzu zaridit aby kazda nekompatibilni zmena implementace nutne znamenala zmenu API.
Ano, vy jste už poněkolikáté zaměnil kompatibilitu API a kompatibilitu implementace. Já stále píšu o kompatibilitě API a vy na to pokaždé reagujete kompatibilitou implementace. Ne každá změna implementace znamená změnu API.
To rekne kompilator co je kompatibilni a co je nekompatibilni. To nemuze byt vec nazoru.
Možná to nemůže být věc názoru, ale je to tak. Je změnou API třeba to, jak je funkce rychlá, jak dlouho trvá, než se provede? Třeba u webových stránek se v JavaScriptu hlavně dříve spousta věcí, která měla být asynchronní, řešila voláním setTimeout – daný kód se odložil a zavolal třeba za 100 ms. Nebo i dneska to často lidé používají v init skriptech – „dej tam pauzu minutu, za tu dobu ta závislost určitě naběhne“. Spousta lidí k tomu má přístup „teď mi to funguje, tak je to v pořádku“. No a někde místo explicitní pauzy funguje kód, který se provádí delší dobu. A teď si představte, že někdo takový kód optimalizuje a zrychlí. Ten kód, který závisel na tom, že to trvá určitou dobu, se rozbije.
Je to zrychlení nekompatibilní změna API? I když ta doba trvání nikde nebyla zdokumentovaná, nebyl to účel té funkce a jenom to tak náhodou vyšlo. Dá se na takový případ napsat jednotkový test? Mohl by to typový systém řešit jinak, než že by každá změna implementace znamenala nekompatibilní změnu, a tím pádem by veškerá typovost šla k šípku, protože by nic nezáviselo na typech ale na konkrétních implementacích?
-
Pre lamy ako Bacsa:
The broken promise of static typing:
https://labs.ig.com/static-typing-promise
The Shocking Secret About Static Types:
https://medium.com/javascript-scene/the-shocking-secret-about-static-types-514d39bf30a3
You Might Not Need TypeScript (or Static Types):
https://medium.com/javascript-scene/you-might-not-need-typescript-or-static-types-aa7cb670a77b
-
A ja uz se po nekolikate snazim rict, ze to nemusi byt pravda. Kdyz budu mit vhodny typovy system a budu chtit, tak muzu zaridit aby kazda nekompatibilni zmena implementace nutne znamenala zmenu API.
Ano, vy jste už poněkolikáté zaměnil kompatibilitu API a kompatibilitu implementace. Já stále píšu o kompatibilitě API a vy na to pokaždé reagujete kompatibilitou implementace. Ne každá změna implementace znamená změnu API.
Obávám se, že on to nezaměňuje. On mluví o tom, že API zasahuje i do implementace. Že typ, nebo API vidí, že se změnila implementace (přesněji ani ne tak implementace, jako chování). Ty vycházíš z předpokladu, že API a implementace jsou od sebe rozdílné. My uvádíme důkazy (Elm), že to tak není.
... Ten kód, který závisel na tom, že to trvá určitou dobu, se rozbije.
Je to zrychlení nekompatibilní změna API?
Ano. Samozřejmě je to změna API.
I když ta doba trvání nikde nebyla zdokumentovaná, nebyl to účel té funkce a jenom to tak náhodou vyšlo. Dá se na takový případ napsat jednotkový test? Mohl by to typový systém řešit jinak, než že by každá změna implementace znamenala nekompatibilní změnu, a tím pádem by veškerá typovost šla k šípku, protože by nic nezáviselo na typech ale na konkrétních implementacích?
Takhle to ale přeci vůbec není.
Funkce:
foo1 x y = x + y
a
foo1 x y = y + x
Jsou různé implemnetace, ale mají stejné API, protože stejnou funkčnost.
Zatímco
foo2 x y = x / y
a
foo2 x y = y / x
už mají různé API, protože různou funkčnost.
-
Funkce:
foo1 x y = x + y
a
foo1 x y = y + x
Jsou různé implemnetace, ale mají stejné API, protože stejnou funkčnost.
Ale tohle je přeci krásný příklad toho, že to tak není! Dokud bude operátor + komutativní, tak předpoklad platí, ale pokud ho někdo přepíše tak, že komutativní už nebude, tak to přestane fungovat správně, ale API zůstalo stejné. No a to ohlídají právě unit testy.
-
Ty vycházíš z předpokladu, že API a implementace jsou od sebe rozdílné.
To není předpoklad, to je definice API.
My uvádíme důkazy (Elm), že to tak není.
Vy pouze uvádíte příklady, kde jazyk neumožňuje definovat žádné API – takže nezbývá, než být API definované někde bokem, v dokumentaci. A na kontrolu toho API opět potřebujete testy.
Samozřejmě je to změna API.
Takže každá změna implementace je změna API. To pak ale není API. A co se týče praktického použití by takový systém byl úplně stejný, jako dynamicky typované jazyky. Protože byste při každé změně implementace automaticky všude změnil typy.
Takhle to ale přeci vůbec není.
Funkce:
foo1 x y = x + y
a
foo1 x y = y + x
Jsou různé implemnetace, ale mají stejné API, protože stejnou funkčnost.
Zatímco
foo2 x y = x / y
a
foo2 x y = y / x
už mají různé API, protože různou funkčnost.
Nesmysl. Dvě různé implementace, které mají (pro většinu použití) stejnou funkčnost a tedy stejné API vypadají např. takhle:
function sum1(addends) {
var sum = 0;
for(var i = addends.length -1; i >= 0; i--) {
sum += addends[i];
}
return sum;
}
function sum2(addends) {
var sum = 0;
for(var i = 0; i < addends.length; i++) {
sum += addends[i];
}
return sum;
}
-
Funkce:
foo1 x y = x + y
a
foo1 x y = y + x
Jsou různé implemnetace, ale mají stejné API, protože stejnou funkčnost.
Ale tohle je přeci krásný příklad toho, že to tak není! Dokud bude operátor + komutativní, tak předpoklad platí, ale pokud ho někdo přepíše tak, že komutativní už nebude, tak to přestane fungovat správně, ale API zůstalo stejné. No a to ohlídají právě unit testy.
Zkuste se naladit na tu myšlenku: v okamžiku když by se změnil ten operátor, a přestal být komutativní, tak se změní typová signatura toho operátoru. Díky tomu se samozřejmě transitivně změní všechny typy, které na tom závisí. Takže to nepůjde přeložit. Což je přesně to, co řeší testy, a typy mohou taky.
-
My uvádíme důkazy (Elm), že to tak není.
Vy pouze uvádíte příklady, kde jazyk neumožňuje definovat žádné API – takže nezbývá, než být API definované někde bokem, v dokumentaci. A na kontrolu toho API opět potřebujete testy.
Toto nepozoruju. Uvedl jsem konkrétní příklad jazyka. Ten jazyk umožňuje definovat API. A tento jazyk si dokáže ohlídat nekompatabilní změny v implementaci, kdy by implementace změnila chování.
Samozřejmě je to změna API.
Takže každá změna implementace je změna API. To pak ale není API. A co se týče praktického použití by takový systém byl úplně stejný, jako dynamicky typované jazyky. Protože byste při každé změně implementace automaticky všude změnil typy.
Je to zcela stejné jako testy. Změním-li implementaci tak, že se změní chování, musím tomu zohlednit testy. Změním-li v Elmu imlementaci tak, že se změní chování, musím to zohlednit v typech. Pokud změním implementaci tak, že chování bude zachováno, nezmění se API, a nemusím nic měnit. Nehledal bych v tom žádnou složitost.
No, na závěr tohoto můžu maximálně doporučit, aby si se na ten Elm mrknul, mohlo by to být pro tebe poučné. Námětem tohoto vlákna nebylo to, někoho tady učit typy, nebo přesvědčovat co všechno se dá pomocí typů udělat, takže já to tady za sebe uzavírám.
-
jak by tedy vypadaly ty funkce v Elmu?
-
A tento jazyk si dokáže ohlídat nekompatabilní změny v implementaci, kdy by implementace změnila chování.
Jenže já tu celou dobu řeším opačný případ. Tedy kompatibilní změnu v implementaci, která z pohledu dohodnutého API chování nemění. Jako příklad jsem uvedl ty dvě různé implementace sumy, které ve většině případů použití implementují stejné API.
Je to zcela stejné jako testy. Změním-li implementaci tak, že se změní chování, musím tomu zohlednit testy. Změním-li v Elmu imlementaci tak, že se změní chování, musím to zohlednit v typech. Pokud změním implementaci tak, že chování bude zachováno, nezmění se API, a nemusím nic měnit. Nehledal bych v tom žádnou složitost.
V komentáři, na který reagujete, jsem uvedl dvě funkce. Tak v tom nehledejte žádnou složitost, nevymlouvejte se a napište je v Elmu ve dvou variantách. Jednou jako funkce s kompatibilním API, které může jejich uživatel vzájemně zaměňovat, a podruhé jako funkce s nekompatibilním API, protože uživatel závisí i na době jejich provedení, která obecně bude různá.
No, na závěr tohoto můžu maximálně doporučit, aby si se na ten Elm mrknul, mohlo by to být pro tebe poučné. Námětem tohoto vlákna nebylo to, někoho tady učit typy, nebo přesvědčovat co všechno se dá pomocí typů udělat, takže já to tady za sebe uzavírám.
Smyslem komentářů v posledních dnech opravdu nebylo naučit vás typy nebo vás přesvědčovat, co se pomocí typů dá a co nedá dělat. Smyslem bylo vysvětlit některým (například vám), že změna v implementaci může a nemusí znamenat změnu API, a že dokonce stejná změna v implementaci pro někoho může a pro jiného nemusí být změnou API.
-
Ty vycházíš z předpokladu, že API a implementace jsou od sebe rozdílné.
To není předpoklad, to je definice API.
Je to Jiraskova definice? Nebo muzes postnout nejaky odkaz?
-
Ty vycházíš z předpokladu, že API a implementace jsou od sebe rozdílné.
To není předpoklad, to je definice API.
Je to Jiraskova definice? Nebo muzes postnout nejaky odkaz?
Ne, Alois Jirásek nic takového nedefinoval.
-
To není předpoklad, to je definice API.
Je to Jiraskova definice? Nebo muzes postnout nejaky odkaz?
Klidně můžu postnout odkaz. API (https://techterms.com/definition/api). Nebo vám to můžu i rovnou napsat. „API“ je zkratka pro „Application programming interface“. „Interface“ je „rozhraní“, vrstva mezi implementací a volajícím kódem, která zajišťuje jejich částečné oddělení, určitou abstrakci implementace.
-
To není předpoklad, to je definice API.
Je to Jiraskova definice? Nebo muzes postnout nejaky odkaz?
Klidně můžu postnout odkaz. API (https://techterms.com/definition/api). Nebo vám to můžu i rovnou napsat. „API“ je zkratka pro „Application programming interface“. „Interface“ je „rozhraní“, vrstva mezi implementací a volajícím kódem, která zajišťuje jejich částečné oddělení, určitou abstrakci implementace.
Podle toho co sem si tam precetl tak API je velice nevhodny termin pro to co tim tady nazyvame.
Tam se mluvi o systemech a aplikacich. My resime jednotlive funkce (aspon doufam).
Mozna pro nas ucel je lepsi pouzivat slovo podpis?
-
Podle toho co sem si tam precetl tak API je velice nevhodny termin pro to co tim tady nazyvame.
Tam se mluvi o systemech a aplikacich. My resime jednotlive funkce (aspon doufam).
Mozna pro nas ucel je lepsi pouzivat slovo podpis?
API má obvykle více funkcí, my řešíme jednu funkci z toho API. Podpis by podle mne bylo horší slovo, protože podpis evokuje nějakou identitu. A to je právě něco jiného – API znamená, že mám nějaké definované chování, a zbytek chování, který je pro mne nepodstatný, definovaný není. Takže to API pak může být implementováno různými způsoby, různými identitami – všechny musí mít stejné to dohodnuté chování, ale chování, které dohodnuté není, může být libovolné. Třeba jako u té funkce sum, kterou jsem uváděl, by nejspíš bylo dohodnuté, že ta funkce vrací součet všech hodnot v poli. Ve většině případů by ale už asi nebylo dohodnuté, jakým způsobem má ta funkce pole procházet – jestli od začátku do konce, od konce do začátku nebo třeba paralelně. Ale v některých případech může být dohodnuté i tohle. Proto je API věcí dohody, která může být částečně vyjádřena ve zdrojovém kódu (třeba pomocí typů), ale některé závazky API prostě nijak formálně vyjádřit nelze. A proto ani nelze automaticky zjistit, jestli změna implementace změnila nebo nezměnila API.
-
... ale některé závazky API prostě nijak formálně vyjádřit nelze. A proto ani nelze automaticky zjistit, jestli změna implementace změnila nebo nezměnila API.
A muzes teda uvest priklad zavazku, ktery formalne vyjadrit nelze?
-
A muzes teda uvest priklad zavazku, ktery formalne vyjadrit nelze?
Třeba spousta her napsaných v Turbo Pascalu měla na novějších platformách potíže s rychlostí – byly příliš rychlé a nedaly se hrát. Protože rychlost závisela na něčem, co záviselo na rychlosti procesoru. Takže tam by ten závazek zněl nějak jako „časovač musí běžet tak rychle, aby normální lidé mohli tu hru hrát“. Případně by se mohl ten požadavek změnit a formalizovat na „trvání funkce musí být v rozmezí x až y ms“. Což se třeba dá zapsat formálně, ale překladač to nemůže zkontrolovat, protože netuší, na jaké cílové platformě ten kód poběží.
-
jak by tedy vypadaly ty funkce v Elmu?
Ha, omlouvám se! Zde jsem se extrémně nešťastně vyjádřil.
Elm samozřejmě neumí to všechno, o čem jsem hovořil. Elm umí ošetřit právě tu změnu kontraktu na úrovni API. Tedy uvedl jsem ho jako příklad pro použití, kdy testy hlídají, zda se něco změnilo, a abych si toho byl schopen všimnout.
To, že změním chování nějaké funkce, ale vnější signatura (vstup a výstup) zůstane stejná, to by zase mohli podchytit závislostní typy. (Případně se tu objevili příspěvky o dalších technikách.)
A když se to spojí, tak máme ten hypotetický jazyk, který by dokázal nahradit testy v případech užití, které byly uváděny.
-
Ty vycházíš z předpokladu, že API a implementace jsou od sebe rozdílné.
To není předpoklad, to je definice API.
Obávám se, že to není nijak podstatné.
Byly časy, kdy API funkce (říkejme tomu spíše signatura) vypadala nějak takto:
function substr(String str, Int start, Int len) : String
A v praxi jsme pak museli ošetřit testem, co se stane, když zavoláme substr("abc", 6, -2). Někde uvnitř té funkce bylo definováno, že to má vyhodit výjimku, prázdný řetězec, nebo něco takového. Podstatné ale je, že signatura funkce o této nesmyslnosti nic nevěděla.
Dnes už máme typy na takové úrovni, že dokážeme zohlednit, že substr("abc", 6, -2) nepůjde vůbec přeložit. A myslím, že nikoho nijak zvlášť nezajímá, že kdysi dávno se tvrdilo, že ošetření těchto nesmyslných vstupů je otázka implementace, a nikoliv API/Signatury.
Takže pokud trváš na tom, že API/Signatura a implemnetace/chování jsou dva oddělené světy, tak já ti tvůj názor přeji, ale v takovém případě nám nejde o stejnou věc.
-
Případně by se mohl ten požadavek změnit a formalizovat na „trvání funkce musí být v rozmezí x až y ms“. Což se třeba dá zapsat formálně, ale překladač to nemůže zkontrolovat, protože netuší, na jaké cílové platformě ten kód poběží.
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
-
Případně by se mohl ten požadavek změnit a formalizovat na „trvání funkce musí být v rozmezí x až y ms“. Což se třeba dá zapsat formálně, ale překladač to nemůže zkontrolovat, protože netuší, na jaké cílové platformě ten kód poběží.
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
překladač nezná frekvenci hodin cílového CPU, ta se navíc může za běhu měnit, to nemusí až tak moc vadit, pokud bychom se zabývali jenom nejhorším možným případem
-
Případně by se mohl ten požadavek změnit a formalizovat na „trvání funkce musí být v rozmezí x až y ms“. Což se třeba dá zapsat formálně, ale překladač to nemůže zkontrolovat, protože netuší, na jaké cílové platformě ten kód poběží.
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
překladač nezná frekvenci hodin cílového CPU, ta se navíc může za běhu měnit, to nemusí až tak moc vadit, pokud bychom se zabývali jenom nejhorším možným případem
Já tam vidím "ms", takže na frekvenci CPU nezáleží.
Ostatně, to, že rychlost funkce závisela na rychlosti procesoru je pradávná historie. Dneska když se píše hra, tak se určitě nebude opírat o frekvenci CPU, ale o hodiny.
-
Případně by se mohl ten požadavek změnit a formalizovat na „trvání funkce musí být v rozmezí x až y ms“. Což se třeba dá zapsat formálně, ale překladač to nemůže zkontrolovat, protože netuší, na jaké cílové platformě ten kód poběží.
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
překladač nezná frekvenci hodin cílového CPU, ta se navíc může za běhu měnit, to nemusí až tak moc vadit, pokud bychom se zabývali jenom nejhorším možným případem
Já tam vidím "ms", takže na frekvenci CPU nezáleží.
Ostatně, to, že rychlost funkce závisela na rychlosti procesoru je pradávná historie. Dneska když se píše hra, tak se určitě nebude opírat o frekvenci CPU, ale o hodiny.
kde byste vzal dobu trvání fragmentu kódu?
-
Případně by se mohl ten požadavek změnit a formalizovat na „trvání funkce musí být v rozmezí x až y ms“. Což se třeba dá zapsat formálně, ale překladač to nemůže zkontrolovat, protože netuší, na jaké cílové platformě ten kód poběží.
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
překladač nezná frekvenci hodin cílového CPU, ta se navíc může za běhu měnit, to nemusí až tak moc vadit, pokud bychom se zabývali jenom nejhorším možným případem
Já tam vidím "ms", takže na frekvenci CPU nezáleží.
Ostatně, to, že rychlost funkce závisela na rychlosti procesoru je pradávná historie. Dneska když se píše hra, tak se určitě nebude opírat o frekvenci CPU, ale o hodiny.
kde byste vzal dobu trvání fragmentu kódu?
Jen si to představ. Vezmeš nějakou hru a dáš ji přeložit pod 486kou, a ono ti to odmítne, protože nejde zaručit potřebnou rychlost. Horní mez je sranda, to stačí jen oříznout.
Tak samozřejmě se můžeme bavit o tom, jak to zjistit, jak moc to jde zaručit, ale je třeba myslet na kontext tohoto vlákna. Porovnáváme to s testy. Pokud to nezvládneš ani testy, tak není nutné řešit jak to udělat typy.
-
jak by tedy vypadaly ty funkce v Elmu?
To, že změním chování nějaké funkce, ale vnější signatura (vstup a výstup) zůstane stejná, to by zase mohli podchytit závislostní typy.
Ano, ty jsou mocné, docela rád bych tu viděl nějaké příklady problémů, které záv. typy řeší.
-
jak by tedy vypadaly ty funkce v Elmu?
To, že změním chování nějaké funkce, ale vnější signatura (vstup a výstup) zůstane stejná, to by zase mohli podchytit závislostní typy.
Ano, ty jsou mocné, docela rád bych tu viděl nějaké příklady problémů, které záv. typy řeší.
Tak třeba toto: https://forum.root.cz/index.php?topic=18370.0
nebo i toto substr("abc", 6, -2) by měli závislostní typy podchytit. Ale nemohu sloužit, zatím jsem ve fázi student :-)
-
A když se to spojí, tak máme ten hypotetický jazyk, který by dokázal nahradit testy v případech užití, které byly uváděny.
Uváděn byl příklad dvou funkcí pro sumaci. Nějak ho stále přehlížíte.
Obávám se, že to není nijak podstatné.
Byly časy, kdy API funkce (říkejme tomu spíše signatura) vypadala nějak takto:
function substr(String str, Int start, Int len) : String
A v praxi jsme pak museli ošetřit testem, co se stane, když zavoláme substr("abc", 6, -2). Někde uvnitř té funkce bylo definováno, že to má vyhodit výjimku, prázdný řetězec, nebo něco takového. Podstatné ale je, že signatura funkce o této nesmyslnosti nic nevěděla.
Dnes už máme typy na takové úrovni, že dokážeme zohlednit, že substr("abc", 6, -2) nepůjde vůbec přeložit. A myslím, že nikoho nijak zvlášť nezajímá, že kdysi dávno se tvrdilo, že ošetření těchto nesmyslných vstupů je otázka implementace, a nikoliv API/Signatury.
Takže pokud trváš na tom, že API/Signatura a implemnetace/chování jsou dva oddělené světy, tak já ti tvůj názor přeji, ale v takovém případě nám nejde o stejnou věc.
Ale já nepíšu o signatuře, píšu o API. A součástí API té funkce substr je, že někde v dokumentaci, např. v manuálové stránce, je napsáno, co ta funkce má dělat, a v lepším případě i jaké jsou možné parametry a co to bude dělat, pokud budou parametry mimo rozsah. V horším případě tam zejména ty chybové stavy moc dobře popsané nebudou , a pak nastává ten případ, o kterém jsem také psal, že se mohou lišit názory na to, jaké je vlastně přesné API té funkce.
Že API a implementace jsou dva oddělené světy jsem uváděl na tom příkladu se sumací, který raději ignorujete. Mimochodem, je to uváděné jako základní vlastnost API, že odstíní uživatele od konkrétní implementace, takže implementace se může měnit, aniž by se o tom uživatel dozvěděl. Znáte třeba POSIX?
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
Nechcete doufám tvrdit, že stejný kód poběží stejně rychle na 386 a na dnešních výkonných procesorech? Že poběží stejně rychle na Raspberry Pi, na chytrém telefonu i na pracovní stanici?
Ostatně, to, že rychlost funkce závisela na rychlosti procesoru je pradávná historie.
Říká vám něco pojem „výpočetní složitost“? Vážně si myslíte, že když budete mít v poli o milionu čísel najít největší hodnotu, nebo ho setřídit, nebude doba trvání té funkce záviset mimo jiné na rychlosti procesoru?
Jen si to představ. Vezmeš nějakou hru a dáš ji přeložit pod 486kou, a ono ti to odmítne, protože nejde zaručit potřebnou rychlost. Horní mez je sranda, to stačí jen oříznout.
Tak samozřejmě se můžeme bavit o tom, jak to zjistit, jak moc to jde zaručit, ale je třeba myslet na kontext tohoto vlákna. Porovnáváme to s testy. Pokud to nezvládneš ani testy, tak není nutné řešit jak to udělat typy.
Jak přeložit pod 486? Vy jí máte k dispozici? A máte k dispozici i budoucí procesory? Navíc rychlost té funkce by přece musela být zakódovaná v tom typu.
Testy se tohle řeší snadno. Napíše se test, který bude měřit dobu běhu té funkce a zkontroluje, že je v daném rozmezí. Že ten test odhalí chybu, až když ho spustím na příslušném zařízení? Ano, to je vlastností testů, že nejsou prevencí chyb, ale umožňují chyby rychle nalézat po té, co k chybě došlo. Že testy nepokrývají všechny případy? Ano, i to je vlastností testů, a to umožňuje, aby se testy vůbec v reálném světě používaly. Protože programování je stále založené na tom, že se vybírají ty podstatné věci, které se vyjádří v programu, a všechny ostatní nepodstatné se ignorují. Takže se třeba v definici API ignorují záporné hodnoty indexu funkce substr, protože přece nikdo soudný nebude předávat záporný index.
Aby ten váš dokonalý typový systém opravdu předcházel všem chybám, jak si představujete, musel by do typu nakonec zakódovat celý vesmír. Vy považujete za nedokonalost testů, že nepokrývají vše. To ale není nedokonalost testů, to je „nedokonalost“, která je v samotných základech programování, a dokonce i v základech jakéhokoli modelování nebo abstraktního popisu světa, který dělá např. věda. A tahle „nedokonalost“ způsobuje, že vůbec něco jako programování nebo věda může existovat. Bez toho ořezávání nepodstatných informací by to totiž nebyl model ale reálný svět. A že občas ořízneme i informaci, která ve skutečnosti je podstatná? Ano, to se stává, jsme jen omylní lidé. Proto máme různé způsoby, jak na takové chyby přijít. Ale řešením není snažit se tam nacpat co nejvíc jakýchkoli informací, protože to byste nikdy neskončil.
-
A když se to spojí, tak máme ten hypotetický jazyk, který by dokázal nahradit testy v případech užití, které byly uváděny.
Uváděn byl příklad dvou funkcí pro sumaci. Nějak ho stále přehlížíte.
Obávám se, že to není nijak podstatné.
Byly časy, kdy API funkce (říkejme tomu spíše signatura) vypadala nějak takto:
function substr(String str, Int start, Int len) : String
A v praxi jsme pak museli ošetřit testem, co se stane, když zavoláme substr("abc", 6, -2). Někde uvnitř té funkce bylo definováno, že to má vyhodit výjimku, prázdný řetězec, nebo něco takového. Podstatné ale je, že signatura funkce o této nesmyslnosti nic nevěděla.
Dnes už máme typy na takové úrovni, že dokážeme zohlednit, že substr("abc", 6, -2) nepůjde vůbec přeložit. A myslím, že nikoho nijak zvlášť nezajímá, že kdysi dávno se tvrdilo, že ošetření těchto nesmyslných vstupů je otázka implementace, a nikoliv API/Signatury.
Takže pokud trváš na tom, že API/Signatura a implemnetace/chování jsou dva oddělené světy, tak já ti tvůj názor přeji, ale v takovém případě nám nejde o stejnou věc.
Ale já nepíšu o signatuře, píšu o API. A součástí API té funkce substr je, že někde v dokumentaci, např. v manuálové stránce, je napsáno, co ta funkce má dělat, a v lepším případě i jaké jsou možné parametry a co to bude dělat, pokud budou parametry mimo rozsah. V horším případě tam zejména ty chybové stavy moc dobře popsané nebudou , a pak nastává ten případ, o kterém jsem také psal, že se mohou lišit názory na to, jaké je vlastně přesné API té funkce.
To ze se nekdo rozhodl, ze nebude formalizovat veskere pozadavky na funkci, a ze neco jen popise v dokumentaci, neni proto, ze by to neslo, ale proto ze se mu nechtelo.
BoneFluteovi se chce.
Že API a implementace jsou dva oddělené světy jsem uváděl na tom příkladu se sumací, který raději ignorujete. Mimochodem, je to uváděné jako základní vlastnost API, že odstíní uživatele od konkrétní implementace, takže implementace se může měnit, aniž by se o tom uživatel dozvěděl. Znáte třeba POSIX?
Kdyz se zamyslim nad tim prikladem se sumaci tak mi prijde, ze to neni idealni. Tim rikam, ze bude ta funkce pracovat jen s nejakou linearni kolekci a dost se tim omezuji.
Kdyby byl na vstupu misto toho iterator tak dosahnu vetsi znovupouzitelnosti. A jen tak mimochoddem ziskam to, ze smer iterace bude dany tim iteratorem a ne zakodovany v implementaci te sumy.
Jak nemůže? Proč by nemohl? Ať je platforma jakákoliv, tak čas bude všude stejný ne? Této argumentaci nerozumím.
Nechcete doufám tvrdit, že stejný kód poběží stejně rychle na 386 a na dnešních výkonných procesorech? Že poběží stejně rychle na Raspberry Pi, na chytrém telefonu i na pracovní stanici?
By me zajimalo jestli v Turbo pascalu sli vubec napsat hodiny, nebo treba stopky...
http://computer-programming-forum.com/29-pascal/c1fd619ca94be881.htm
Jen si to představ. Vezmeš nějakou hru a dáš ji přeložit pod 486kou, a ono ti to odmítne, protože nejde zaručit potřebnou rychlost. Horní mez je sranda, to stačí jen oříznout.
Tak samozřejmě se můžeme bavit o tom, jak to zjistit, jak moc to jde zaručit, ale je třeba myslet na kontext tohoto vlákna. Porovnáváme to s testy. Pokud to nezvládneš ani testy, tak není nutné řešit jak to udělat typy.
Jak přeložit pod 486? Vy jí máte k dispozici? A máte k dispozici i budoucí procesory? Navíc rychlost té funkce by přece musela být zakódovaná v tom typu.
Testy se tohle řeší snadno. Napíše se test, který bude měřit dobu běhu té funkce a zkontroluje, že je v daném rozmezí. Že ten test odhalí chybu, až když ho spustím na příslušném zařízení? Ano, to je vlastností testů, že nejsou prevencí chyb, ale umožňují chyby rychle nalézat po té, co k chybě došlo.
Takze az napisu tu hru a budu ji prodavat skolakum tak je slusne poprosim, aby mi na svem stroji napred pustili testy z diskety 2?
Že testy nepokrývají všechny případy? Ano, i to je vlastností testů, a to umožňuje, aby se testy vůbec v reálném světě používaly. Protože programování je stále založené na tom, že se vybírají ty podstatné věci, které se vyjádří v programu, a všechny ostatní nepodstatné se ignorují. Takže se třeba v definici API ignorují záporné hodnoty indexu funkce substr, protože přece nikdo soudný nebude předávat záporný index.
Co kdyz se si zvykl na negativni indexovani v pythonu? Nejsem soudny?
-
jak by tedy vypadaly ty funkce v Elmu?
To, že změním chování nějaké funkce, ale vnější signatura (vstup a výstup) zůstane stejná, to by zase mohli podchytit závislostní typy.
Ano, ty jsou mocné, docela rád bych tu viděl nějaké příklady problémů, které záv. typy řeší.
měli jsme tu vektory s pevnou délkou tj. kontrola indexu při překladu
-
Protože programování je stále založené na tom, že se vybírají ty podstatné věci, které se vyjádří v programu, a všechny ostatní nepodstatné se ignorují. Takže se třeba v definici API ignorují záporné hodnoty indexu funkce substr, protože přece nikdo soudný nebude předávat záporný index.
buffer overflow? sql injection?
-
To ze se nekdo rozhodl, ze nebude formalizovat veskere pozadavky na funkci, a ze neco jen popise v dokumentaci, neni proto, ze by to neslo, ale proto ze se mu nechtelo.
Nikoli, je to proto, že to nejde. Abyste popsal opravdu vše, musel byste v důsledku popsat celý vesmír.
BoneFluteovi se chce.
Ne, jemu se chce jenom teoretizovat. Kdyby se mu chtělo to opravdu popisovat, nemusí čekat na žádný formální jazyk a může začít tím, že funkci přesně naspecifikuje v jazyce českém.
Kdyz se zamyslim nad tim prikladem se sumaci tak mi prijde, ze to neni idealni. Tim rikam, ze bude ta funkce pracovat jen s nejakou linearni kolekci a dost se tim omezuji.
Je to příklad, který můžete potkat v praxi. Byl by celkem k ničemu dokonalý typový systém, ve kterém by se daly psát jen ideální programy, ale reálné programy nikoli.
Kdyby byl na vstupu misto toho iterator tak dosahnu vetsi znovupouzitelnosti. A jen tak mimochoddem ziskam to, ze smer iterace bude dany tim iteratorem a ne zakodovany v implementaci te sumy.
A nebo taky ne. Iterátor definuje pořadí, sečíst můžete ale i prvky, které žádné pořadí nemají. A může být výhodnější prvky sčítat jinak, než v pořadí určeném iterátorem. Navíc to, že směr iterace bude daný iterátorem, je nevýhoda – ty dva příklady se lišily tím, že v některých případech mohl být jeden přístup efektivnější než druhý, o čemž by měl vědět autor implementace té sumační funkce, ale vůbec to nemá zajímat jejího uživatele. To je právě součást API – že schovává implementační detaily.
By me zajimalo jestli v Turbo pascalu sli vubec napsat hodiny, nebo treba stopky...
Šly.
Takze az napisu tu hru a budu ji prodavat skolakum tak je slusne poprosim, aby mi na svem stroji napred pustili testy z diskety 2?
Chápete rozdíl mezi „prevencí“ a „až po té, co k chybě došlo“?
-
Takže se třeba v definici API ignorují záporné hodnoty indexu funkce substr, protože přece nikdo soudný nebude předávat záporný index.
Autoři PHP na to mají zjevně jiný názor - záporný parametr znamená že se bere x znaků od konce :)
-
To ze se nekdo rozhodl, ze nebude formalizovat veskere pozadavky na funkci, a ze neco jen popise v dokumentaci, neni proto, ze by to neslo, ale proto ze se mu nechtelo.
Nikoli, je to proto, že to nejde. Abyste popsal opravdu vše, musel byste v důsledku popsat celý vesmír.
Jakoze abych mel kompletni API tak potrebuju osetrit pripad ze mi kozel sezere procesor?
BoneFluteovi se chce.
Ne, jemu se chce jenom teoretizovat. Kdyby se mu chtělo to opravdu popisovat, nemusí čekat na žádný formální jazyk a může začít tím, že funkci přesně naspecifikuje v jazyce českém.
Hmmm
Kdyz se zamyslim nad tim prikladem se sumaci tak mi prijde, ze to neni idealni. Tim rikam, ze bude ta funkce pracovat jen s nejakou linearni kolekci a dost se tim omezuji.
Je to příklad, který můžete potkat v praxi. Byl by celkem k ničemu dokonalý typový systém, ve kterém by se daly psát jen ideální programy, ale reálné programy nikoli.
Nechtel jsem primo rict, ze to smrdi tak jsem pouzil sugar coating "neni idealni"
Kdyby byl na vstupu misto toho iterator tak dosahnu vetsi znovupouzitelnosti. A jen tak mimochoddem ziskam to, ze smer iterace bude dany tim iteratorem a ne zakodovany v implementaci te sumy.
A nebo taky ne. Iterátor definuje pořadí, sečíst můžete ale i prvky, které žádné pořadí nemají. A může být výhodnější prvky sčítat jinak, než v pořadí určeném iterátorem. Navíc to, že směr iterace bude daný iterátorem, je nevýhoda – ty dva příklady se lišily tím, že v některých případech mohl být jeden přístup efektivnější než druhý, o čemž by měl vědět autor implementace té sumační funkce, ale vůbec to nemá zajímat jejího uživatele. To je právě součást API – že schovává implementační detaily.
No prave ze ten Iterator schova jeste vic implementacnich detailu. A muzu ho snad snadno napsat i pro "veci" co sami od sebe poradi nemaji. Efektivita scitani snad bude stejna pri obou smerech iterace. A optimalni zpusob iterace by mel prave spis zaridit ten iterator nez funkce co ho bude pouzivat. Protoze kdyz budu mit 1000 funkci iterujicich stejnou kolekci tak optimalizace bude potreba na 1000 mistech. S iteratorem jen na jednom...
By me zajimalo jestli v Turbo pascalu sli vubec napsat hodiny, nebo treba stopky...
Šly.
Asi si prehlidl ten odkaz. Byla to ironicka poznamka...
Takze az napisu tu hru a budu ji prodavat skolakum tak je slusne poprosim, aby mi na svem stroji napred pustili testy z diskety 2?
Chápete rozdíl mezi „prevencí“ a „až po té, co k chybě došlo“?
Tak kdy se teda ty testy budou na te skolakove 486 poustet?
-
Jakoze abych mel kompletni API tak potrebuju osetrit pripad ze mi kozel sezere procesor?
Víceméně. V tomhle případě to asi bude zbytečné řešit, protože bez procesoru nebude na čem ten kód spouštět. Ale jinak je to přesně ono – co všechno se má ještě zahrnout do definice API. Je jasné, že substr bude všichni volat s nezáporným indexem, a nebo je potřeba nadefinovat i to, jak se má chovat, když někdo použije záporný index? A co když ho někdo zavolá s délkou větší, než je dostupná délka řetězce? A co když někdo závisí i na tom, jak dlouho ta funkce trvá? Jsou to všechno stále méně a méně pravděpodobné věci. Ale to je přesně to, na co si BoneFlute na začátku stěžoval, že testy se píší jenom na ty pravděpodobnější chyby a méně pravděpodobné chyby se ignorují – do té doby, než se ukáže, že je to pravděpodobnější, než si někdo myslel. BoneFlute řešil, jak podchytit všechny případy – tedy i ty málo pravděpodobné, jako že kozel sežere procesor.
Efektivita scitani snad bude stejna pri obou smerech iterace.
Efektivita sčítání ano. Ale stejná nemusí být efektivita procházení kolekce. Procházení jednosměrného spojového seznamu „proti srsti“ bude obvykle mnohem nákladnější, než procházení po směru.
A optimalni zpusob iterace by mel prave spis zaridit ten iterator nez funkce co ho bude pouzivat. Protoze kdyz budu mit 1000 funkci iterujicich stejnou kolekci tak optimalizace bude potreba na 1000 mistech. S iteratorem jen na jednom...
Jenže to, že budete pro sčítání prvků iterovat přes jednotlivé prvky, je implementační detail. Ta sumace může být implementovaná i jinak.
Tak kdy se teda ty testy budou na te skolakove 486 poustet?
Když se s tím bude počítat předem jako s prostředím, kde je potřeba to testovat, bude se to tam spouštět třeba v rámci buildu. Když se takový požadavek objeví až dodatečně, spustí se ty testy tehdy, až se ten požadavek objeví – a díky testům bude snazší zjistit, jestli to na té 486 bude fungovat a co případně opravit. S dokonalým typovým systémem byste tu 486 musel řešit, i když by nikdo neočekával, že se ta aplikace na 486 někdy bude spouštět.
-
Jakoze abych mel kompletni API tak potrebuju osetrit pripad ze mi kozel sezere procesor?
Víceméně. V tomhle případě to asi bude zbytečné řešit, protože bez procesoru nebude na čem ten kód spouštět. Ale jinak je to přesně ono – co všechno se má ještě zahrnout do definice API. Je jasné, že substr bude všichni volat s nezáporným indexem, a nebo je potřeba nadefinovat i to, jak se má chovat, když někdo použije záporný index? A co když ho někdo zavolá s délkou větší, než je dostupná délka řetězce? A co když někdo závisí i na tom, jak dlouho ta funkce trvá? Jsou to všechno stále méně a méně pravděpodobné věci. Ale to je přesně to, na co si BoneFlute na začátku stěžoval, že testy se píší jenom na ty pravděpodobnější chyby a méně pravděpodobné chyby se ignorují – do té doby, než se ukáže, že je to pravděpodobnější, než si někdo myslel. BoneFlute řešil, jak podchytit všechny případy – tedy i ty málo pravděpodobné, jako že kozel sežere procesor.
Myslim, ze BoneFlute bude spokojeny uz kdyz ten typovy system dokaze pokryt to co unit testy. Dokud neuvidim unit test na kozla pozirajiciho procesor tak bych tyhle pripady nechal stranou.
A optimalni zpusob iterace by mel prave spis zaridit ten iterator nez funkce co ho bude pouzivat. Protoze kdyz budu mit 1000 funkci iterujicich stejnou kolekci tak optimalizace bude potreba na 1000 mistech. S iteratorem jen na jednom...
Jenže to, že budete pro sčítání prvků iterovat přes jednotlivé prvky, je implementační detail. Ta sumace může být implementovaná i jinak.
Kdyz bude mit funkce na vstupu iterator misto kolekce tak ten implementacni detail je tak trochu vynuceny v tom API, nemyslis?
Tak kdy se teda ty testy budou na te skolakove 486 poustet?
Když se s tím bude počítat předem jako s prostředím, kde je potřeba to testovat, bude se to tam spouštět třeba v rámci buildu. Když se takový požadavek objeví až dodatečně, spustí se ty testy tehdy, až se ten požadavek objeví – a díky testům bude snazší zjistit, jestli to na té 486 bude fungovat a co případně opravit. S dokonalým typovým systémem byste tu 486 musel řešit, i když by nikdo neočekával, že se ta aplikace na 486 někdy bude spouštět.
Mam pocit, ze tohle uz taky neni tak uplne o unit testech, teda pokud nemam takovy test napsany na (skoro) kazdou funkci v cele aplikaci. Neco podobneho resil kolega tusim pomoci AOP a myslim, ze slo spis o performance testy nez o unit testy.
-
Kdyz bude mit funkce na vstupu iterator misto kolekce tak ten implementacni detail je tak trochu vynuceny v tom API, nemyslis?
Jenže se implementace tím API zbytečně omezuje a nemusí být optimální.
Mam pocit, ze tohle uz taky neni tak uplne o unit testech, teda pokud nemam takovy test napsany na (skoro) kazdou funkci v cele aplikaci. Neco podobneho resil kolega tusim pomoci AOP a myslim, ze slo spis o performance testy nez o unit testy.
Je to pořád jednotkový test, nebo možná funkční test. Neřeší se výkon, ale to, že ta aplikace je za určité situace nepoužitelná nebo padá na chybu.
-
Takže se třeba v definici API ignorují záporné hodnoty indexu funkce substr, protože přece nikdo soudný nebude předávat záporný index.
Autoři PHP na to mají zjevně jiný názor - záporný parametr znamená že se bere x znaků od konce :)
Asi měli dobrej matroš :)
-
Kdyz bude mit funkce na vstupu iterator misto kolekce tak ten implementacni detail je tak trochu vynuceny v tom API, nemyslis?
Jenže se implementace tím API zbytečně omezuje a nemusí být optimální.
Podle me to prave pruznejsi. A optimalizaci prochazeni kolekce to nepotrebuje. Tu zajisti ten iterator.
Mam pocit, ze tohle uz taky neni tak uplne o unit testech, teda pokud nemam takovy test napsany na (skoro) kazdou funkci v cele aplikaci. Neco podobneho resil kolega tusim pomoci AOP a myslim, ze slo spis o performance testy nez o unit testy.
Je to pořád jednotkový test, nebo možná funkční test. Neřeší se výkon, ale to, že ta aplikace je za určité situace nepoužitelná nebo padá na chybu.
Unit test by podle me mel byt platfomne nezavisli.
Ale i tak:
BoneFlute uz tu popisoval jak to zaridit pri kompilaci na te 486.
Namitka byla pokud vim, ze 486 neni v dobe prekladu k dispozici.
Takze kdyz zjistim, ze mam pozadavek aby to bezelo na 486 tak si nejakou sezenu a zkusim to na ni zkompilovat.
Stejne jako u toho testu, ktery zkusim na nejake pustit.
-
A když se to spojí, tak máme ten hypotetický jazyk, který by dokázal nahradit testy v případech užití, které byly uváděny.
Uváděn byl příklad dvou funkcí pro sumaci. Nějak ho stále přehlížíte.
Obávám se, že to není nijak podstatné.
Byly časy, kdy API funkce (říkejme tomu spíše signatura) vypadala nějak takto:
function substr(String str, Int start, Int len) : String
A v praxi jsme pak museli ošetřit testem, co se stane, když zavoláme substr("abc", 6, -2). Někde uvnitř té funkce bylo definováno, že to má vyhodit výjimku, prázdný řetězec, nebo něco takového. Podstatné ale je, že signatura funkce o této nesmyslnosti nic nevěděla.
Dnes už máme typy na takové úrovni, že dokážeme zohlednit, že substr("abc", 6, -2) nepůjde vůbec přeložit. A myslím, že nikoho nijak zvlášť nezajímá, že kdysi dávno se tvrdilo, že ošetření těchto nesmyslných vstupů je otázka implementace, a nikoliv API/Signatury.
Takže pokud trváš na tom, že API/Signatura a implemnetace/chování jsou dva oddělené světy, tak já ti tvůj názor přeji, ale v takovém případě nám nejde o stejnou věc.
Ale já nepíšu o signatuře, píšu o API. A součástí API té funkce substr je, že někde v dokumentaci, např. v manuálové stránce, je napsáno, co ta funkce má dělat, a v lepším případě i jaké jsou možné parametry a co to bude dělat, pokud budou parametry mimo rozsah. V horším případě tam zejména ty chybové stavy moc dobře popsané nebudou , a pak nastává ten případ, o kterém jsem také psal, že se mohou lišit názory na to, jaké je vlastně přesné API té funkce.
To ze se nekdo rozhodl, ze nebude formalizovat veskere pozadavky na funkci, a ze neco jen popise v dokumentaci, neni proto, ze by to neslo, ale proto ze se mu nechtelo.
BoneFluteovi se chce.
Chci se posunout, a mět jazyky a stroj, který udělá maximum nudné práce.
Že limit nemá být záporný, a že start musí být menší jak str nebudu psát do dokumentace ani do testů. Napíšu to pomocí závislostních typů, protože je to výhodnější. Když to jde, tak to použiju. Když to výhodnější nebude, tak to nepoužiju. Ale to neznamená že to nejde.
-
Ale to neznamená že to nejde.
dosud jsi neukázal, že to jde ani u jednoduchých funkcí pro sčítání a odčítání.
-
Ale to neznamená že to nejde.
dosud jsi neukázal, že to jde ani u jednoduchých funkcí pro sčítání a odčítání.
To je pravda. To ukázali jiní, dvakrát.
-
Že limit nemá být záporný, a že start musí být menší jak str nebudu psát do dokumentace ani do testů. Napíšu to pomocí závislostních typů, protože je to výhodnější.
A jak by si tu funkci substr těmi závislostními typy napsal?
-
A optimalizaci prochazeni kolekce to nepotrebuje. Tu zajisti ten iterator.
Nezajistí, protože iterátor neví, jak je výhodné procházet kolekci z pohledu sumační funkce. Vždycky je to něco za něco. Buď můžete mít obecné API, které můžete používat opakovaně, ale za cenu horší optimalizace. A nebo můžete mít kód, který jde až na dřeň toho, co jde z hardwaru vyždímat, pak ale musíte rezignovat na abstrakci a univerzální rozhraní.
Unit test by podle me mel byt platfomne nezavisli.
Proč? Jednotkový test má testovat jednu samostatnou část kódu. Klidně to může být implementace v assembleru něčeho, co je na jiných platformách dostupné jako instrukce procesoru. Ale i kód ve vyšších jazycích může být potřeba otestovat na různých platformách různě.
BoneFlute uz tu popisoval jak to zaridit pri kompilaci na te 486.
Namitka byla pokud vim, ze 486 neni v dobe prekladu k dispozici.
Takze kdyz zjistim, ze mam pozadavek aby to bezelo na 486 tak si nejakou sezenu a zkusim to na ni zkompilovat.
Stejne jako u toho testu, ktery zkusim na nejake pustit.
Ale BoneFlute přece chce, aby bylo vše kontrolované v době překladu, tedy ty informace v typech musí být už v době překladu. Bez ohledu na to, zda nějakou 486 máte nebo nemáte k dispozici, a dokonce bez ohledu na to, zda nějaká 486 už byla či nebyla vytvořena. Když to tam mít nebudete, musíte v typu povolit něco jako „neznámé“, a tím povolíte to, čemu se chtěl BoneFlute vyhnout.
-
Když to výhodnější nebude, tak to nepoužiju. Ale to neznamená že to nejde.
Čímž jste právě popřel to, čím jste odstartoval celou diskusi. Pokud vím, nelíbilo se vám, že testy se píšou jenom tehdy, když je to výhodné – a chtěl jste je nahradit něčím, co bude provádět kontroly vždy, bez ohledu na to, jestli si programátor myslí, zda je nebo není ta kontrola výhodná.
A mimochodem, s tím dokazováním, že to vždy jde, jste na tom taky dost bledě. Zatím jste neodkázal, že to jde, ani u konkrétních příkladů, natož abyste to dokázal obecně.
-
Že limit nemá být záporný, a že start musí být menší jak str nebudu psát do dokumentace ani do testů. Napíšu to pomocí závislostních typů, protože je to výhodnější.
A jak by si tu funkci substr těmi závislostními typy napsal?
Jak jsem uváděl, zatím je ještě neovládám, takže toto je jen takový pseudokód:
function substr(str: String, start: Int 0 (strlen str), len: Int 0 (strlen str)) : String 0 (strlen str)
Zápis asi nic moc, tak vařím to z hlavy, bez přípravy.
-
Že limit nemá být záporný, a že start musí být menší jak str nebudu psát do dokumentace ani do testů. Napíšu to pomocí závislostních typů, protože je to výhodnější.
A jak by si tu funkci substr těmi závislostními typy napsal?
Jak jsem uváděl, zatím je ještě neovládám, takže toto je jen takový pseudokód:
function substr(str: String, start: Int 0 (strlen str), len: Int 0 (strlen str)) : String 0 (strlen str)
Zápis asi nic moc, tak vařím to z hlavy, bez přípravy.
Doporučil bych knihu "Seven more languages in seven weeks", tam stručně popisují Idris, který se přesně na tohle hodí.
-
Doporučil bych knihu "Seven more languages in seven weeks", tam stručně popisují Idris, který se přesně na tohle hodí.
dokážeš v tom Idrisu napsat jednořádkovou funkci?
-
Doporučil bych knihu "Seven more languages in seven weeks", tam stručně popisují Idris, který se přesně na tohle hodí.
Díky! Mrknu na to.
Můžeš mě trochu navnadit, o čem všem se tam píše?
-
A optimalizaci prochazeni kolekce to nepotrebuje. Tu zajisti ten iterator.
Nezajistí, protože iterátor neví, jak je výhodné procházet kolekci z pohledu sumační funkce. Vždycky je to něco za něco. Buď můžete mít obecné API, které můžete používat opakovaně, ale za cenu horší optimalizace. A nebo můžete mít kód, který jde až na dřeň toho, co jde z hardwaru vyždímat, pak ale musíte rezignovat na abstrakci a univerzální rozhraní.
Iterator zajisti optimalni prochazeni kolekce. Myslel jsem, ze na tom scitani uz jsme se dohodli ze performance rozdil nebude.
Mozna neco prehlizim. Priklad?
BoneFlute uz tu popisoval jak to zaridit pri kompilaci na te 486.
Namitka byla pokud vim, ze 486 neni v dobe prekladu k dispozici.
Takze kdyz zjistim, ze mam pozadavek aby to bezelo na 486 tak si nejakou sezenu a zkusim to na ni zkompilovat.
Stejne jako u toho testu, ktery zkusim na nejake pustit.
Ale BoneFlute přece chce, aby bylo vše kontrolované v době překladu, tedy ty informace v typech musí být už v době překladu. Bez ohledu na to, zda nějakou 486 máte nebo nemáte k dispozici, a dokonce bez ohledu na to, zda nějaká 486 už byla či nebyla vytvořena. Když to tam mít nebudete, musíte v typu povolit něco jako „neznámé“, a tím povolíte to, čemu se chtěl BoneFlute vyhnout.
To aby to selhalo pri prekladu na 486 a fungovalo jinde prece nezalezi na tom jestli 486 existuje nebo ne.
-
Doporučil bych knihu "Seven more languages in seven weeks", tam stručně popisují Idris, který se přesně na tohle hodí.
Díky! Mrknu na to.
Můžeš mě trochu navnadit, o čem všem se tam píše?
O závislostních typech ;) Je to úvod do toho jazyka se zaměřením na právě závislostní typy, protože znalost toho, na čem staví (FP à la Haskell), se předpokládá.
-
Doporučil bych knihu "Seven more languages in seven weeks", tam stručně popisují Idris, který se přesně na tohle hodí.
Díky! Mrknu na to.
Můžeš mě trochu navnadit, o čem všem se tam píše?
O závislostních typech ;) Je to úvod do toho jazyka se zaměřením na právě závislostní typy, protože znalost toho, na čem staví (FP à la Haskell), se předpokládá.
OK, díky.
Tak já jsem si původně představoval, že to třeba bere více teoreticky a i jiné techniky než závislostní typy. Ale taky dobrý. Díky!
-
Doporučil bych knihu "Seven more languages in seven weeks", tam stručně popisují Idris, který se přesně na tohle hodí.
Díky! Mrknu na to.
Můžeš mě trochu navnadit, o čem všem se tam píše?
O závislostních typech ;) Je to úvod do toho jazyka se zaměřením na právě závislostní typy, protože znalost toho, na čem staví (FP à la Haskell), se předpokládá.
OK, díky.
Tak já jsem si původně představoval, že to třeba bere více teoreticky a i jiné techniky než závislostní typy. Ale taky dobrý. Díky!
Ne, je to poměrně stručné, ale jako úvod užitečné, s rozumnými příklady. Teoretičtěji a do hloubky to bere Bradyho kniha o Idrisu, tam jde od úplných začátků až po komplexní konstrukce, ale kdo zná Haskell, tak stejně dvě třetiny přeskočí.
-
Iterator zajisti optimalni prochazeni kolekce.
Ano. Akorát že já nechci kolekci procházet, já chci získat součet jejích prvků.
Myslel jsem, ze na tom scitani uz jsme se dohodli ze performance rozdil nebude.
Nikoli, to byla pouze vaše chybná domněnka, kterou jsem vyvrátil.
Mozna neco prehlizim. Priklad?
Procesor nemůže pracovat s daty přímo, pracuje s tím, co má v registrech nebo nejbližší cache. Ta cache není moc velká, data do ní se tahají z pomalejší vzdálenější cache, z ještě pomalejší RAM nebo z ještě pomalejšího swapu. Aby procesor na data zbytečně nečekal, pokouší se odhadnout, jaká data budou potřeba, a ty načítá dopředu. Pokud tedy bude způsob procházení kolekce pro procesor předvídatelný, dokáže data včas přednačítat a jejich zpracování bude mnohem rychlejší, než když bude procesor každou chvíli na data čekat.
Navíc dnešní procesory jsou vícevláknové, a zrovna sumace se dá dobře paralelizovat – každé vlákno sečte část kolekce a na závěr se sečtou dílčí součty. Akorát z výše uvedeného důvodu je potřeba, aby každé vlákno zpracovávalo ucelený blok kolekce – tj. první vlákno třeba prvních 16 prvků, druhé vlákno dalších 16 prvků atd. To iterátor neumožňuje, ten by cpal jednotlivé prvky vláknům napřeskáčku (a ještě by se musel mezi vlákny zamykat).
To aby to selhalo pri prekladu na 486 a fungovalo jinde prece nezalezi na tom jestli 486 existuje nebo ne.
Ale ono to nemá selhat při překladu na 486. Má to selhat při překladu kdekoli, pokud by to např. na 486 selhalo při běhu. BoneFlute přece chtěl, aby se jakákoli chyba odhalila už při překladu, ne až při běhu testů.
-
Myslel jsem, ze na tom scitani uz jsme se dohodli ze performance rozdil nebude.
Nikoli, to byla pouze vaše chybná domněnka, kterou jsem vyvrátil.
Kde? Asi jsem prehledl...
Mozna neco prehlizim. Priklad?
Procesor nemůže pracovat s daty přímo, pracuje s tím, co má v registrech nebo nejbližší cache. Ta cache není moc velká, data do ní se tahají z pomalejší vzdálenější cache, z ještě pomalejší RAM nebo z ještě pomalejšího swapu. Aby procesor na data zbytečně nečekal, pokouší se odhadnout, jaká data budou potřeba, a ty načítá dopředu. Pokud tedy bude způsob procházení kolekce pro procesor předvídatelný, dokáže data včas přednačítat a jejich zpracování bude mnohem rychlejší, než když bude procesor každou chvíli na data čekat.
Navíc dnešní procesory jsou vícevláknové, a zrovna sumace se dá dobře paralelizovat – každé vlákno sečte část kolekce a na závěr se sečtou dílčí součty. Akorát z výše uvedeného důvodu je potřeba, aby každé vlákno zpracovávalo ucelený blok kolekce – tj. první vlákno třeba prvních 16 prvků, druhé vlákno dalších 16 prvků atd. To iterátor neumožňuje, ten by cpal jednotlivé prvky vláknům napřeskáčku (a ještě by se musel mezi vlákny zamykat).
To je ale dost nizkourovnova zalezitost. Myslim, ze v jazycich vyssi urovne s tim stejne moc neudelame, protoze jsme tak daleko abstrahovali od HW, ze nemuzeme optimalizovat na urovni l1 a l2 cache.
To je dan kterou platime za expresivnost jazyku.
To aby to selhalo pri prekladu na 486 a fungovalo jinde prece nezalezi na tom jestli 486 existuje nebo ne.
Ale ono to nemá selhat při překladu na 486. Má to selhat při překladu kdekoli, pokud by to např. na 486 selhalo při běhu. BoneFlute přece chtěl, aby se jakákoli chyba odhalila už při překladu, ne až při běhu testů.
Jmeno toho vlakna naznacuje, ze jde o srovnani toho co jde a nejde udelat typy vs unit testy.
Takze nevim jak BoneFlute, ale za me:
Az uvidim unit test ktery pri behu na Xeonu zahlasi ze dana funkce selze na 486 zacnu resit jak je mozne, ze tohle nedokaze typovy system.
-
To je ale dost nizkourovnova zalezitost. Myslim, ze v jazycich vyssi urovne s tim stejne moc neudelame, protoze jsme tak daleko abstrahovali od HW, ze nemuzeme optimalizovat na urovni l1 a l2 cache.
To je dan kterou platime za expresivnost jazyku.
Zde bych si dovolil nesouhlasit.
Právě expresivnost jazyka nám, minimálně teoreticky, dovoluje agresivně optimalizovat. Tudíž se docela dobře na tu úroveň cache můžeme dostat.
Příklad: mám kolekci objektů, u které si kompilátor z typové signatury odvodí, že jsou imutable, tak mohu nejenom neřešit zámky, ale klidně můžu tu kolekci umístit na stacku, nebo ji inlinovat/rozkopírovat. Mě, jako uživatele to nezajímá, a kompilátor má volné ruce.
V praxi se to i dost ukazuje: http://funkcionalne.cz/2015/04/bez-typu-se-obejdeme-ale/
V kontextu tohoto vlákna: kompilátor píšou parta lidí, kteří se soustředí na různé tyto optimalizace. Obvykle můžeme očekávat špičky ve svém oboru. V případě, kdy to samé dělám testy, tak to píšeš zas a znova, a optimalizovat musíš opět zas a znova ty sám. Snad je z toho vidět ta motivace po typech.
Jmeno toho vlakna naznacuje, ze jde o srovnani toho co jde a nejde udelat typy vs unit testy.
Takze nevim jak BoneFlute, ale za me:
Az uvidim unit test ktery pri behu na Xeonu zahlasi ze dana funkce selze na 486 zacnu resit jak je mozne, ze tohle nedokaze typovy system.
:-D Tak nějak.
-
Zde bych si dovolil nesouhlasit.
Právě expresivnost jazyka nám, minimálně teoreticky, dovoluje agresivně optimalizovat. Tudíž se docela dobře na tu úroveň cache můžeme dostat.
Příklad: mám kolekci objektů, u které si kompilátor z typové signatury odvodí, že jsou imutable, tak mohu nejenom neřešit zámky, ale klidně můžu tu kolekci umístit na stacku, nebo ji inlinovat/rozkopírovat. Mě, jako uživatele to nezajímá, a kompilátor má volné ruce.
Puvodne jsem tam mel napsany cancy o tom jak kompilator to zoptimalizuje daleko lip nez ja bych kdy dokazal.
Ale pak sem si predstavil jak mi tu nekdo napise, ze to ze ja sem lama neznamena, ze ostatni to taky neumi, a moje ego mi nedovolilo to postnout ;-).
Ale myslenka zustava stejna. Ja jako programator nemuzu ve vysokourovnovem jazyce optimalizovat na nizke urovni.
Musim spolehat na kompilator. A asi je to vetsinou dobre (v mem pripade urcite :-D)
-
Příklad: mám kolekci objektů, u které si kompilátor z typové signatury odvodí, že jsou imutable
Pardon že se vám do toho pletu, ale co má immutabilita společného s datovými typy? Takovou optimalizaci můžu stejně tak udělat i v dynamicky typovaném jazyce. V typovém systému to žádnou výhodu navíc mít nebude.
-
To je ale dost nizkourovnova zalezitost. Myslim, ze v jazycich vyssi urovne s tim stejne moc neudelame, protoze jsme tak daleko abstrahovali od HW, ze nemuzeme optimalizovat na urovni l1 a l2 cache.
To je dan kterou platime za expresivnost jazyku.
Zde bych si dovolil nesouhlasit.
Právě expresivnost jazyka nám, minimálně teoreticky, dovoluje agresivně optimalizovat. Tudíž se docela dobře na tu úroveň cache můžeme dostat.
Příklad: mám kolekci objektů, u které si kompilátor z typové signatury odvodí, že jsou imutable, tak mohu nejenom neřešit zámky, ale klidně můžu tu kolekci umístit na stacku, nebo ji inlinovat/rozkopírovat. Mě, jako uživatele to nezajímá, a kompilátor má volné ruce.
V praxi se to i dost ukazuje: http://funkcionalne.cz/2015/04/bez-typu-se-obejdeme-ale/
V kontextu tohoto vlákna: kompilátor píšou parta lidí, kteří se soustředí na různé tyto optimalizace. Obvykle můžeme očekávat špičky ve svém oboru. V případě, kdy to samé dělám testy, tak to píšeš zas a znova, a optimalizovat musíš opět zas a znova ty sám. Snad je z toho vidět ta motivace po typech.
iterátor neumožňuje náhodný přístup, z toho plyne ten problém, o kterém psal jirsák. Typy prvků vám nepomohou.
-
Kde? Asi jsem prehledl...
Zde (https://forum.root.cz/index.php?topic=18804.msg282499#msg282499).
To je ale dost nizkourovnova zalezitost. Myslim, ze v jazycich vyssi urovne s tim stejne moc neudelame, protoze jsme tak daleko abstrahovali od HW, ze nemuzeme optimalizovat na urovni l1 a l2 cache.
To je dan kterou platime za expresivnost jazyku.
Nikoli, tohle výrazně ovlivňuje výkon i u jazyků vyšší úrovně, třeba těch běžících nad JVM. Tam, kde je to kritické, se i kód v těchhle jazycích optimalizuje tak, aby se např. data vešla do řádku cache a minimalizoval se cache miss.
Jmeno toho vlakna naznacuje, ze jde o srovnani toho co jde a nejde udelat typy vs unit testy.
Takze nevim jak BoneFlute, ale za me:
Az uvidim unit test ktery pri behu na Xeonu zahlasi ze dana funkce selze na 486 zacnu resit jak je mozne, ze tohle nedokaze typovy system.
Důležitější je asi obsah, než název. Název vlákna naznačuje, že jde o srovnání, ale text prvního příspěvku je jednoznačný pokus (úspěšný) o rozpoutání flamewar.
Navíc ta vaše podmínka je přísnější, než co požadoval BoneFlute. On se ptal na to, co jde vyřešit testem a nejde to podchytit typovým systémem. A tohle je jeden z příkladů. Je možné napsat test, který na Xeonu selže, protože testovaná funkce byla napsána pro 486 a na Xeonu je příliš rychlá. Typovým systémem toto podchytit nelze.
-
To je ale dost nizkourovnova zalezitost. Myslim, ze v jazycich vyssi urovne s tim stejne moc neudelame, protoze jsme tak daleko abstrahovali od HW, ze nemuzeme optimalizovat na urovni l1 a l2 cache.
To je dan kterou platime za expresivnost jazyku.
Zde bych si dovolil nesouhlasit.
Právě expresivnost jazyka nám, minimálně teoreticky, dovoluje agresivně optimalizovat. Tudíž se docela dobře na tu úroveň cache můžeme dostat.
Příklad: mám kolekci objektů, u které si kompilátor z typové signatury odvodí, že jsou imutable, tak mohu nejenom neřešit zámky, ale klidně můžu tu kolekci umístit na stacku, nebo ji inlinovat/rozkopírovat. Mě, jako uživatele to nezajímá, a kompilátor má volné ruce.
V praxi se to i dost ukazuje: http://funkcionalne.cz/2015/04/bez-typu-se-obejdeme-ale/
V kontextu tohoto vlákna: kompilátor píšou parta lidí, kteří se soustředí na různé tyto optimalizace. Obvykle můžeme očekávat špičky ve svém oboru. V případě, kdy to samé dělám testy, tak to píšeš zas a znova, a optimalizovat musíš opět zas a znova ty sám. Snad je z toho vidět ta motivace po typech.
iterátor neumožňuje náhodný přístup, z toho plyne ten problém, o kterém psal jirsák. Typy prvků vám nepomohou.
Iterátor nemá typ? To, že neumožňuje náhodný přístup je typová vlastnost. Iterátor jsem zvolil z nějakého důvodu. Pokud ten důvod nemám, tak nebudu kompilátoru tvrdit, že má použítá iterátor, ale nechám to na něm.
-
Důležitější je asi obsah, než název. Název vlákna naznačuje, že jde o srovnání, ale text prvního příspěvku je jednoznačný pokus (úspěšný) o rozpoutání flamewar.
Já jsem o žádné flamewar zájem neměl. Text mého příspěvku k flamewar nenabádal. Ale beru tě jako nutné zlo.
-
Příklad: mám kolekci objektů, u které si kompilátor z typové signatury odvodí, že jsou imutable
Pardon že se vám do toho pletu, ale co má immutabilita společného s datovými typy? Takovou optimalizaci můžu stejně tak udělat i v dynamicky typovaném jazyce. V typovém systému to žádnou výhodu navíc mít nebude.
Nepřímou.
Ale v tom odkazovaném článku je to pěkně rozebráno. I to, na co narážíš. Shrnuto - pokud jsou typy blbé, je pro komplilátor výhodnější je ignorovat a odvodit si vlastní.
-
Ja jako programator nemuzu ve vysokourovnovem jazyce optimalizovat na nizke urovni.
Můžete. I u toho vysokoúrovňového jazyka můžete mít zaručené, že pole ten jazyk ukládá jako jednotlivé prvky v paměti vedle sebe. Takže když použijete pole primitivních hodnot, nejde se vám do řádku cache několik hodnot. Když použijete spojový seznam, bude každá položka uložená v paměti někde jinde a procesor bude při průchodu kolekcí pořád jen čekat, než se nahrají data z paměti. A tohle je třeba rozdíl mezi java.util.ArrayList a java.util.LinkedList. Připadají vám Java, Scala nebo Clojure jako dostatečně vysokoúrovňové jazyky? Ano, Java je jen assembler nad bajtkódem, ale stejně…
-
Ale myslenka zustava stejna. Ja jako programator nemuzu ve vysokourovnovem jazyce optimalizovat na nizke urovni.
Musim spolehat na kompilator. A asi je to vetsinou dobre (v mem pripade urcite :-D)
Ano. To prakticky vždycky. Rád na přednáškách tvrdím, že je třeba psát kód tak, aby ho kolegové mohli intuitivně použít i když budou našrot.
-
Já jsem o žádné flamewar zájem neměl. Text mého příspěvku k flamewar nenabádal.
Jasně. V názvu tématu se na něco ptáte, v textu rovnou odpovíte, arogantně a bez jakéhokoli vysvětlení. A pak to celou dobu přiživujete tím, že sice úplně nechápete základy, ale někde jste zahlédl něco úžasného, z čeho se všichni musí posadit na zadek. To vůbec není odstartování flamewaru…
-
Rád na přednáškách tvrdím,
Tohle je nejhorší zpráva z celého tématu.
-
Ja jako programator nemuzu ve vysokourovnovem jazyce optimalizovat na nizke urovni.
Můžete. I u toho vysokoúrovňového jazyka můžete mít zaručené, že pole ten jazyk ukládá jako jednotlivé prvky v paměti vedle sebe. Takže když použijete pole primitivních hodnot, nejde se vám do řádku cache několik hodnot. Když použijete spojový seznam, bude každá položka uložená v paměti někde jinde a procesor bude při průchodu kolekcí pořád jen čekat, než se nahrají data z paměti. A tohle je třeba rozdíl mezi java.util.ArrayList a java.util.LinkedList. Připadají vám Java, Scala nebo Clojure jako dostatečně vysokoúrovňové jazyky? Ano, Java je jen assembler nad bajtkódem, ale stejně…
ArrayList v jave bude vedle sebe ukladat jen reference. Kdyz chci hodnotu tak stejne musim hledat nekde v halde.
-
Já jsem o žádné flamewar zájem neměl. Text mého příspěvku k flamewar nenabádal.
Jasně. V názvu tématu se na něco ptáte, v textu rovnou odpovíte, arogantně a bez jakéhokoli vysvětlení. A pak to celou dobu přiživujete tím, že sice úplně nechápete základy, ale někde jste zahlédl něco úžasného, z čeho se všichni musí posadit na zadek. To vůbec není odstartování flamewaru…
IMHO není, záleží na backgroundu
-
ArrayList v jave bude vedle sebe ukladat jen reference. Kdyz chci hodnotu tak stejne musim hledat nekde v halde.
Podstatné v této diskusi je, že prvky kolekce ukládá do pole a javovské pole je v paměti uložené v souvislé paměti. Takže když primitivní typy uložíte přímo do pole nebo do kolekce, která umožňuje ukládat primitivní typy, má procesor ty hodnoty v paměti hned vedle sebe. Jinak ano, kolekce ve standardní knihovně Javy umožňují ukládat jen objekty, takže rozdíl mezi java.util.ArrayList a java.util.LinkedList je v tom, že první má odkaz, zatímco druhý má odkaz na odkaz.
-
Já jsem o žádné flamewar zájem neměl. Text mého příspěvku k flamewar nenabádal.
Jasně. V názvu tématu se na něco ptáte, v textu rovnou odpovíte, arogantně a bez jakéhokoli vysvětlení. A pak to celou dobu přiživujete tím, že sice úplně nechápete základy, ale někde jste zahlédl něco úžasného, z čeho se všichni musí posadit na zadek. To vůbec není odstartování flamewaru…
Neříká se tomuhle, co to Filip Jirsák předvádí trollování?
Co se mě týče, tak po dlouhé době je to téma které je zajímavé, takže já dávám BoneFlute +1.
-
Důležitější je asi obsah, než název. Název vlákna naznačuje, že jde o srovnání, ale text prvního příspěvku je jednoznačný pokus (úspěšný) o rozpoutání flamewar.
Já jsem o žádné flamewar zájem neměl. Text mého příspěvku k flamewar nenabádal. Ale beru tě jako nutné zlo.
Teď by tu všichni měli udělat krok zpět, nastudovat si ten Idris a pak pokračovat v debatě.
-
Teď by tu všichni měli udělat krok zpět, nastudovat si ten Idris a pak pokračovat v debatě.
Myslíte opravdu nastudovat, takže se tu sejdeme znova za pět let? Protože debatu „během půl hodiny jsem si něco přečetl a dospěl jsem k nezdravému přesvědčení“ už tu máme…
-
Teď by tu všichni měli udělat krok zpět, nastudovat si ten Idris a pak pokračovat v debatě.
Myslíte opravdu nastudovat, takže se tu sejdeme znova za pět let? Protože debatu „během půl hodiny jsem si něco přečetl a dospěl jsem k nezdravému přesvědčení“ už tu máme…
já bych navrhl začít s přirozenýma číslama a vektorama, to by pro tuto debatu mohlo stačit (substr...)
-
já bych navrhl začít s přirozenýma číslama a vektorama, to by pro tuto debatu mohlo stačit (substr...)
Já myslím, že problém nebude v tom, že bychom si tu nedokázali představit nacpat velikost vektoru do jeho typu. To je celkem jednoduché a umí to kdejaký jazyk. Problém je v tom, že ta potřebná velikost prostě není k dispozici, dokud program neběží u zákazníka.
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole. Pokud se ta typová kontrola bude provádět až zákazník načte data, tak si musím napsat testy i na ty typy.
-
*../idr/test> :t mysubstr
mysubstr : (p : Nat) -> (n : Nat) -> Vect (p + (n + more)) t -> Vect n t
*../idr/test> mysubstr 1 2 [10,20,30,40]
[20, 30] : Vect 2 Integer
*../idr/test> mysubstr 3 2 [10,20,30,40]
(input):1:15-16:When checking argument xs to constructor Data.Vect.:::
Type mismatch between
Vect 0 elem (Type of [])
and
Vect (S more) t (Expected type)
Specifically:
Type mismatch between
0
and
S more
<3
-
*../idr/test> :t mysubstr
mysubstr : (p : Nat) -> (n : Nat) -> Vect (p + (n + more)) t -> Vect n t
*../idr/test> mysubstr 1 2 [10,20,30,40]
[20, 30] : Vect 2 Integer
*../idr/test> mysubstr 3 2 [10,20,30,40]
(input):1:15-16:When checking argument xs to constructor Data.Vect.:::
Type mismatch between
Vect 0 elem (Type of [])
and
Vect (S more) t (Expected type)
Specifically:
Type mismatch between
0
and
S more
<3
Trvalo mi asi 10 minut nez jsem to pochopil, a pak jsem musel dalsich 10 minut rozdychavat ten naval endorfinu ::)
-
*../idr/test> :t mysubstr
mysubstr : (p : Nat) -> (n : Nat) -> Vect (p + (n + more)) t -> Vect n t
*../idr/test> mysubstr 1 2 [10,20,30,40]
[20, 30] : Vect 2 Integer
*../idr/test> mysubstr 3 2 [10,20,30,40]
(input):1:15-16:When checking argument xs to constructor Data.Vect.:::
Type mismatch between
Vect 0 elem (Type of [])
and
Vect (S more) t (Expected type)
Specifically:
Type mismatch between
0
and
S more
<3
Hezké, ale teď mě zajímá klíčová otázka: jak se to použije když budu chtít udělat prográmek, který přečte ze stdin p, zavolá na to mysubstr p 2 [10,20,30,40] , a výsledek vytiskne? Programy bez IO moc užitečné nebývají, že.. Poprosil bych přímo zdroják, je už to jen krůček... ?
-
Hezké, ale teď mě zajímá klíčová otázka: jak se to použije když budu chtít udělat prográmek, který přečte ze stdin p, zavolá na to mysubstr p 2 [10,20,30,40] , a výsledek vytiskne? Programy bez IO moc užitečné nebývají, že.. Poprosil bych přímo zdroják, je už to jen krůček... ?
předpokládám, že jste to zkusil napsat a nefunguje vám to, postněte tady váš kód a zkusíme to odladit :)
-
předpokládám, že jste to zkusil napsat a nefunguje vám to, postněte tady váš kód a zkusíme to odladit :)
potom mu neodpovíš, jak je tu zvykem. Protože sám nevíš, jak to napsat. Doufám, že s vámi ava nebude ztrácet čas, dokud neukážete váš kód.
-
Dospěl jsem k nezdravému přesvědčení, že jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?
No, je nejde (teoreticky) a nejde (prakticky).
Ja jsem dospel k presvedceni, ze testovat auta neni potreba, pokud je umite matematicky modelovat dokonale na urovni kazde molekuly.
Ostatne, je nejaky priklad konstrukce, kterou je nutne testovat v realnem svete, protoze ji nejde simulovat matematicko-fyzikalnim modelem?
-
Hezké, ale teď mě zajímá klíčová otázka: jak se to použije když budu chtít udělat prográmek, který přečte ze stdin p, zavolá na to mysubstr p 2 [10,20,30,40] , a výsledek vytiskne? Programy bez IO moc užitečné nebývají, že.. Poprosil bych přímo zdroják, je už to jen krůček... ?
předpokládám, že jste to zkusil napsat a nefunguje vám to, postněte tady váš kód a zkusíme to odladit :)
Nezkusil, a ani nevím jak na to. Opravdu prosím, obětujte 10 minut svého času, napište to a postněte to (přeložitelnou a spustitelnou verzi).
-
Teď by tu všichni měli udělat krok zpět, nastudovat si ten Idris a pak pokračovat v debatě.
Myslíte opravdu nastudovat, takže se tu sejdeme znova za pět let? Protože debatu „během půl hodiny jsem si něco přečetl a dospěl jsem k nezdravému přesvědčení“ už tu máme…
Pět let ne, stačilo by jen pochopit ty závislostní typy. Klidně i v jiném jazyce nebo jen ten teoretický koncept. Ono to není složité, pokud už chápete Curry-Howardovu korespondenci.
-
já bych navrhl začít s přirozenýma číslama a vektorama, to by pro tuto debatu mohlo stačit (substr...)
Já myslím, že problém nebude v tom, že bychom si tu nedokázali představit nacpat velikost vektoru do jeho typu. To je celkem jednoduché a umí to kdejaký jazyk. Problém je v tom, že ta potřebná velikost prostě není k dispozici, dokud program neběží u zákazníka.
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole. Pokud se ta typová kontrola bude provádět až zákazník načte data, tak si musím napsat testy i na ty typy.
To je brutální nepochopení závislostních typů. Který “kdejaký” jazyk to umí?
-
já bych navrhl začít s přirozenýma číslama a vektorama, to by pro tuto debatu mohlo stačit (substr...)
Já myslím, že problém nebude v tom, že bychom si tu nedokázali představit nacpat velikost vektoru do jeho typu. To je celkem jednoduché a umí to kdejaký jazyk. Problém je v tom, že ta potřebná velikost prostě není k dispozici, dokud program neběží u zákazníka.
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole. Pokud se ta typová kontrola bude provádět až zákazník načte data, tak si musím napsat testy i na ty typy.
To je brutální nepochopení závislostních typů. Který “kdejaký” jazyk to umí?
Přidat do typu rozsahy hodnot a i nějaký ten výraz s abstraktními proměnnými se dá i v C++ šablonách. Jasně, je to hnus a generuje to bloat, ale principielně to jde. Hrál jsem si právě s rozsahy polí a intů. Problém nastal na rozhraní kontrolovaného a normálního kódu. A ty kousky kontrolovaného kódu nemůžou být kdovíjak rozsáhlé, protože je to pro netriviální problémy občas i nerozhodnutelné.
Jedna věc je napsat funkci, ve které nemůže dojít k chybě. Druhá věc je tu funkci zavolat na reálná data. Zavolat to v konzoli přes REPL toho moc neukáže.
-
já bych navrhl začít s přirozenýma číslama a vektorama, to by pro tuto debatu mohlo stačit (substr...)
Já myslím, že problém nebude v tom, že bychom si tu nedokázali představit nacpat velikost vektoru do jeho typu. To je celkem jednoduché a umí to kdejaký jazyk. Problém je v tom, že ta potřebná velikost prostě není k dispozici, dokud program neběží u zákazníka.
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole. Pokud se ta typová kontrola bude provádět až zákazník načte data, tak si musím napsat testy i na ty typy.
To je brutální nepochopení závislostních typů. Který “kdejaký” jazyk to umí?
Přidat do typu rozsahy hodnot a i nějaký ten výraz s abstraktními proměnnými se dá i v C++ šablonách. Jasně, je to hnus a generuje to bloat, ale principielně to jde. Hrál jsem si právě s rozsahy polí a intů. Problém nastal na rozhraní kontrolovaného a normálního kódu. A ty kousky kontrolovaného kódu nemůžou být kdovíjak rozsáhlé, protože je to pro netriviální problémy občas i nerozhodnutelné.
Jedna věc je napsat funkci, ve které nemůže dojít k chybě. Druhá věc je tu funkci zavolat na reálná data. Zavolat to v konzoli přes REPL toho moc neukáže.
IMHO je důležité, aby s těmi hodnotami v typech šla dělat aritmetika a podobné “výpočty”. Jak to je v C++ nevím, ale tam to bude asi dost omezené. V jazycích jako zmíněný Idris (nebo třeba Coq, ten ale blíže neznám) je typový systém v podstatě dokazovač, kde jde napsat libovolná logická formule s proměnnými.
-
IMHO je důležité, aby s těmi hodnotami v typech šla dělat aritmetika a podobné “výpočty”. Jak to je v C++ nevím, ale tam to bude asi dost omezené.
Šablony jsou výpočetně úplné. Jen syntaxe je hnusná.
V jazycích jako zmíněný Idris (nebo třeba Coq, ten ale blíže neznám) je typový systém v podstatě dokazovač, kde jde napsat libovolná logická formule s proměnnými.
Napsat jo. Ale porovnat dvě formule je obecně nerozhodnutelný problém, jestli se nepletu. Nebo je to minimálně NP-úplné.
-
IMHO je důležité, aby s těmi hodnotami v typech šla dělat aritmetika a podobné “výpočty”. Jak to je v C++ nevím, ale tam to bude asi dost omezené.
Šablony jsou výpočetně úplné. Jen syntaxe je hnusná.
To ano, právě o to jde, aby v těch typech (šablonách) šly psát výrazy a používat operátory nad typy. V C++ by to asi šlo s variantem taky, ale vidět bych si to nepřál.
-
V jazycích jako zmíněný Idris (nebo třeba Coq, ten ale blíže neznám) je typový systém v podstatě dokazovač, kde jde napsat libovolná logická formule s proměnnými.
Napsat jo. Ale porovnat dvě formule je obecně nerozhodnutelný problém, jestli se nepletu. Nebo je to minimálně NP-úplné.
O tom se v té knížce píše taky. Logika je sice jen semirozhodnutelná, ale ve většině praktických případů je typová kontrola rozhodnutelná. Ostatně i v C++ se dají napsat šablony, které překladač zacyklí, ale u běžných programů k tomu nedochází.
-
O tom se v té knížce píše taky. Logika je sice jen semirozhodnutelná, ale ve většině praktických případů je typová kontrola rozhodnutelná. Ostatně i v C++ se dají napsat šablony, které překladač zacyklí, ale u běžných programů k tomu nedochází.
Jop, tady souhlasím.
Pořád ale netuším, jak tímhle typovým systémem nahradím (takhle to tu totiž BoneFlute celou dobu propaguje) ty zmiňované unittesty. Jo, něco to pochopitelně zkontroluje a ulehčí práci. S tím nemám problém. Ale pořád vidím dva zásadní problémy :
1) Data pocházejí zvenku. Už jsem psal, že já se svým hraním skončil na rozhraní, kde bylo třeba ta data konvertovat. A na něco podobného se tu ptal i ava.
2) A i ty samotné typy přestávají být triviální. Místo testování kódu abych napsal testy na typy.
-
A i ty samotné typy přestávají být triviální. Místo testování kódu abych napsal testy na typy.
:D
Na tom něco, ve vší vážnosti, bude. Já to vždy chápal tak, že závislostní typy jsou něco jako asserty, akorát v době překladu. Tzn. deklarativní vyjádření nutně splněných podmínek. Ještě bych dodal, že záv. typy dávají smysl jen ve funkcionálních jazycích.
-
Já to vždy chápal tak, že závislostní typy jsou něco jako asserty, akorát v době překladu. Tzn. deklarativní vyjádření nutně splněných podmínek.
to mi připomělo tohle:
A recurring method in dependently typed programming is to program with data structures that enforce coherence of their indices, even though they contain no bits themselves...leaving said data-bearing indices entirely implicit.
(McBride na twitteru)
-
Hezké, ale teď mě zajímá klíčová otázka: jak se to použije když budu chtít udělat prográmek, který přečte ze stdin p, zavolá na to mysubstr p 2 [10,20,30,40] , a výsledek vytiskne? Programy bez IO moc užitečné nebývají, že.. Poprosil bych přímo zdroják, je už to jen krůček... ?
předpokládám, že jste to zkusil napsat a nefunguje vám to, postněte tady váš kód a zkusíme to odladit :)
Nezkusil, a ani nevím jak na to. Opravdu prosím, obětujte 10 minut svého času, napište to a postněte to (přeložitelnou a spustitelnou verzi).
dostat ze stdin Nat by mělo být triviální, potom je třeba "dokázat" že hodnota pasuje k danému vektoru, to by mělo být relativně snadné (vím jak bych to dělal v haskellu), ale v idrisu to zatím neumím (možná overLength?), zatím jsem v něm programoval cca deset minut, pokud se to pokusíte naprogramovat a postnete sem kód, budu se tím zabývat dál
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
načte se řetězec a pak se z něj udělá Nat
*Data/String> the (Maybe Nat) (parsePositive "1")
Just 1 : Maybe Nat
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
načte se řetězec a pak se z něj udělá Nat
*Data/String> the (Maybe Nat) (parsePositive "1")
Just 1 : Maybe Nat
Jde o to, jak načtu Nat po kompilaci. Nat je typ s teorií následník/nula, ne? To bych musel nejdřív načíst číslo a pak program přeložit se vstupem jako konstantou.
-
A i ty samotné typy přestávají být triviální. Místo testování kódu abych napsal testy na typy.
:D
Na tom něco, ve vší vážnosti, bude.
A to je navíc testování toho, že se něco opravdu nepřeloží, strašný opruz. Ručně je to ok, ale jak to chce člověk trochu zautomatizovat, aby si omylem něco nerozbil, tak aby si na to psal scripty. A ještě nějak zkontrolovat, jestli se to nepřeložilo ze správného důvodu. :D
Já to vždy chápal tak, že závislostní typy jsou něco jako asserty, akorát v době překladu. Tzn. deklarativní vyjádření nutně splněných podmínek. Ještě bych dodal, že záv. typy dávají smysl jen ve funkcionálních jazycích.
Ona hranice funkcionálního jazyka není úplně ostrá. Třeba na novém C++ je vliv Haskellu a podobných jazyků hodně vidět.
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
načte se řetězec a pak se z něj udělá Nat
*Data/String> the (Maybe Nat) (parsePositive "1")
Just 1 : Maybe Nat
Jde o to, jak načtu Nat po kompilaci. Nat je typ s teorií následník/nula, ne? To bych musel nejdřív načíst číslo a pak program přeložit se vstupem jako konstantou.
hm, to by bylo blbé
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
načte se řetězec a pak se z něj udělá Nat
*Data/String> the (Maybe Nat) (parsePositive "1")
Just 1 : Maybe Nat
Jde o to, jak načtu Nat po kompilaci. Nat je typ s teorií následník/nula, ne? To bych musel nejdřív načíst číslo a pak program přeložit se vstupem jako konstantou.
hm, to by bylo blbé
Měl jsem za to, že tento problém každý vidí.
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
načte se řetězec a pak se z něj udělá Nat
*Data/String> the (Maybe Nat) (parsePositive "1")
Just 1 : Maybe Nat
Jde o to, jak načtu Nat po kompilaci. Nat je typ s teorií následník/nula, ne? To bych musel nejdřív načíst číslo a pak program přeložit se vstupem jako konstantou.
hm, to by bylo blbé
Měl jsem za to, že tento problém každý vidí.
No pro mě právě tohle taky bylo záhadou. Trochu mi pomohly následující články:
https://stackoverflow.com/questions/48128884/
https://news.ycombinator.com/item?id=12349899
tedy pomohly spíš tak, že už vidím, že na konci tunelu může být světlo, než že by se mi vysloveně rozsvítilo.
Každopádně co se týče (abych trochu poskočil v tématu) původního dotazu BoneFluteho, mám dost podobný dojem jako Jirsák, že BoneFlute našel novou modlu, o které téměř nic neví, ale o to více ji chválí. Tím dependent typy nechci shazovat, je možné že se v budoucnu ukáží užitečné a rozšíří se. Abych ovšem byl také trochu konstruktivní a vyjádřil se k původnímu dotazu, podle mě dependent typy nemohou nahradit unit testy v následujícím:
Dependent typy z principu nemohou dokázat korektnost např. převodu stringu na číslo. Jak by se v typu fce convert: String -> Maybe Nat vyjádřilo, zda se očekává stringový vstup v desítkové nebo šestnáctkové soustavě? Podle mě je to principiálně nemožné, a stejně tak není možné ani vyjádřit korektnost implementace převodu. V Idris se asi dá vyjádřit, že funkce doběhne, a že nezpanikaří, ale to je málo.
Unit testy slouží jako vždy up-to-date dokumentace. U jednoduchých věcí se dá samozřejmě hodně věcí vyčíst z typů (hezký příklad je tady: http://funkcionalne.cz/2014/08/types-will-carry-you-over-the-monads/), ale u složitějších je prostě hezké mít chování zdokumentované na příkladech, místo potřeby rozjímat nad důsledky komplikované typové signatury. Navíc je slušnost mít knihovny zdokumentované, tak proč to rovnou nedělat unit testy? (podívejte např. sem: https://doc.rust-lang.org/std/iter/trait.Iterator.html), všechny Examples jsou rovnou spustitelné unittesty zapsané do docstringů funkcí.
Unit testy jednoduchým způsobem ověřují chování v krajních a nečekaných případech. Když jsem psal implementaci funkce testující, zda je bod uvnitř polygonu, rovnou napíšu test, jak se chová bod na hraně, jak se chová v polygonu, který není uzavřený, jak se chová v polygonu který protíná sám sebe. Nedovedu si představit, jak by mohlo být takové chování zřejmé z typu funkce. Možná, až BoneFlute přestane "být stále student", nějak pěkně to vyřeší, to by mě pak docela zajímalo.
Unit testy jsou šablony funkčního kódu, který používá knihovnu kanonickým způsobem. Kód mohu copy'n'pastnout do vlastního projektu a upravit podle potřeby. Typy tohle neumí.
Na závěr: Typy a unit testy se doplňují, líbí se mi tahle asi minuta a půl: https://www.youtube.com/watch?v=pMgmKJyWKn8&feature=youtu.be&t=317
-
dostat ze stdin Nat by mělo být triviální
Jak se to dělá?
načte se řetězec a pak se z něj udělá Nat
*Data/String> the (Maybe Nat) (parsePositive "1")
Just 1 : Maybe Nat
Jde o to, jak načtu Nat po kompilaci. Nat je typ s teorií následník/nula, ne? To bych musel nejdřív načíst číslo a pak program přeložit se vstupem jako konstantou.
hm, to by bylo blbé
Měl jsem za to, že tento problém každý vidí.
No pro mě právě tohle taky bylo záhadou. Trochu mi pomohly následující články:
https://stackoverflow.com/questions/48128884/
https://news.ycombinator.com/item?id=12349899
tedy pomohly spíš tak, že už vidím, že na konci tunelu může být světlo, než že by se mi vysloveně rozsvítilo.
Každopádně co se týče (abych trochu poskočil v tématu) původního dotazu BoneFluteho, mám dost podobný dojem jako Jirsák, že BoneFlute našel novou modlu, o které téměř nic neví, ale o to více ji chválí. Tím dependent typy nechci shazovat, je možné že se v budoucnu ukáží užitečné a rozšíří se. Abych ovšem byl také trochu konstruktivní a vyjádřil se k původnímu dotazu, podle mě dependent typy nemohou nahradit unit testy v následujícím:
Dependent typy z principu nemohou dokázat korektnost např. převodu stringu na číslo. Jak by se v typu fce convert: String -> Maybe Nat vyjádřilo, zda se očekává stringový vstup v desítkové nebo šestnáctkové soustavě? Podle mě je to principiálně nemožné, a stejně tak není možné ani vyjádřit korektnost implementace převodu. V Idris se asi dá vyjádřit, že funkce doběhne, a že nezpanikaří, ale to je málo.
Unit testy slouží jako vždy up-to-date dokumentace. U jednoduchých věcí se dá samozřejmě hodně věcí vyčíst z typů (hezký příklad je tady: http://funkcionalne.cz/2014/08/types-will-carry-you-over-the-monads/), ale u složitějších je prostě hezké mít chování zdokumentované na příkladech, místo potřeby rozjímat nad důsledky komplikované typové signatury. Navíc je slušnost mít knihovny zdokumentované, tak proč to rovnou nedělat unit testy? (podívejte např. sem: https://doc.rust-lang.org/std/iter/trait.Iterator.html), všechny Examples jsou rovnou spustitelné unittesty zapsané do docstringů funkcí.
Unit testy jednoduchým způsobem ověřují chování v krajních a nečekaných případech. Když jsem psal implementaci funkce testující, zda je bod uvnitř polygonu, rovnou napíšu test, jak se chová bod na hraně, jak se chová v polygonu, který není uzavřený, jak se chová v polygonu který protíná sám sebe. Nedovedu si představit, jak by mohlo být takové chování zřejmé z typu funkce. Možná, až BoneFlute přestane "být stále student", nějak pěkně to vyřeší, to by mě pak docela zajímalo.
Unit testy jsou šablony funkčního kódu, který používá knihovnu kanonickým způsobem. Kód mohu copy'n'pastnout do vlastního projektu a upravit podle potřeby. Typy tohle neumí.
Na závěr: Typy a unit testy se doplňují, líbí se mi tahle asi minuta a půl: https://www.youtube.com/watch?v=pMgmKJyWKn8&feature=youtu.be&t=317
Jak tak čtu tu Bradyho knihu podrobněji, docházím k názoru, že psaní kódu se záv. typy je prostě jiné paradigma a vyžaduje úplně jiné myšlení u než třeba Haskell (ten v porovnání s Idrisem vůbec není abstraktní).
-
Já myslím, že problém nebude v tom, že bychom si tu nedokázali představit nacpat velikost vektoru do jeho typu. To je celkem jednoduché a umí to kdejaký jazyk. Problém je v tom, že ta potřebná velikost prostě není k dispozici, dokud program neběží u zákazníka.
Ona ale je k dispozici, v existenčním typu.
-
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole.
Toto je zásadní omyl. Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec). Za to můžeme poděkovat Currymu a Howardovi (nezávisle). Můžu mít například funkci getVect, co mi načte od uživatele vektor nad ω libovolné délky (typu IO (Maybe ((n:Nat) ** Vect n Nat))). Where's the problem?
-
chcete refinement types
https://github.com/fthomas/refined
https://ucsd-progsys.github.io/liquidhaskell-blog/
-
Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec).
Nevidím nic matoucího na tom, že se to nazývá typová kontrola – je to přesně to, co lidé znají z JavaScriptu, Pythonu, C nebo Javy, akorát je to na škále důslednosti kontrol ještě dál, než Java nebo C. A tím, jak je to na škále ještě dál, zvětšuje se množství chyb, které dokáže typová kontrola odhalit, a zároveň jsou ty typy čím dál víc svazující a musí se různě „obcházet“.
U dynamicky typovaných jazyků je s hodnotami pracuje tak, že teprve když něco od hodnoty potřebuju, zjistím, zda je požadovaného typu. Třeba uživatel něco zadá, a teprve tam, kde s tím chci pracovat jako s číslem, zjistím, jestli to číslo je. Když někdo přejde na C nebo Javu, může mu připadat svazující, že musí typ určit dopředu a problém s tím, že uživatel nezadal číslo, musí řešit daleko dřív, třeba i zbytečně, protože by se k tomu zpracování jako čísla ani nedostal. Podobně svazující jsou dál generické typy, třeba u kolekcí – bez generických typů si do kolekce naházím jaké objekty mne napadne, a typy řeším až při jejich použití. S generickými kolekcemi najednou musím řešit typ prvků a mám problém do jedné kolekce dostat různé typy. Spousta věcí se přitom vyřeší tak, že „to nemůže nastat“. Třeba vím, že do kolekce strkám jenom stringy, takže nemusím řešit, že by se tam objevilo něco jiného. A závislostní typy jdou ještě dál.
Třeba obyčejné sčítání dvou čísel. V C nebo Javě sečtu dvě 32bitová čísla, a výsledek uložím opět do 32bitové hodnoty. Protože vím, že se tam budou sčítat malá čísla a přetečení „nemůže nastat“. Závislostní typy tohle neumožní, součet dvou 32bitových čísel musím uložit jako 64bitové číslo (nebo jako 33bitové, pokud bude takový typ povolen). A k tomu můžu chtít přičíst další číslo, a můžu dokonce chtít udělat sumu neznámého prvku čísel. Najednou musím řešit „hypotetické“ problémy, které bych v Javě nebo C řešit nemusel, protože přece vím, že tak velká čísla se tam nikdy sčítat nebudou – a jestli bude mít někdo problém, že se suma transakcí na jeho bankovním účtu nevejde do 32bitového čísla, tak mu to rád za nějaké promile z jeho zisku upravím. Stejně tak v Javě nebo C musím řešit „hypotetické“ problémy, které bych nemusel řešit v dynamicky typovaném jazyce.
Přísnost typové kontroly je pak jenom otázka míry, nalezení optimální hranice, kdy při dalším zpřísňování kontrol už nenajdu žádné reálné chyby, za to budu muset řešit „hlouposti“ typu „co kdyby firma měla trilion zaměstnanců“. Když pojedu vlakem, budu radši, když zabezpečovací zařízení bude používat závislostní typy a bude logicky dokázané, že nemůže pustit dva vlaky proti sobě (pokud o nich ví, že), u multimideálního systému pro výběr videa zabudovaného v sedačce přede mnou mi naopak vůbec nebude vadit použití dynamického typování.
-
smysluplné použití závislostních typů je compile time kontrola tvarů matic a tenzorů.
-
Když pojedu vlakem, budu radši, když zabezpečovací zařízení bude používat závislostní typy a bude logicky dokázané, že nemůže pustit dva vlaky proti sobě
A vo tom to je :)
A když už jsme u toho, víte o jiných jazycích se záv. typy krom Idrisu, Agdy a Coqu, zejména takových, co se používají v praxi v kritických aplikacích?
-
A když už jsme u toho, víte o jiných jazycích se záv. typy krom Idrisu, Agdy a Coqu, zejména takových, co se používají v praxi v kritických aplikacích?
Ony se podle mne tolik nepoužívají ani u kritických aplikací. Tam se to pokud vím řeší spíš tak, že je to naprogramované dvakrát nezávisle na sobě a běží to na dvou nezávislých zařízeních. Pokud se na výsledku neshodnou, následuje reset do nějakého bezpečného stavu.
-
Když pojedu vlakem, budu radši, když zabezpečovací zařízení bude používat závislostní typy a bude logicky dokázané, že nemůže pustit dva vlaky proti sobě
A vo tom to je :)
A když už jsme u toho, víte o jiných jazycích se záv. typy krom Idrisu, Agdy a Coqu, zejména takových, co se používají v praxi v kritických aplikacích?
spark ada možná? ale to bude trochu zvláštní případ
-
A když už jsme u toho, víte o jiných jazycích se záv. typy krom Idrisu, Agdy a Coqu, zejména takových, co se používají v praxi v kritických aplikacích?
Ony se podle mne tolik nepoužívají ani u kritických aplikací. Tam se to pokud vím řeší spíš tak, že je to naprogramované dvakrát nezávisle na sobě a běží to na dvou nezávislých zařízeních. Pokud se na výsledku neshodnou, následuje reset do nějakého bezpečného stavu.
viz IEC61508
-
Každopádně co se týče (abych trochu poskočil v tématu) původního dotazu BoneFluteho, mám dost podobný dojem jako Jirsák, že BoneFlute našel novou modlu, o které téměř nic neví, ale o to více ji chválí. Tím dependent typy nechci shazovat, je možné že se v budoucnu ukáží užitečné a rozšíří se.
Psal jsem hned můj první příspěvek: "získal jsem nezdravé přesvědčení". A nebo, že "A snažím se zchladit své nadšení hledáním, kde to má hranice." Taky jsem psal, že se snažím použít typy co to jde, a na zbytek testy.
Vidět v tom, že o tom nic nevím, nebo, že jsem si v tom našel modlu chce hodně fantazie.
Pište co k tomu víte. Na posuzování znalostí druhých tu máme Jirsáka.
-
Každopádně co se týče (abych trochu poskočil v tématu) původního dotazu BoneFluteho, mám dost podobný dojem jako Jirsák, že BoneFlute našel novou modlu, o které téměř nic neví, ale o to více ji chválí. Tím dependent typy nechci shazovat, je možné že se v budoucnu ukáží užitečné a rozšíří se.
Psal jsem hned můj první příspěvek: "získal jsem nezdravé přesvědčení". A nebo, že "A snažím se zchladit své nadšení hledáním, kde to má hranice." Taky jsem psal, že se snažím použít typy co to jde, a na zbytek testy.
Vidět v tom, že o tom nic nevím, nebo, že jsem si v tom našel modlu chce hodně fantazie.
Pište co k tomu víte. Na posuzování znalostí druhých tu máme Jirsáka.
Ok, beru osobní věci zpět. Každopádně můj příspěvek byl z výrazně větší části k tématu, možná bys tedy mohl zareagovat spíš na ty věcné kusy.
1) K původní otázce - psal jsem příklad, že podle mě není možné pomocí dependent typů ověřit korektnost funkce stringToNum: String -> Maybe Nat. V praxi je přitom asi v každém užitečném programu třeba parsovat uživatelský vstup, čili dělat něco podobného.
2) Už samotná otázka je, nevím jestli úmyslně, zavádějící: "Zajímalo by mě, můžete zkusit uvést nějaký příklad konstrukce, na kterou je nutné napsat test, protože typem to podchytit nejde?". Jak jsem uváděl v předchozím příspěvku, význam unit testů zdaleka není jen v tom, že ověřují správnost nějaké konstrukce. Jejich hodnota je i v dalších aspektech, které typy nemají.
-
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole.
Toto je zásadní omyl. Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec). Za to můžeme poděkovat Currymu a Howardovi (nezávisle). Můžu mít například funkci getVect, co mi načte od uživatele vektor nad ω libovolné délky (typu IO (Maybe ((n:Nat) ** Vect n Nat))). Where's the problem?
K tomu IO, nechápu význam IO (), proč to může jít do >>=, když ten vnitřní typ nemá žádné hodnoty?
-
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole.
Toto je zásadní omyl. Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec). Za to můžeme poděkovat Currymu a Howardovi (nezávisle). Můžu mít například funkci getVect, co mi načte od uživatele vektor nad ω libovolné délky (typu IO (Maybe ((n:Nat) ** Vect n Nat))). Where's the problem?
K tomu IO, nechápu význam IO (), proč to může jít do >>=, když ten vnitřní typ nemá žádné hodnoty?
() je normální hodnota
Idris> ()
() : ()
-
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole.
Toto je zásadní omyl. Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec). Za to můžeme poděkovat Currymu a Howardovi (nezávisle). Můžu mít například funkci getVect, co mi načte od uživatele vektor nad ω libovolné délky (typu IO (Maybe ((n:Nat) ** Vect n Nat))). Where's the problem?
K tomu IO, nechápu význam IO (), proč to může jít do >>=, když ten vnitřní typ nemá žádné hodnoty?
() je normální hodnota
Idris> ()
() : ()
() je typ ;) Je to void bez hodnot.
-
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole.
Toto je zásadní omyl. Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec). Za to můžeme poděkovat Currymu a Howardovi (nezávisle). Můžu mít například funkci getVect, co mi načte od uživatele vektor nad ω libovolné délky (typu IO (Maybe ((n:Nat) ** Vect n Nat))). Where's the problem?
K tomu IO, nechápu význam IO (), proč to může jít do >>=, když ten vnitřní typ nemá žádné hodnoty?
() je normální hodnota
Idris> ()
() : ()
() je typ ;) Je to void bez hodnot.
neřekl bych, viz https://github.com/idris-lang/Idris-dev/blob/master/libs/prelude/Builtins.idr
() je Unit, typ s jednou hodnotou
-
Pořádná typová kontrola prostě musí probíhat v mé pracovní době a pokud možno u mně na stole.
Toto je zásadní omyl. Nad záv. typy se korektnost dokazuje symbolicky, nevadí, není-li nějaká hodnota známa. Matoucí IMHO je, že se tomu říká typová kontrola, kterou lidi znají tak nanejvýš z Javy nebo céčka (pythonisti a spol. vůbec). Za to můžeme poděkovat Currymu a Howardovi (nezávisle). Můžu mít například funkci getVect, co mi načte od uživatele vektor nad ω libovolné délky (typu IO (Maybe ((n:Nat) ** Vect n Nat))). Where's the problem?
K tomu IO, nechápu význam IO (), proč to může jít do >>=, když ten vnitřní typ nemá žádné hodnoty?
() je normální hodnota
Idris> ()
() : ()
() je typ ;) Je to void bez hodnot.
neřekl bych, viz https://github.com/idris-lang/Idris-dev/blob/master/libs/prelude/Builtins.idr
() je Unit, typ s jednou hodnotou
Jo, mea culpa, sorry :-\
-
stane se
-
stane se
Pořád to ale neodpovídá na tu otázku.
-
stane se
Pořád to ale neodpovídá na tu otázku.
jaké je její aktuální znění?
-
stane se
Pořád to ale neodpovídá na tu otázku.
jaké je její aktuální znění?
"význam IO (), proč to může jít do >>="
-
stane se
Pořád to ale neodpovídá na tu otázku.
jaké je její aktuální znění?
"význam IO (), proč to může jít do >>="
Podle mě tu jsou otázky v podstatě dvě: Jakou vnitřní hodnotu vrací putStr (to je jeho výstupní typ) a co se cpe do getLine apod., když to jsou konstanty. Mě vysvětlení je, že něco jako
do
putStr “...”
x <- getLine
je ve skutečnosti putStr “...” >>= \_ => getLine, kde se využije toho, že ta konstanta je isomorfní s funkcí A1.
-
Ok, beru osobní věci zpět. Každopádně můj příspěvek byl z výrazně větší části k tématu, možná bys tedy mohl zareagovat spíš na ty věcné kusy.
Byl. Už jsem si myslel, že to tady nikoho nezajímá ;-)
Dependent typy z principu nemohou dokázat korektnost např. převodu stringu na číslo. Jak by se v typu fce convert: String -> Maybe Nat vyjádřilo, zda se očekává stringový vstup v desítkové nebo šestnáctkové soustavě? Podle mě je to principiálně nemožné, a stejně tak není možné ani vyjádřit korektnost implementace převodu. V Idris se asi dá vyjádřit, že funkce doběhne, a že nezpanikaří, ale to je málo.
Já v těch závislostních typech nejsem kovanej, takže takto si to předstvuju v pseudokódu, jak to chápe typový systém:
parseFromDec :: Str -> Int = ('0' -> 0) | ('1' -> 1) | ... | ('9' -> 9)
případně
parseFromDecM :: Str -> Maybe Int = ('0' -> Just 0) | ('1' -> Just 1) | ... | ('9' -> Just 9) | _ -> Nothing
Plus nějaká recurze.
Píšu, že tak to chápe ten typovej systém, ne, že to tak bude psát programátor. Ten na to musí mět nějaký cukřík - ale tady se zase dostávám do oblasti praktičnosti, a to nepovažuji za námět mé otázky.
Unit testy slouží jako vždy up-to-date dokumentace. U jednoduchých věcí se dá samozřejmě hodně věcí vyčíst z typů (hezký příklad je tady: http://funkcionalne.cz/2014/08/types-will-carry-you-over-the-monads/), ale u složitějších je prostě hezké mít chování zdokumentované na příkladech, místo potřeby rozjímat nad důsledky komplikované typové signatury. Navíc je slušnost mít knihovny zdokumentované, tak proč to rovnou nedělat unit testy? (podívejte např. sem: https://doc.rust-lang.org/std/iter/trait.Iterator.html), všechny Examples jsou rovnou spustitelné unittesty zapsané do docstringů funkcí.
Obecně s tebou naprosto souhlasím. Však já jsem nikde nepsal, že testy jsou zlo.
Ale co by si řekl na to, když by ty ukázkové příklady generoval stroj na požádání? Vzal by sis nějakou funkci, předal jí třeba první argument (a nebo žádný), a stroj by si domyslel tři různé příklady a výsledky, a ty by ti ukázal.
Ono totiž moje zkušenost je taková, že ty ukázky jsou sice fajn, ale stejně mě vždycky zajímala hlavně ta myšlenka, jakási idea té funkce/knihovny/kódu. A na tu většinou autoři zapomínaj - tam ti testy (ale ani typy) nepomůžou.
Unit testy jednoduchým způsobem ověřují chování v krajních a nečekaných případech. Když jsem psal implementaci funkce testující, zda je bod uvnitř polygonu, rovnou napíšu test, jak se chová bod na hraně, jak se chová v polygonu, který není uzavřený, jak se chová v polygonu který protíná sám sebe. Nedovedu si představit, jak by mohlo být takové chování zřejmé z typu funkce. Možná, až BoneFlute přestane "být stále student", nějak pěkně to vyřeší, to by mě pak docela zajímalo.
Byl jsem línej, a napsal jsem si generátor unittestů. Takovej ten postup, kdy si napíšeš prototyp, a pak na něj začneš psát testy - úplně špatně podle TDD, já vím.
Ten generátor měl takové patterny: Int = [INT_MIN, -2, -1, 0, 1, 2, INT_MAX], plus jednoduchá kombinatorika.
Možná, opravdu jen možná, by se z těchto základních patternů dali komponovat/odvozovat složitější třeba pro ten polygon.
Z typu funkce to asi zřejmé nebude. Ale když by ten stroj dokázal vygenerovat ukázky na požádání?
Unit testy jsou šablony funkčního kódu, který používá knihovnu kanonickým způsobem. Kód mohu copy'n'pastnout do vlastního projektu a upravit podle potřeby. Typy tohle neumí.
Viz ten generátor.
A co se týče kanonického způsobu, je otázka jak k tomu přistupovat. Z Haskellu jsem zvyklej, že jinak, než kanonicky to napsat nejde. Prostě ti to nedovolí. (Jen jednou se mi stalo, že jsem kompilátoru zamotal hlavu takovým způsobem, že mi kód napůl blbě přeložil. A bůví, so jsem to ve skutečnosti prováděl.)
-
Ale co by si řekl na to, když by ty ukázkové příklady generoval stroj na požádání? Vzal by sis nějakou funkci, předal jí třeba první argument (a nebo žádný), a stroj by si domyslel tři různé příklady a výsledky, a ty by ti ukázal.
[…]
Byl jsem línej, a napsal jsem si generátor unittestů. Takovej ten postup, kdy si napíšeš prototyp, a pak na něj začneš psát testy - úplně špatně podle TDD, já vím.
Ten generátor měl takové patterny: Int = [INT_MIN, -2, -1, 0, 1, 2, INT_MAX], plus jednoduchá kombinatorika.
To jsou ale úplně triviální funkce, kterých je maličko a pro které se jednotkové testy píšou spíš pro pocit, že testy pokrývám opravdu maximum kódu (navíc se na nich dá snadno nahnat procento pokrytí testy), než že by někdo věřil, že ten test opravdu odhalí nějakou chybu. Mnohem zajímavější a užitečnější testy jsou na takové funkce, u kterých není takhle na první pohled patrné, co jsou ty významné hodnoty, se kterými je vhodné funkci testovat.
-
Dependent typy z principu nemohou dokázat korektnost např. převodu stringu na číslo. Jak by se v typu fce convert: String -> Maybe Nat vyjádřilo, zda se očekává stringový vstup v desítkové nebo šestnáctkové soustavě? Podle mě je to principiálně nemožné, a stejně tak není možné ani vyjádřit korektnost implementace převodu. V Idris se asi dá vyjádřit, že funkce doběhne, a že nezpanikaří, ale to je málo.
Já v těch závislostních typech nejsem kovanej, takže takto si to předstvuju v pseudokódu, jak to chápe typový systém:
parseFromDec :: Str -> Int = ('0' -> 0) | ('1' -> 1) | ... | ('9' -> 9)
případně
parseFromDecM :: Str -> Maybe Int = ('0' -> Just 0) | ('1' -> Just 1) | ... | ('9' -> Just 9) | _ -> Nothing
Plus nějaká recurze.
Zkusím tady nadhodit myšlenkový experiment, který snad ukáže, co se mi celé na té myšlence náhrady testů typy nelíbí.
Testy by vypadaly asi takhle (pseudokód):
assert(parseFromDecM "0" == Just 0)
assert(parseFromDecM "42" == Just 42)
assert(parseFromDecM "foo" == Nothing)
assert(parseFromDecM "" == Nothing) // Empty string is not a zero, but parse error
assert(parseFromDecM " 42" == Nothing) // Whitespace results in parse error
∀x: Int( assert(parseFromDecM . toString x == Just x ) // quickcheck test
Když píšu TDD, tedy nejprve testy, rovnou si rozmyslím, co má implementace umět. Dovedu si třeba dost představit, že naivní implementace by pro prázdný string vrátila 0. Neříkám že je to nutně špatně, ale možná že jo, a určitě je dobré mít takové chování zdokumentované. Když píšu testy first, ještě před implementací si chování rozmyslím. Navíc jsem vybral takové příklady, které dobře vystihují "ideu" chování, tady si myslím přesný opak toho co ty, testy jsou pro vystižení myšlenky funkce dost užitečné, naopak nějaké generátory unit testů tam tu "intuici za smyslem funkce" nemají moc šanci postihnout.
A teď dejme tomu, že bych chtěl implementovat tu samou funkci v nějakém vysněném jazyce s typovým systémem který mi umožní úplně všechno co chci.
Když jí dám typ String -> Maybe Int, je možné udělat nekorektní implementaci, to je z typu evidentní. Není například jasné, jestli je převod každé jedné číslice správně implementován (je to převod z binární soustavy? šestnáctové? desítkové?).
Tak do typu přidáme omezení na převodní funkci: String -> (Char -> Maybe Int) -> Maybe Int.
Pořád můžeme mít nekorektní implementaci. Co když by funkce brala znaky ze stringu v opačném pořadí? V rekurzi a násobení základem 10 se člověk snadno sekne... Tak přidáme nějaké hypotetické omezení TraversalOrder. Typová signatura nám naroste na String -> (Char -> Maybe Int) -> TraversalOrder -> Maybe Int. Ale chybí nám tu vlastně ten základ 10, kterým se to má násobit, a ten je navíc svázaný s funkcí ze znaku do čísla. No tak uděláme nějaké String -> ({convertDigit: Char -> Maybe Intů base: Int}) -> TraversalOrder -> Maybe Int. A taky potřebujeme nějak zahrnout speciální případ, že prázdný string není Just 0 ale Nothing. Naštěstí můj typový systém umí trochu číst myšlenky: OnEmptyInputNothing: String -> ({convertDigit: Char -> Maybe Int, base: Int}) -> TraversalOrder -> Maybe Int. Taky bych asi měl dodat, že všechny znaky se skutečně použijí, atp.... Každopádně pokud bych chtěl pomocí typového systému opravdu dokázat 100% korektnost implementace, v zásadě musím v tom typovém systému tu implementaci nakonec naimplementovat znovu, což jaksi nedává smysl, a jak už tu někdo psal, stejně bych pak asi pro jistotu ještě musel napsat testy na ty typy...
Možná, opravdu jen možná, by se z těchto základních patternů dali komponovat/odvozovat složitější třeba pro ten polygon.
Z typu funkce to asi zřejmé nebude. Ale když by ten stroj dokázal vygenerovat ukázky na požádání?
Myslím, že alespoň v tom, co dělám já, by ty ukázky často byly k ničemu. Třeba u toho polygonu by ze stroje vypadla řada čísel - souřadnic bodů polygonu, ale dokud si to nenakreslíš, tak nevidíš co to vlastně testuje. A to už je jednodušší si ty zajímavé příklady nejprve nakreslit a potom je, u komplikovaných případů třeba i okomentované a s naskenovaným obrázkem, zadat do unit testů.
-
Když píšu TDD, tedy nejprve testy, rovnou si rozmyslím, co má implementace umět.
Celý váš komentář bych podepsal, ale tohle ještě zvlášť vypíchnu. TDD znamená, že se na tu funkci nejprve dívám z pohledu jejího uživatele. Takže se mi daleko spíš podaří API navrhnout tak, aby se dobře používalo, ne hlavně aby se mi dobře psala implementace. A když se API dobře používá, je zase menší pravděpodobnost, že ho někdo použije špatně.
-
Dependent typy z principu nemohou dokázat korektnost např. převodu stringu na číslo. Jak by se v typu fce convert: String -> Maybe Nat vyjádřilo, zda se očekává stringový vstup v desítkové nebo šestnáctkové soustavě? Podle mě je to principiálně nemožné, a stejně tak není možné ani vyjádřit korektnost implementace převodu. V Idris se asi dá vyjádřit, že funkce doběhne, a že nezpanikaří, ale to je málo.
Myslim, ze se pletes. Dostatecne silnym typem se da vyjadrit, ze ta konverzni funkce vrati Nothing pokud vstup nebude cislo v desitkove soustave. Potiz je v tom, ze pak tim vlastne cim dal vic implementujes znovu celou funkci...
Z meho pohledu je to tak, ze jak (dostatecne pokryvajici) testy, tak (dostatecne silne) typy jsou urcitou aproximaci toho, co ma program delat (a nekdy i za jakou cenu). V limitnim pripade obe tyto aproximace znamenaji napsat cely program znovu.
Napriklad vezmi si scitani dvou cisel. Typova aproximace typicky je "funkce vraci zase cislo". Ale muzeme to vzit dal a reprezentovat typem stale silnejsi invariant (treba vyznacny bit vysledku souvisi s vyznacnymi bity argumentu), az budeme typem reprezentovat, ze vysledkem operace je cislo.
Podobne, testova aproximace je typicky "funkce funguje na techto 100 prikladech cisel". Muzeme test rozsirovat a testovat stale vetsi mnozstvi pripadu, az dojdeme k situaci, kdy budeme mit (treba pro soucet 16-bit integeru) 2^32 testovacich pripadu a pokryji vsechny moznosti. (Pripadne muzeme delat neco jako QuickCheck a rozsirovat test o invarianty jako v pripade typu, az dojdeme k invariantu ktery popisuje presne, co testovana funkce dela.)
Takze podle me, neni (teoreticka) cesta ven - pokud chces neco dokonale otestovat nebo dokonale typove popsat, znamena to napsat znovu nezavisle celou implementaci.
Ale v praxi samozrejme obe aproximace jsou uzitecne a obe ma smysl pouzivat a znat jejich silne a slabe stranky. Otazka z titulku je asi podobne podivna jako ptat se, je lepsi pouzivat Taylorovu nebo Fourierovu radu?
-
Jj, něco takového si v zásadě myslím taky, na konkrétnějších případech jsem to ukazoval ve svém předchozím příspěvku, pěkně jsi to shrnul z trochu jiné stránky. Skoro se mi nechce věřit, že by se na root fóru dospělo k nějakému konsenzu :)
-
konsenzu
a ten je? a co na to zastánci dynamických jazyků?
-
konsenzu
a ten je? a co na to zastánci dynamických jazyků?
Zastanci dynamickych jazyku maji misto staticke typove kontroly kontrolu za behu, a misto "zavislostnich typu" maji asserty. Testy maji oba tabory. Takze pro ne plati to, co jsem napsal, takrka stejne.
(Jinak dynamickou typovou kontrolu a asserty lze samozrejme pouzit i ve staticky typovanych jazycich, a ma to sve vyhody.)
-
konsenzu
a ten je? a co na to zastánci dynamických jazyků?
Za mě je ten konsenzus JS-eho veta "obe aproximace jsou uzitecne a obe ma smysl pouzivat a znat jejich silne a slabe stranky.". I když "konsenzus za mě" je samozřejmě protimluv, spíš jsem to s tím konseznem plácnul..
Zastánci dynamických jazyků (tedy spíš jazyků bez statického typového systému) ... se musí obejít bez statického typového systému :) Typicky za to získávají větší flexibilitu, větší možnosti introspekce a modifikace programu za běhu, z komerčně používaných jazyků to podle mě nejdál dotáhl Smalltalk, kde je třeba možné za běhu debuggovat a upravovat debugger a nikomu na tom nepřijde nic zvláštního. Ale to už je zase jiné téma.
-
Skoro se mi nechce věřit, že by se na root fóru dospělo k nějakému konsenzu :)
Jinak to je duvod, proc sem zase tak moc nechodim.. Nejvic mi asi vadi to, kdyz nekdo chce s necim pomoci, nekdo jiny mu odpovi, a hned se najde nejaky magor, ktery (misto aby upresnil nebo napsal lepsi odpoved a pomohl tak puvodnimu tazateli) se zacne navazet do toho, kdo odpovedel, a ukazovat, jak je "lepsi" programator.
Bohuzel ale to je asi vseobecne dnes v Cesku takova hulvatska kultura.
-
Zkusím tady nadhodit myšlenkový experiment, který snad ukáže, co se mi celé na té myšlence náhrady testů typy nelíbí.
...
Díky za příspěvek. Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá, ale děkuji za pěkný rozbor. V mnohém máš určitě i pravdu.
Myslím, že alespoň v tom, co dělám já, by ty ukázky často byly k ničemu. Třeba u toho polygonu by ze stroje vypadla řada čísel - souřadnic bodů polygonu, ale dokud si to nenakreslíš, tak nevidíš co to vlastně testuje. A to už je jednodušší si ty zajímavé příklady nejprve nakreslit a potom je, u komplikovaných případů třeba i okomentované a s naskenovaným obrázkem, zadat do unit testů.
Hmm, může být.
-
Díky za příspěvek. Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Ono ty typy nejsou moc praktické obecně, větší program se závislostními typy se klidně může překládat hodiny.
-
Díky za příspěvek. Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Ono ty typy nejsou moc praktické obecně, větší program se závislostními typy se klidně může překládat hodiny.
Já si dokážu nějaké praktické využití i představit. Při běžné kompilaci by se používaly jen nějak zjednodušené typy bez závislostí. Plný typový systém by se použil až na buildserveru, kde to v pohodě může překládat hodiny a hodiny.
Ale tohle je vlastně jen trochu jiná statická analýza. A anotace pro statický analyzátor se přidávají do spousty jazyků. Není to omezené na fukcionální jazyky.
-
Díky za příspěvek. Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Ono ty typy nejsou moc praktické obecně, větší program se závislostními typy se klidně může překládat hodiny.
Já si dokážu nějaké praktické využití i představit. Při běžné kompilaci by se používaly jen nějak zjednodušené typy bez závislostí. Plný typový systém by se použil až na buildserveru, kde to v pohodě může překládat hodiny a hodiny.
Ano, já nechtěl říct, že to je nepoužitelné, jen že to má trochu specifické použití.
-
Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Když už jsme u té praktičnosti, řekněme, že mám funkci "double" pro násobení přirozených čísel dvěma a chci zaručit, že výsledek je sudý tím, že vracím (závislostní) hodnoty typu (n ** Even n). Jak ale zařídím, aby na lichých hodnotách typová kontrola selhala, resp. aby všechny relevantní funkce byly totální?
-
Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Když už jsme u té praktičnosti, řekněme, že mám funkci "double" pro násobení přirozených čísel dvěma a chci zaručit, že výsledek je sudý tím, že vracím (závislostní) hodnoty typu (n ** Even n). Jak ale zařídím, aby na lichých hodnotách typová kontrola selhala, resp. aby všechny relevantní funkce byly totální?
Možná ti nerozumím, ale tak nepřeloží se to, ne?
-
Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Když už jsme u té praktičnosti, řekněme, že mám funkci "double" pro násobení přirozených čísel dvěma a chci zaručit, že výsledek je sudý tím, že vracím (závislostní) hodnoty typu (n ** Even n). Jak ale zařídím, aby na lichých hodnotách typová kontrola selhala, resp. aby všechny relevantní funkce byly totální?
Možná ti nerozumím, ale tak nepřeloží se to, ne?
Takhle ne, ale když chci totální funkce, tak ty úpravy mě v podstatě donutí řešit to až za běhu.
-
Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Když už jsme u té praktičnosti, řekněme, že mám funkci "double" pro násobení přirozených čísel dvěma a chci zaručit, že výsledek je sudý tím, že vracím (závislostní) hodnoty typu (n ** Even n). Jak ale zařídím, aby na lichých hodnotách typová kontrola selhala, resp. aby všechny relevantní funkce byly totální?
Možná ti nerozumím, ale tak nepřeloží se to, ne?
Tak si odpovím sám, musí se vytvořit koprodukt implementující Uninhabited, aby ty funkce byly totální. Člověk se pořád učí...
-
Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Když už jsme u té praktičnosti, řekněme, že mám funkci "double" pro násobení přirozených čísel dvěma a chci zaručit, že výsledek je sudý tím, že vracím (závislostní) hodnoty typu (n ** Even n). Jak ale zařídím, aby na lichých hodnotách typová kontrola selhala, resp. aby všechny relevantní funkce byly totální?
Možná ti nerozumím, ale tak nepřeloží se to, ne?
Tak si odpovím sám, musí se vytvořit koprodukt implementující Uninhabited, aby ty funkce byly totální. Člověk se pořád učí...
ukažte kód :)
-
Já jsem to celé sice původně podával jako, že praktičnost mě až tak moc nezajímá
Když už jsme u té praktičnosti, řekněme, že mám funkci "double" pro násobení přirozených čísel dvěma a chci zaručit, že výsledek je sudý tím, že vracím (závislostní) hodnoty typu (n ** Even n). Jak ale zařídím, aby na lichých hodnotách typová kontrola selhala, resp. aby všechny relevantní funkce byly totální?
Možná ti nerozumím, ale tak nepřeloží se to, ne?
Tak si odpovím sám, musí se vytvořit koprodukt implementující Uninhabited, aby ty funkce byly totální. Člověk se pořád učí...
ukažte kód :)
data OnlyEven : Parity n -> Type where
OnlyEvenC : OnlyEven (Even n)
Uninhabited (OnlyEven (Odd n)) where
uninhabited _ impossible
test : (par:Parity n) -> {auto prf:OnlyEven par} -> String
test n = (show n) ++ " is provably even"
Ať žije type-driven programming :)
-
data OnlyEven : Parity n -> Type where
OnlyEvenC : OnlyEven (Even n)
Uninhabited (OnlyEven (Odd n)) where
uninhabited _ impossible
test : (par:Parity n) -> {auto prf:OnlyEven par} -> String
test n = (show n) ++ " is provably even"
Ať žije type-driven programming :)
díky, máte k tomu i tu nějakou tu double nebo něco podobného (co vyžaduje sudý Nat v argumentu nebo tak) ?
-
data OnlyEven : Parity n -> Type where
OnlyEvenC : OnlyEven (Even n)
Uninhabited (OnlyEven (Odd n)) where
uninhabited _ impossible
test : (par:Parity n) -> {auto prf:OnlyEven par} -> String
test n = (show n) ++ " is provably even"
Ať žije type-driven programming :)
díky, máte k tomu i tu nějakou tu double nebo něco podobného (co vyžaduje sudý Nat v argumentu nebo tak) ?
Ne, psal jsem to celé znova a "double" už jsem pak neřešil, to mi už přišlo triviální.
-
data OnlyEven : Parity n -> Type where
OnlyEvenC : OnlyEven (Even n)
Uninhabited (OnlyEven (Odd n)) where
uninhabited _ impossible
test : (par:Parity n) -> {auto prf:OnlyEven par} -> String
test n = (show n) ++ " is provably even"
Ať žije type-driven programming :)
díky, máte k tomu i tu nějakou tu double nebo něco podobného (co vyžaduje sudý Nat v argumentu nebo tak) ?
Pro argument to bude asi něco jako
double : (n:Nat) -> {default (parity n) par:Parity n} -> {auto prf:OnlyEven par} -> Nat
double n = n * 2
-
jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
Typem jde vyjádřít jakákoliv vyčíslitelná vlastnost. Testy (nejen jednotkové) mají tu nevýhodu, že mohou prokázat přítomnost bugů, ale nikdy jejich absenci. Typový systém dokáže prokázat korektnost (absenci bugů).
-
jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
Typem jde vyjádřít jakákoliv vyčíslitelná vlastnost. Testy (nejen jednotkové) mají tu nevýhodu, že mohou prokázat přítomnost bugů, ale nikdy jejich absenci. Typový systém dokáže prokázat korektnost (absenci bugů).
Hezká formulace. Díky!
-
jednotkové testy nejsou potřeba máte-li kvalitní typový systém.
Typem jde vyjádřít jakákoliv vyčíslitelná vlastnost. Testy (nejen jednotkové) mají tu nevýhodu, že mohou prokázat přítomnost bugů, ale nikdy jejich absenci. Typový systém dokáže prokázat korektnost (absenci bugů).
Hezká formulace. Díky!
Není zač :)
-
...Typový systém dokáže prokázat korektnost (absenci bugů).
Co když je v něm chyba (úplně stejně, jako může být ve výpočtu)?
-
Nechapu jednu vec. Mam funkci, ktera meni vstup na vystup:
5->3
3->5
Jak jde toto ošetřit typem bez použití unit testu?
-
Nechapu jednu vec. Mam funkci, ktera meni vstup na vystup:
5->3
3->5
Jak jde toto ošetřit typem bez použití unit testu?
Na to už se tu ptalo hodně lidí. Odpověď nečekejte.
-
...Typový systém dokáže prokázat korektnost (absenci bugů).
Co když je v něm chyba (úplně stejně, jako může být ve výpočtu)?
Tak to je pak smůla, stejně jako když je chyba v testech.
-
Nechapu jednu vec. Mam funkci, ktera meni vstup na vystup:
5->3
3->5
Jak jde toto ošetřit typem bez použití unit testu?
1. Ta funkce musí být totální. 2. V takto triviálních příkladech není moc co porovnávat, zápis těch typů bude v podstatě stejný jako zápis testů (akorát se vyhodnotí v době překladu). Zajímavějším příkladem by byla funkce s nekonečnem případů, např. f(n)=n+2, která nejde stoprocentně pokrýt testy.
-
Jak jde toto ošetřit typem bez použití unit testu?
Zajímavějším příkladem by byla funkce s nekonečnem případů, např. f(n)=n+2, která nejde stoprocentně pokrýt testy.
Řešení: plus2Proof : (n:Nat) -> plus2 n = n + 2
plus2Proof n = Refl
-
Ta funkce musí být totální.
Můžete mi prosím vysvětlit, co to znamená totální funkce?
-
Ta funkce musí být totální.
Můžete mi prosím vysvětlit, co to znamená totální funkce?
Totální funkce má hodnotu pro všechny možné vstupy. V haskellu je třeba funkce head, která vrací první prvek seznamu
head :: [a] -> a
Ta není totální. Pro prázdný seznam nemá co vrátit a může leda tak nějak umřít. Jak přesně se to stane tady není podstatné.
head :: [a] -> Maybe a
by totální byla, protože Maybe (v jiných jazycích třeba optional) může být buď prázdný, nebo obsahovat hodnotu.
-
Nechapu jednu vec. Mam funkci, ktera meni vstup na vystup:
5->3
3->5
Jak jde toto ošetřit typem bez použití unit testu?
Zkusím taky odpovědět: Např. závislostním typem duplikujícím výpočet dané funkce.
Jestli po celé té diskusi správně chápu závislostní typy, pak se jedná o (deklarativní) mechanismus omezení definičního oboru a oboru hodnot, případně vyjádření jejich závislosti. To lze určit v rozsahu od zcela volného až po zcela přesný, který pak ale obvykle (když nemá více řešení) kopíruje samotný výpočet. Takže buďto získám mechanismus omezeně kontrolující správnost výpočtu - otázkou je, zda to stačí, nebo zcela spolehlivě ověřím výpočet, ale samotná definice typu bude nutně stejně složitá jako samotný výpočet, takže můžu udělat tu samou chybu 2x. Závěr: Obecně neexistuje žádný magický mechanismus, který by dokázal (aťto v typu či jinde) rozhodnout, zda je můj výpočet správný.
To podstatné: Jednotkové testy se o hledání takového mechanismu ani nesnaží, protože to dle výše uvedené úvahy nejde. Využívají podmnožinu ZNÁMÝCH vstupů a jejich výstupů pro ověření výpočtu s tím, že je-li v pořádku, pro neznámé výstupy se výpočet považuje za pravděpodobně správný.
Takže z podstaty správnost výpočtu nezaručují ani jednotkové testy (to se vědělo), ani typový systém (to se tu někteří snažili dokázat). Tudíž jestli má smysl o něčem diskutovat, tak to, zda se vyplatí budovat typový systém nebo jednotkové testy.
-
Nechapu jednu vec. Mam funkci, ktera meni vstup na vystup:
5->3
3->5
Jak jde toto ošetřit typem bez použití unit testu?
Jestli po celé té diskusi správně chápu závislostní typy, pak se jedná o (deklarativní) mechanismus omezení definičního oboru a oboru hodnot, případně vyjádření jejich závislosti.
Spíš to druhé, když už. Typem jde vyjádřit vše, co je vyčíslitelné. Typické použití by bylo třeba u NP-úplných problémů. Na úrovni hodnot se hledá řešení, typový systém ověřuje řešení. Zásadní je, nakolik konkrétní překladač (resp. type checker) umí hledat důkazy automaticky, aby korektnost dokázal symbolicky bez pomoci.
-
Takže buďto získám mechanismus omezeně kontrolující správnost výpočtu - otázkou je, zda to stačí, nebo zcela spolehlivě ověřím výpočet, ale samotná definice typu bude nutně stejně složitá jako samotný výpočet, takže můžu udělat tu samou chybu 2x. Závěr: Obecně neexistuje žádný magický mechanismus, který by dokázal (aťto v typu či jinde) rozhodnout, zda je můj výpočet správný.
Děkuji, moc pěkné.
-
Právě vyšla kniha k tématu: https://mitpress.mit.edu/books/little-typer
-
tady někdo píše k tématu https://blog.root.cz/scientia/
-
tady někdo píše k tématu https://blog.root.cz/scientia/
Paráda!
-
tady někdo píše k tématu https://blog.root.cz/scientia/
Paráda!
Doufám, že se tam přesune relevantní diskuse a blitky trotlů se budou mazat.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Jo, musí se věřit překladači, ale překladače stejného jazyka budou fungovat stejně na stejném kódu.
-
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Dobře je to vidět například u PHP, kde se každá verze chová mírně odlišně. Navíc u stejné verze ještě závisí na konfiguraci a na verzích instalovaných frameworků. Nedovedu si už představit dělat v PHP bez testů.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Částečně máš pravdu. Ale když si to rozebereš:
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Částečně máš pravdu. Ale když si to rozebereš:
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
Ta urputnost je až zarážející. Unit testy ověřují, zda kus kódu dělá to, co se po něm chce podle specifikace. Typový systém je jedna z možných součástí nástrojů k modelování problémů pomocí počítačů. Dva mimoběžné světy. Celá tahle debata vznikla jako poznámka, že kniha by za určitých okolností (když bude o jídle) mohla nahrazovat jídlo. Odpověď je ne, nemohla. Kniha je kniha a jídlo je jídlo.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Částečně máš pravdu. Ale když si to rozebereš:
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
Ta urputnost je až zarážející. Unit testy ověřují, zda kus kódu dělá to, co se po něm chce podle specifikace. Typový systém je jedna z možných součástí nástrojů k modelování problémů pomocí počítačů. Dva mimoběžné světy. Celá tahle debata vznikla jako poznámka, že kniha by za určitých okolností (když bude o jídle) mohla nahrazovat jídlo. Odpověď je ne, nemohla. Kniha je kniha a jídlo je jídlo.
Typy (závislostní) a jednotkové testy se na úrovni sémantiky docela protínají, tedy alespoň v případě “extrinsics”. Některé jazyky umí ověřovat kód symbolicky.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
Kite, typy - a to je moje zvláštnost - si zásadně míchám sám ;D
-
Typy (závislostní) a jednotkové testy se na úrovni sémantiky docela protínají, tedy alespoň v případě “extrinsics”. Některé jazyky umí ověřovat kód symbolicky.
Symbolicky můžeš ověřit maximálně syntaxi, ale už ne sémantiku.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
Kite, typy - a to je moje zvláštnost - si zásadně míchám sám ;D
Takže sám sobě věříš? To neděláš dobře, Jaromíre. Jednou se ti to vymstí.
-
Typy (závislostní) a jednotkové testy se na úrovni sémantiky docela protínají, tedy alespoň v případě “extrinsics”. Některé jazyky umí ověřovat kód symbolicky.
Symbolicky můžeš ověřit maximálně syntaxi, ale už ne sémantiku.
To není pravda, viz závislostní typy v Agdě nebo Idrisu. Ale to se tu už řešilo včetně příkladů.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Ano, to je jeden z problémů, ktdrý skrz své malé zkušenosti nevnímáš v celé jeho šíři. Změna kompilátoru není výjimečná, je běžná. Stačí změna platformy (multiplatformní program) či architektury. Kompilátor se mění i s jeho verzí.
Tyto nemají zaručeně ani stejný výstup, ani stejnou kontrolu. Často pak upravuješ program ne proto, že je chybný, ale aby prošel tím ne o onním kompilátorem.
A to ani nemusíme zabředávat do typů, které mění své vlastnosti podle architektury.
Ve výsledku statické typy představují spíše překážku než pomoc, protože překáží, kód je kvůli nim zbytečně těžkopádný a nepřehledný, což zvyšuje počet jiných chyb, které kompilátor neodhalí, a tak se stejně program musí testovat tak jako tak.
Typový systém není cesta k bezchybnému kódu a dokonce ani cesta ke snížení počtu chyb v programu.
Testy jsou lepší cesta. Sice se dá argumentovat, že to je také zbytečný kód navíc podobně jako u statických typů (což je pravda, práci to neušetří), ale je to kód, který není součástí výsledného programu.
Cesta k ideálu bezchybného kódu vede podle mě jinudy. Je to cesta krátkého, přehledného a dobře srozumitelného kódu. Čím méně má program řádků, tím méně má spolehlivě statisticky chyb, čím má jazyk pokročilejší konstrukce, které program zkracují a zpřehledňují či dokonce zabraňují udělat některé chyby, tím lépe.
Přičemž přehlednost a krátkost se mohou navzájem tlouci, takže zkracovat ano, ale nikdy na úkor přehlednosti.
Líbí se mi třeba konstrukce with, nebo zákaz používání přiřazení v podmínkách a podobně. To jsou jednoduchá opatření, která snižují počet chyb spolehlivěji, než statické typy, protože oproti nim si nenesou s sebou negativa.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Ano, to je jeden z problémů, ktdrý skrz své malé zkušenosti nevnímáš v celé jeho šíři. Změna kompilátoru není výjimečná, je běžná. Stačí změna platformy (multiplatformní program) či architektury. Kompilátor se mění i s jeho verzí.
Tyto nemají zaručeně ani stejný výstup, ani stejnou kontrolu. Často pak upravuješ program ne proto, že je chybný, ale aby prošel tím ne o onním kompilátorem.
A to ani nemusíme zabředávat do typů, které mění své vlastnosti podle architektury.
Ve výsledku statické typy představují spíše překážku než pomoc, protože překáží, kód je kvůli nim zbytečně těžkopádný a nepřehledný, což zvyšuje počet jiných chyb, které kompilátor neodhalí, a tak se stejně program musí testovat tak jako tak.
Typový systém není cesta k bezchybnému kódu a dokonce ani cesta ke snížení počtu chyb v programu.
Testy jsou lepší cesta. Sice se dá argumentovat, že to je také zbytečný kód navíc podobně jako u statických typů (což je pravda, práci to neušetří), ale je to kód, který není součástí výsledného programu.
Cesta k ideálu bezchybného kódu vede podle mě jinudy. Je to cesta krátkého, přehledného a dobře srozumitelného kódu. Čím méně má program řádků, tím méně má spolehlivě statisticky chyb, čím má jazyk pokročilejší konstrukce, které program zkracují a zpřehledňují či dokonce zabraňují udělat některé chyby, tím lépe.
Přičemž přehlednost a krátkost se mohou navzájem tlouci, takže zkracovat ano, ale nikdy na úkor přehlednosti.
Líbí se mi třeba konstrukce with, nebo zákaz používání přiřazení v podmínkách a podobně. To jsou jednoduchá opatření, která snižují počet chyb spolehlivěji, než statické typy, protože oproti nim si nenesou s sebou negativa.
To je zase blábol ::)
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
slovy klasika "Beware of bugs in the above code; I have only proved it correct, not tried it."
jestli jste tak daleko, že nemůžete věřit kompilátoru, tak byste měl testy napsat v jiném jazyce, přeložit jiným kompilátorem a testovat přímo objektový kód :) a v takové situaci byste možná chtěl i typy
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Ano, to je jeden z problémů, ktdrý skrz své malé zkušenosti nevnímáš v celé jeho šíři. Změna kompilátoru není výjimečná, je běžná. Stačí změna platformy (multiplatformní program) či architektury. Kompilátor se mění i s jeho verzí.
Tyto nemají zaručeně ani stejný výstup, ani stejnou kontrolu. Často pak upravuješ program ne proto, že je chybný, ale aby prošel tím ne o onním kompilátorem.
Mas nejaky priklad? Zatim jsem na to nenarazil a chtel bych to videt, abych si mohl udelat obrazek jak vazny je to problem. Zajima me predevsim ta kontrola, jestli si narazil na pripad, ze by se s verzi kompilatoru zmenila.
A to ani nemusíme zabředávat do typů, které mění své vlastnosti podle architektury.
Ve výsledku statické typy představují spíše překážku než pomoc, protože překáží, kód je kvůli nim zbytečně těžkopádný a nepřehledný, což zvyšuje počet jiných chyb, které kompilátor neodhalí, a tak se stejně program musí testovat tak jako tak.
V cem pises? Tohle sedi na javu, ale nerekl bych, ze je to obecne platne pro vsechny staticky typovane jazyky.
-
jestli jste tak daleko, že nemůžete věřit kompilátoru, tak byste měl testy napsat v jiném jazyce, přeložit jiným kompilátorem a testovat přímo objektový kód :) a v takové situaci byste možná chtěl i typy
Pokud budu testovat objektový kód, tak k tomu typy potřebovat nebudu.
-
Líbí se mi třeba konstrukce with, nebo zákaz používání přiřazení v podmínkách a podobně. To jsou jednoduchá opatření, která snižují počet chyb spolehlivěji, než statické typy, protože oproti nim si nenesou s sebou negativa.
V podmínkách přece není zákaz přiřazení.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
slovy klasika "Beware of bugs in the above code; I have only proved it correct, not tried it."
jestli jste tak daleko, že nemůžete věřit kompilátoru, tak byste měl testy napsat v jiném jazyce, přeložit jiným kompilátorem a testovat přímo objektový kód :) a v takové situaci byste možná chtěl i typy
Nejsem tak paranoidni (zatim :-)).
Vidim to spis tak, ze testy si muzu snadno prohlidnout a ziskam prehled o tom jake kontroly se delaji.
A kdyz zmenim prekladac tak ty testy porad budou delat ty same kontroly.
Kdezto kdyz nekdo vyrobi alternativni prekladac haskellu, ktery bude zazracne rychly, protoze vynecha nektere kontroly...
To je jako kdyby mi nekdo smazal cast testu.
Abych se ubranil "zlovuli" autora alternativniho prekladace budu muset rozumet tomu jak prekladac funguje driv nez ho pouziju.
A nebo budu muset naveky zustat u jednoho prekladace - compiler lock-in
Vim, ze je to hodne hypoteticky priklad, ale to mi snad v kontextu tohoto vlakna odpustite.
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
slovy klasika "Beware of bugs in the above code; I have only proved it correct, not tried it."
jestli jste tak daleko, že nemůžete věřit kompilátoru, tak byste měl testy napsat v jiném jazyce, přeložit jiným kompilátorem a testovat přímo objektový kód :) a v takové situaci byste možná chtěl i typy
Nejsem tak paranoidni (zatim :-)).
Vidim to spis tak, ze testy si muzu snadno prohlidnout a ziskam prehled o tom jake kontroly se delaji.
A kdyz zmenim prekladac tak ty testy porad budou delat ty same kontroly.
Kdezto kdyz nekdo vyrobi alternativni prekladac haskellu, ktery bude zazracne rychly, protoze vynecha nektere kontroly...
To je jako kdyby mi nekdo smazal cast testu.
Abych se ubranil "zlovuli" autora alternativniho prekladace budu muset rozumet tomu jak prekladac funguje driv nez ho pouziju.
A nebo budu muset naveky zustat u jednoho prekladace - compiler lock-in
Vim, ze je to hodne hypoteticky priklad, ale to mi snad v kontextu tohoto vlakna odpustite.
Tak právě proto existují normy.
-
U typů musíš také věřit autorovi těch typů.
Kite, typy - a to je moje zvláštnost - si zásadně míchám sám ;D
Takže nepoužíváš žádné knihovny třetích stran a neustále vynalézáš kolo?
-
U typů musíš také věřit autorovi těch typů.
Kite, typy - a to je moje zvláštnost - si zásadně míchám sám ;D
Takže nepoužíváš žádné knihovny třetích stran a neustále vynalézáš kolo?
Jen občas.
-
Nejsem tak paranoidni (zatim :-)).
Vidim to spis tak, ze testy si muzu snadno prohlidnout a ziskam prehled o tom jake kontroly se delaji.
A kdyz zmenim prekladac tak ty testy porad budou delat ty same kontroly.
Kdezto kdyz nekdo vyrobi alternativni prekladac haskellu, ktery bude zazracne rychly, protoze vynecha nektere kontroly...
To je jako kdyby mi nekdo smazal cast testu.
Abych se ubranil "zlovuli" autora alternativniho prekladace budu muset rozumet tomu jak prekladac funguje driv nez ho pouziju.
A nebo budu muset naveky zustat u jednoho prekladace - compiler lock-in
Vim, ze je to hodne hypoteticky priklad, ale to mi snad v kontextu tohoto vlakna odpustite.
ny typy se můžete podívat stejně jako testy, myslím, že ten hypotetický zjednodušený překladač by spíš odmítl některé validní (podle nezjednodušeného) programy než pustil nevalidní
jinak mezi testama a typama bych volil fakt nerad, testy jsou z principu strašně omezené, ale ukážou mi příklad, že to aspoň někdy funguje
-
Ono naopak díky typům lze i velmi dobře testovat... takový QuickCheck je vynikající...
-
jinak mezi testama a typama bych volil fakt nerad, testy jsou z principu strašně omezené, ale ukážou mi příklad, že to aspoň někdy funguje
Testy mi ukážou i příklady, kdy to nefunguje a ani fungovat nemá.
-
Ono naopak díky typům lze i velmi dobře testovat... takový QuickCheck je vynikající...
mohli bychom se zeptat jestli je lepší jazyk dynamický nebo statický (nebo statický a "rich") vzhledem k testovatelnosti
-
jinak mezi testama a typama bych volil fakt nerad, testy jsou z principu strašně omezené, ale ukážou mi příklad, že to aspoň někdy funguje
Testy mi ukážou i příklady, kdy to nefunguje a ani fungovat nemá.
A testy zvládají i ověřování netransparentních funkcí, tj. můžou být stavové. Můžou být stavové typy?
-
jinak mezi testama a typama bych volil fakt nerad, testy jsou z principu strašně omezené, ale ukážou mi příklad, že to aspoň někdy funguje
Testy mi ukážou i příklady, kdy to nefunguje a ani fungovat nemá.
To i typy, viz konstrukce typu "X -> Void", které musí být uninhabited.
-
jinak mezi testama a typama bych volil fakt nerad, testy jsou z principu strašně omezené, ale ukážou mi příklad, že to aspoň někdy funguje
Testy mi ukážou i příklady, kdy to nefunguje a ani fungovat nemá.
Můžou být stavové typy?
Ano.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
Samozřejmě. Však to píšu, že?
-
Vim, ze je to hodne hypoteticky priklad, ale to mi snad v kontextu tohoto vlakna odpustite.
IMHO ano, hypoteticky se něco takového může stát. Podle mého ale benefity typů extrémně převažují. Upřednostňovat testy jen z tohoto důvodu mi nepřijde racionální.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
Samozřejmě. Však to píšu, že?
No jasně, jenže kvalita vývojáře těch typů je z principu stejná jako kvalita vývojáře testů.
-
Píšu sice jen v jazycích, které tak bohatý typový systém nemají, ale zajímalo by mě:
- jak typovým systémem ošetříte metodu která má na vstupu jakýkoliv int, na výstupu také vždy int závislý na vstupu a uvnitř nějakou matematimu.
Unit test je vcelku jasný - pošlu pár běžných a hraničních hodnot a ověřím známý správný výsledek, ale řešení nějakým závislostním typovým systémem by přece muselo zopakovat tu matematiku, která je uvnitř metody = ověřování samo sebou = když bude chyba v metodě, bude i v definici výstupního typu.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
Samozřejmě. Však to píšu, že?
No jasně, jenže kvalita vývojáře těch typů je z principu stejná jako kvalita vývojáře testů.
Můžeš rozvést ten princip, kdy platí, že:
kvalita průměrného vývojáře == kvalita lepších vývojářů + lepší matematici + miliardy iterací testování
?
-
Píšu sice jen v jazycích, které tak bohatý typový systém nemají, ale zajímalo by mě:
- jak typovým systémem ošetříte metodu která má na vstupu jakýkoliv int, na výstupu také vždy int závislý na vstupu a uvnitř nějakou matematimu.
Unit test je vcelku jasný - pošlu pár běžných a hraničních hodnot a ověřím známý správný výsledek, ale řešení nějakým závislostním typovým systémem by přece muselo zopakovat tu matematiku, která je uvnitř metody = ověřování samo sebou = když bude chyba v metodě, bude i v definici výstupního typu.
Myslím, že už to tu několikrát bylo. To, co vyčítáš typovému systému musíš vyčítat i unittestům. Dělají to totiž úplně stejně. To, že zaneseš chybu do typu je podobné, jako zanesení chyby do testů.
A říkám předem, že testy rozhodně nejsou čitelnější jak typy.
-
- U typů musíš věřit kompilátoru, který napsali lepší programátoři, stavějící na teorii lepších matematiků, ověřený miliardami iterací jednotlivých vývojářů-uživatelů, kteří "ověřili" že se ten typový systém chová "inteligentně".
- U unittestů musíš věřit autorovi těch testů.
Svobodně si vyber, komu svěříš svou důvěru :-)
U typů musíš také věřit autorovi těch typů.
Samozřejmě. Však to píšu, že?
No jasně, jenže kvalita vývojáře těch typů je z principu stejná jako kvalita vývojáře testů.
Můžeš rozvést ten princip, kdy platí, že:
kvalita průměrného vývojáře == kvalita lepších vývojářů + lepší matematici + miliardy iterací testování
?
Myslim, ze nema na mysli vyvojare typoveho systemu, ale vyvojare co ho pouzije. Tzn. toho sameho, ktery alternativne pouzije testy. Tzn. napriklad sebe. tebe, nebo me ;-)
-
Můžeš rozvést ten princip, kdy platí, že:
kvalita průměrného vývojáře == kvalita lepších vývojářů + lepší matematici + miliardy iterací testování
?
Ty si nepíšeš vlastní typy? Kolegové je také nepíší? A co vývojáři třetích stran, také nic?
-
Můžou být stavové typy?
Ano.
"stavové typy" možná ještě neznám, jak se to prosím jmenuje anglicky?
-
Myslim, ze nema na mysli vyvojare typoveho systemu, ale vyvojare co ho pouzije. Tzn. toho sameho, ktery alternativne pouzije testy. Tzn. napriklad sebe. tebe, nebo me ;-)
Ahá! To pak jo.
V takovém případě bych zdůraznil expresivitu a deklarativnost typů. Napsat nebo použít typ je IMHO výrazně snazší a bezpečnější než napsat testy. Snazší, když to umíš, samozřejmě. Ale to opět platí o obém.
-
Můžou být stavové typy?
Ano.
"stavové typy" možná ještě neznám, jak se to prosím jmenuje anglicky?
Closure over a type. Některé jazyky to mají, je to stejný princip jako uzávěr lambda výrazu, akorát na úrovni typů. Někdy se to hodí ve FP.
-
Ono naopak díky typům lze i velmi dobře testovat... takový QuickCheck je vynikající...
mohli bychom se zeptat jestli je lepší jazyk dynamický nebo statický (nebo statický a "rich") vzhledem k testovatelnosti
Zeptat se můžem asi na cokoliv, ale nejsem si jist, zdali existuje správná odpověď. Imho v prvé řadě záleží na kódu - tj. tom, co chci testovat.
Nicméně asi tomuto vláknu pořád nerozumím... ony typy vylučují unittesty a unittesty typy?
-
Ono naopak díky typům lze i velmi dobře testovat... takový QuickCheck je vynikající...
mohli bychom se zeptat jestli je lepší jazyk dynamický nebo statický (nebo statický a "rich") vzhledem k testovatelnosti
ony typy vylučují unittesty a unittesty typy?
Ne, vzájemně se doplňují, nicméně částečně se funkčně prolínají.
-
Nicméně asi tomuto vláknu pořád nerozumím... ony typy vylučují unittesty a unittesty typy?
No já nic takového nikdy netvrdil. Naopak jsem takovou myšlenku opakovaně dementoval. Marně.
-
Myslím, že už to tu několikrát bylo. To, co vyčítáš typovému systému musíš vyčítat i unittestům. Dělají to totiž úplně stejně. To, že zaneseš chybu do typu je podobné, jako zanesení chyby do testů.
A říkám předem, že testy rozhodně nejsou čitelnější jak typy.
Já v tom vidím rozdíl:
- u unit testu ověřuji výsledek, ke kterému jsem mohl dojít naprosto jiným způsobem, než výpočtem tou mojí metodou/funkcí a kódem v ní. Mohla být součástí zadání, mohu ji mít z nějakých Mat-Fyz-Tech tabulek, mohl jsem ji spočítat na kalkulačce a někde ověřit správnost - prostě tu dvojici čísel "konkrétní vstupní hodnota => konkrétní výstupní hodnota" mám ověřenou nezávisle na kódu v mé metodě/funkci a zásah do kódu na té definici nic nemění.
Unit test bude mít jen statickou hromádku vstupních a výstupních hodnot, které ověří - souhlasí/nesouhlasí - nic, v čem by mohla vzniknout nečitelnost, tam nevidím.
- u typového systému duplikuju obsah své metody/funkce jako ověření výsledku, ten nezávislý pohled tam není. Když něco upravím v v kódu, budu asi muset stejnou úpravu udělat v definici výstupního typu = možnou chybu zduplikuju. A co se týká čitelnosti - definice výstupního typu je přesně stejně složitá jako celý můj kód v metodě/funkci.
Nezavrhuju typový systém obecně, ale pro výše uvedený příklad mi prostě na rozdíl od unit testu nedává smysl.
-
Já v tom vidím rozdíl:
...
- u typového systému duplikuju obsah své metody/funkce jako ověření výsledku, ten nezávislý pohled tam není.
Rozumím. A měl by si pravdu. Ale myslím si, že ten tvůj předpoklad není nutný. Dovedu si představit, kdy typem určím druh výsledku, ale nechám prostor pro různé implementace. Dokonce jsem tu uváděl i jednoduchý příklad.
-
Myslim, ze nema na mysli vyvojare typoveho systemu, ale vyvojare co ho pouzije. Tzn. toho sameho, ktery alternativne pouzije testy. Tzn. napriklad sebe. tebe, nebo me ;-)
Ahá! To pak jo.
V takovém případě bych zdůraznil expresivitu a deklarativnost typů. Napsat nebo použít typ je IMHO výrazně snazší a bezpečnější než napsat testy. Snazší, když to umíš, samozřejmě. Ale to opět platí o obém.
Obávám se, že srovnáváš typy s jednotkovými testy, ale měly by se srovnávat funkcionální typy s objektovými třídami. Z toho vyplývá, že jednotkové testy nesoupeří s typy, ale jsou něčím navíc, tedy se s typy (resp. s třídami) vzájemně doplňují.
-
Rozumím. A měl by si pravdu. Ale myslím si, že ten tvůj předpoklad není nutný. Dovedu si představit, kdy typem určím druh výsledku, ale nechám prostor pro různé implementace. Dokonce jsem tu uváděl i jednoduchý příklad.
Druh výsledku (např pro funkci počítající x2 to dejme tomu bude int od 0 do nekonečna) mi moc nepomůže, když potřebuju ověřit, jestli mi to ve skutečnosti nevrací x2/2.
-
Myslim, ze nema na mysli vyvojare typoveho systemu, ale vyvojare co ho pouzije. Tzn. toho sameho, ktery alternativne pouzije testy. Tzn. napriklad sebe. tebe, nebo me ;-)
Ahá! To pak jo.
V takovém případě bych zdůraznil expresivitu a deklarativnost typů. Napsat nebo použít typ je IMHO výrazně snazší a bezpečnější než napsat testy. Snazší, když to umíš, samozřejmě. Ale to opět platí o obém.
Obávám se, že srovnáváš typy s jednotkovými testy, ale měly by se srovnávat funkcionální typy s objektovými třídami. Z toho vyplývá, že jednotkové testy nesoupeří s typy, ale jsou něčím navíc, tedy se s typy (resp. s třídami) vzájemně doplňují.
"Funkcionální" typy a třídy à la OO jsou dva různé koncepty. Jinak to o tom vzájemném doplňování jsem ve stejném znění psal výše, prosím neopičit se :P
-
Rozumím. A měl by si pravdu. Ale myslím si, že ten tvůj předpoklad není nutný. Dovedu si představit, kdy typem určím druh výsledku, ale nechám prostor pro různé implementace. Dokonce jsem tu uváděl i jednoduchý příklad.
Druh výsledku (např pro funkci počítající x2 to dejme tomu bude int od 0 do nekonečna) mi moc nepomůže, když potřebuju ověřit, jestli mi to ve skutečnosti nevrací x2/2.
Toto je příklad intrinsic proof v silných typových systémech. V takovém případě funkce nevrací jen int, ale taky "důkaz" (proof), typicky nějaký zobecněný součtový typ, který zajišťuje korektnost. Jednoduché příklady má ve své knize Sitnikovski, doporučuji.
-
Obávám se, že srovnáváš typy s jednotkovými testy, ale měly by se srovnávat funkcionální typy s objektovými třídami. Z toho vyplývá, že jednotkové testy nesoupeří s typy, ale jsou něčím navíc, tedy se s typy (resp. s třídami) vzájemně doplňují.
Nemohu souhlasit. Typy ve funkcionálním jazyce se chovaj stejně jako typy v objektovém jazyce. Tedy takové porovnání je neužitečné. Já chci srovnat typy s jednotkovými testy. V tom vidím potenciál. Tedy nevyplývá z toho to co tvrdíš, že z toho vyplývá.
-
Rozumím. A měl by si pravdu. Ale myslím si, že ten tvůj předpoklad není nutný. Dovedu si představit, kdy typem určím druh výsledku, ale nechám prostor pro různé implementace. Dokonce jsem tu uváděl i jednoduchý příklad.
Druh výsledku (např pro funkci počítající x2 to dejme tomu bude int od 0 do nekonečna) mi moc nepomůže, když potřebuju ověřit, jestli mi to ve skutečnosti nevrací x2/2.
No ano, v tom nejsme ve sporu. Já uvažuji, proč by typový systém měl být tak omezený, aby vracel jen 0 .. nekonečno? Jde vyjádřit i víc.
-
"Funkcionální" typy a třídy à la OO jsou dva různé koncepty. Jinak to o tom vzájemném doplňování jsem ve stejném znění psal výše, prosím neopičit se :P
Jsou to různé koncepty, ale dá se srovnávat analogie. Co je pro OOP třída, to je pro FP typ. V OOP se píší testy, ve FP se programy dokazují.
-
Obávám se, že srovnáváš typy s jednotkovými testy, ale měly by se srovnávat funkcionální typy s objektovými třídami. Z toho vyplývá, že jednotkové testy nesoupeří s typy, ale jsou něčím navíc, tedy se s typy (resp. s třídami) vzájemně doplňují.
Nemohu souhlasit. Typy ve funkcionálním jazyce se chovaj stejně jako typy v objektovém jazyce. Tedy takové porovnání je neužitečné. Já chci srovnat typy s jednotkovými testy. V tom vidím potenciál. Tedy nevyplývá z toho to co tvrdíš, že z toho vyplývá.
Typy nejsou v OOP důležité, jsou jen atributem objektu. FP je na typech postaveno.
-
V OOP se píší testy, ve FP se programy dokazují.
To určitě nelze takto generalizovat.
Typy nejsou v OOP důležité, jsou jen atributem objektu. FP je na typech postaveno.
To zcela jistě není pravda. Jak je takové Clojure postaveno na typech? Java bez interfaců by byla méně než poloviční.
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
-
Obávám se, že srovnáváš typy s jednotkovými testy, ale měly by se srovnávat funkcionální typy s objektovými třídami. Z toho vyplývá, že jednotkové testy nesoupeří s typy, ale jsou něčím navíc, tedy se s typy (resp. s třídami) vzájemně doplňují.
Nemohu souhlasit. Typy ve funkcionálním jazyce se chovaj stejně jako typy v objektovém jazyce. Tedy takové porovnání je neužitečné. Já chci srovnat typy s jednotkovými testy. V tom vidím potenciál. Tedy nevyplývá z toho to co tvrdíš, že z toho vyplývá.
Typy nejsou v OOP důležité, jsou jen atributem objektu.
Ha, tak tohle tesat do kamene.
-
Obávám se, že srovnáváš typy s jednotkovými testy, ale měly by se srovnávat funkcionální typy s objektovými třídami. Z toho vyplývá, že jednotkové testy nesoupeří s typy, ale jsou něčím navíc, tedy se s typy (resp. s třídami) vzájemně doplňují.
Nemohu souhlasit. Typy ve funkcionálním jazyce se chovaj stejně jako typy v objektovém jazyce. Tedy takové porovnání je neužitečné. Já chci srovnat typy s jednotkovými testy. V tom vidím potenciál. Tedy nevyplývá z toho to co tvrdíš, že z toho vyplývá.
FP je na typech postaveno.
To tak obecně neplatí, původní (beztypový) λ-počet je taky čisté FP a po typech ani vidu. To jen Haskell a spol. s typy stojí a padají.
-
V OOP se píší testy, ve FP se programy dokazují.
To určitě nelze takto generalizovat.
Typy nejsou v OOP důležité, jsou jen atributem objektu. FP je na typech postaveno.
To zcela jistě není pravda. Jak je takové Clojure postaveno na typech? Java bez interfaců by byla méně než poloviční.
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Java zrovna není příliš dobrý příklad objektového jazyka. Je to spíš takový objektový paskvil.
-
V OOP se píší testy, ve FP se programy dokazují.
To určitě nelze takto generalizovat.
Typy nejsou v OOP důležité, jsou jen atributem objektu. FP je na typech postaveno.
To zcela jistě není pravda. Jak je takové Clojure postaveno na typech? Java bez interfaců by byla méně než poloviční.
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Takže jsme se dopracovali k tomu, že typy nejsou důležité ani v OOP, ani ve FP. Typy jsou užitečné, ale nejsou nezbytné.
Clojure není čistě funkcionálním jazykem, dá se v něm psát i strukturovaně nebo objektově.
Kdysi jsem si napsal javovskou aplikaci (plugin do Vimu) ve které jediným rozhraním byl Object. Žádné přetypování, elegance sama. Smalltalk je důkazem, že se bez typů obejdeme, ale bez testů nikoli.
-
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Důkaz sporem: Napiš jedinou netriviální aplikaci, kterou po úspěšné kompilaci předáš zákazníkovi jako hotovou. Nesmíš ji ani jednou spustit, ani žádnou její komponentu. Pokud to svedeš, tak ti pogratuluji, že ses vyhnul testům a že sis vystačil s typy.
-
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Důkaz sporem: Napiš jedinou netriviální aplikaci, kterou po úspěšné kompilaci předáš zákazníkovi jako hotovou. Nesmíš ji ani jednou spustit, ani žádnou její komponentu. Pokud to svedeš, tak ti pogratuluji, že ses vyhnul testům a že sis vystačil s typy.
Nemám zájem. Jak píšu, mě zajímá schopnost typů na úkor testů.
-
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Důkaz sporem: Napiš jedinou netriviální aplikaci, kterou po úspěšné kompilaci předáš zákazníkovi jako hotovou. Nesmíš ji ani jednou spustit, ani žádnou její komponentu. Pokud to svedeš, tak ti pogratuluji, že ses vyhnul testům a že sis vystačil s typy.
Nemám zájem. Jak píšu, mě zajímá schopnost typů na úkor testů.
V tom případě je jasné, že testy jsou nenahraditelné. Typy z tohoto krajíce mohou něco ukousnout, ale větší díl zůstává na těch testech.
-
V tom případě je jasné, že testy jsou nenahraditelné. Typy z tohoto krajíce mohou něco ukousnout, ale větší díl zůstává na těch testech.
V Haskellu se jednotkové testy používají ve velmi malé míře. Typový systém Haskellu je sice nadprůměrný, ale stále nevyčerpal teoretické možnosti. Toliko k tvému rozmáchlému tvrzení.
Nevím, jestli to řekl Evan Czaplicki nebo kdo, že typové systémy běžných jazyků jsou odfláklé, ne, že by to nešlo udělat líp.
-
V tom případě je jasné, že testy jsou nenahraditelné. Typy z tohoto krajíce mohou něco ukousnout, ale větší díl zůstává na těch testech.
V Haskellu se jednotkové testy používají ve velmi malé míře. Typový systém Haskellu je sice nadprůměrný, ale stále nevyčerpal teoretické možnosti. Toliko k tvému rozmáchlému tvrzení.
Tak mi to rozmáchlé tvrzení vyvrať nějakým důkazem. I v Haskellu je každá jednotka důkladně testována. Možná vývojáři nepoužívají automatizované testy, ale určitě si každou jednotku několikrát spustí, aby si ověřili, že dělá, co má dělat.
-
V tom případě je jasné, že testy jsou nenahraditelné. Typy z tohoto krajíce mohou něco ukousnout, ale větší díl zůstává na těch testech.
V Haskellu se jednotkové testy používají ve velmi malé míře. Typový systém Haskellu je sice nadprůměrný, ale stále nevyčerpal teoretické možnosti. Toliko k tvému rozmáchlému tvrzení.
Tak mi to rozmáchlé tvrzení vyvrať nějakým důkazem.
To jsem právě udělal poznámkou o Haskellu.
I v Haskellu je každá jednotka důkladně testována. Možná vývojáři nepoužívají automatizované testy, ale určitě si každou jednotku několikrát spustí, aby si ověřili, že dělá, co má dělat.
Samozřejmě. Haskellisti moc nepíšou jednotkové testy, protože si "vystačí" s typy. Ale samozřejmě si vyzkouší, co stvořili a zda to dělá co má. V čem je problém? V čem vidíš "důkaz" svého tvrzení?
-
V Haskellu se jednotkové testy používají ve velmi malé míře. Typový systém Haskellu je sice nadprůměrný, ale stále nevyčerpal teoretické možnosti. Toliko k tvému rozmáchlému tvrzení.
Tak mi to rozmáchlé tvrzení vyvrať nějakým důkazem.
To jsem právě udělal poznámkou o Haskellu.
Poznámka není důkaz. Navíc tu svou poznámku v následujícím odstavci vyvracíš.
I v Haskellu je každá jednotka důkladně testována. Možná vývojáři nepoužívají automatizované testy, ale určitě si každou jednotku několikrát spustí, aby si ověřili, že dělá, co má dělat.
Samozřejmě. Haskellisti moc nepíšou jednotkové testy, protože si "vystačí" s typy. Ale samozřejmě si vyzkouší, co stvořili a zda to dělá co má. V čem je problém? V čem vidíš "důkaz" svého tvrzení?
Důkaz vidím tom, že každé takové vyzkoušení je testem. Je úplně jedno, zda je testem automatizovaným nebo manuálním. Bylo by lepší, kdyby místo holedbání, že testy nepotřebují, psali normální automatizované testy - třeba jen v omezené míře.
Jak bez testu ověříš, zda máš ve vyvíjeném modulu všechny požadované funkce a s potřebnými parametry?
-
Důkaz vidím tom, že každé takové vyzkoušení je testem. Je úplně jedno, zda je testem automatizovaným nebo manuálním.
Ne, to není jedno. Toto vlákno je o nahrazení unit testů ve prospěch typování. O akceptačních testech, nebo ručním otestování není řeč. Tudíž, pokud chceš odvádět diskusi tímto směrem, nebudu ti sekundovat.
-
Důkaz vidím tom, že každé takové vyzkoušení je testem. Je úplně jedno, zda je testem automatizovaným nebo manuálním.
Ne, to není jedno. Toto vlákno je o nahrazení unit testů ve prospěch typování. O akceptačních testech, nebo ručním otestování není řeč. Tudíž, pokud chceš odvádět diskusi tímto směrem, nebudu ti sekundovat.
Tohle jsi vyhodil z citace:
Jak bez testu ověříš, zda máš ve vyvíjeném modulu všechny požadované funkce a s potřebnými parametry?
Tohle dělají právě jednotkové testy.
-
V OOP se píší testy, ve FP se programy dokazují.
To určitě nelze takto generalizovat.
Typy nejsou v OOP důležité, jsou jen atributem objektu. FP je na typech postaveno.
To zcela jistě není pravda. Jak je takové Clojure postaveno na typech? Java bez interfaců by byla méně než poloviční.
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Myslím, že typový systém a paradigma jazyku jsou oddělenými záležitostmi.
-
V OOP se píší testy, ve FP se programy dokazují.
To určitě nelze takto generalizovat.
Typy nejsou v OOP důležité, jsou jen atributem objektu. FP je na typech postaveno.
To zcela jistě není pravda. Jak je takové Clojure postaveno na typech? Java bez interfaců by byla méně než poloviční.
Každopádně mě ani nijak zvlášť nezajímá rozdíl mezi FP a OOP; ten je celkem jasný. Mě zajímá schopnost typů na úkor testů.
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Myslím, že typový systém a paradigma jazyku jsou oddělenými záležitostmi.
Co je netypový interface?
-
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Co je netypový interface?
Zřejmě má na mysli duck typing.
-
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Co je netypový interface?
Zřejmě má na mysli duck typing.
Aha. Tak to pak jo. To byla ostatně, pokud se správně pamatuju, úplně první verze rozhraní.
-
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Co je netypový interface?
Zřejmě má na mysli duck typing.
Aha. Tak to pak jo. To byla ostatně, pokud se správně pamatuju, úplně první verze rozhraní.
A kde se to používalo? U Javy?
-
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Co je netypový interface?
Zřejmě má na mysli duck typing.
Aha. Tak to pak jo. To byla ostatně, pokud se správně pamatuju, úplně první verze rozhraní.
A kde se to používalo? U Javy?
V Javě se to dá používat také, pokud do interface dáš typ Object. U jednodušších úloh je to docela praktické - do doby, než poprvé použiješ operátor instanceof.
Duck typing běžně používám při prototypování v PHP. Podobně to funguje i v Javascriptu a Pythonu.
-
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Co je netypový interface?
Zřejmě má na mysli duck typing.
Aha. Tak to pak jo. To byla ostatně, pokud se správně pamatuju, úplně první verze rozhraní.
A kde se to používalo? U Javy?
V Javě se to dá používat také, pokud do interface dáš typ Object. U jednodušších úloh je to docela praktické - do doby, než poprvé použiješ operátor instanceof.
Duck typing běžně používám při prototypování v PHP. Podobně to funguje i v Javascriptu a Pythonu.
Ale na to jsem se přece neptal!
-
Nikde není napsáno, že interface musí být typový. Nějaká Java není argumentem.
Co je netypový interface?
Zřejmě má na mysli duck typing.
Aha. Tak to pak jo. To byla ostatně, pokud se správně pamatuju, úplně první verze rozhraní.
A kde se to používalo? U Javy?
Ani náhodou :) Ve Smalltalku. Java ale své "interface" okopčila z Objective-C, ta historie je celkem zajímavá, na Javě dělali (hlavně standardní knihovnu) ObjC vývojáři po tom, co Sun koupil Lighthouse Design, takže tam přenesli své znalosti, zvyky a postupy.
-
A kde se to používalo? U Javy?
Ani náhodou :) Ve Smalltalku. Java ale své "interface" okopčila z Objective-C, ta historie je celkem zajímavá, na Javě dělali (hlavně standardní knihovnu) ObjC vývojáři po tom, co Sun koupil Lighthouse Design, takže tam přenesli své znalosti, zvyky a postupy.
Jo aha. OK, ale to se pak nebavíme o typech, ne? Smalltalk typy nepoužívá, takže to už tolik nepřekvapí. V javě jsou interface typy, a jako takové se tak používají - jako nominální typ. Jakou ideu má ObjC to už netuším.
Nechceš to "takže tam přenesli své znalosti, zvyky a postupy." trochu rozvést, ať je tu alespoň něco zajímavého?
-
A kde se to používalo? U Javy?
Ani náhodou :) Ve Smalltalku. Java ale své "interface" okopčila z Objective-C, ta historie je celkem zajímavá, na Javě dělali (hlavně standardní knihovnu) ObjC vývojáři po tom, co Sun koupil Lighthouse Design, takže tam přenesli své znalosti, zvyky a postupy.
Jo aha. OK, ale to se pak nebavíme o typech, ne? Smalltalk typy nepoužívá, takže to už tolik nepřekvapí. V javě jsou interface typy, a jako takové se tak používají - jako nominální typ. Jakou ideu má ObjC to už netuším.
Nechceš to "takže tam přenesli své znalosti, zvyky a postupy." trochu rozvést, ať je tu alespoň něco zajímavého?
Smalltalk ma protokoly ne? Neni to totez co interface respektive typ?
A btw. nejsem si jisty, ze mel SB tohle na mysli.
@SB: Je to tak? Co je to ten netypovy interface?
-
Smalltalk ma protokoly ne? Neni to totez co interface respektive typ?
Tak tady je to těžký - máš nominální typ, to jsou ty interface z Javy. Pak máš strukturální typy, což je hodně volně podobné duck typingu.
V případě tohoto vlákna se cca bavíme o statickém typování. Takže nakolik Smalltalk znám, tak ten padá.
Takže si asi definovat, co je typ o kterém se to bavíme :-)
-
A kde se to používalo? U Javy?
Ani náhodou :) Ve Smalltalku. Java ale své "interface" okopčila z Objective-C, ta historie je celkem zajímavá, na Javě dělali (hlavně standardní knihovnu) ObjC vývojáři po tom, co Sun koupil Lighthouse Design, takže tam přenesli své znalosti, zvyky a postupy.
Jo aha. OK, ale to se pak nebavíme o typech, ne? Smalltalk typy nepoužívá, takže to už tolik nepřekvapí.
No jasně, ale otázka zněla na "netypový interface".
-
A kde se to používalo? U Javy?
Ani náhodou :) Ve Smalltalku. Java ale své "interface" okopčila z Objective-C, ta historie je celkem zajímavá, na Javě dělali (hlavně standardní knihovnu) ObjC vývojáři po tom, co Sun koupil Lighthouse Design, takže tam přenesli své znalosti, zvyky a postupy.
Nechceš to "takže tam přenesli své znalosti, zvyky a postupy." trochu rozvést, ať je tu alespoň něco zajímavého?
Tady je k tomu info přímo z první ruky: https://cs.gmu.edu/~sean/stuff/java-objc.html
-
No jasně, ale otázka zněla na "netypový interface".
Tak jasně. Jsem původně nabyl (mylného) dojmu, že se u Javy začínalo s interfacemi bez typů, nebo tak něco zajímavého :-)
-
Potrebuju jeste na chvilku vyhrabat tohle vlakno, protoze si myslim, ze jsem narazil na oblast kde unit testy predci typy.
A chtel bych si nechat poradit jestli je to tak nebo ne...
Problem typu je zavislost na kompilatoru. Ve smyslu ja musim 'verit' kompilatoru, ze provede spravne statickou typovou kontrolu. U unit testu kompilatoru verit nemusim, protoze overeni spravnosti je na nem nezavisle.
Ve vetsine pripadu to asi nebude velky problem, ale co kdyz se budu u nejakeho projektu rozhodovat, ze vymenim kompilator za jiny, protoze ma nejake vyhody, kterych chci vyuzit(napada me jen rychlost, ale muze jich asi byt vic).
Co myslite?
Ano, to je jeden z problémů, ktdrý skrz své malé zkušenosti nevnímáš v celé jeho šíři. Změna kompilátoru není výjimečná, je běžná. Stačí změna platformy (multiplatformní program) či architektury. Kompilátor se mění i s jeho verzí.
Tyto nemají zaručeně ani stejný výstup, ani stejnou kontrolu. Často pak upravuješ program ne proto, že je chybný, ale aby prošel tím ne o onním kompilátorem.
A to ani nemusíme zabředávat do typů, které mění své vlastnosti podle architektury.
Ve výsledku statické typy představují spíše překážku než pomoc, protože překáží, kód je kvůli nim zbytečně těžkopádný a nepřehledný, což zvyšuje počet jiných chyb, které kompilátor neodhalí, a tak se stejně program musí testovat tak jako tak.
Typový systém není cesta k bezchybnému kódu a dokonce ani cesta ke snížení počtu chyb v programu.
Testy jsou lepší cesta. Sice se dá argumentovat, že to je také zbytečný kód navíc podobně jako u statických typů (což je pravda, práci to neušetří), ale je to kód, který není součástí výsledného programu.
Cesta k ideálu bezchybného kódu vede podle mě jinudy. Je to cesta krátkého, přehledného a dobře srozumitelného kódu. Čím méně má program řádků, tím méně má spolehlivě statisticky chyb, čím má jazyk pokročilejší konstrukce, které program zkracují a zpřehledňují či dokonce zabraňují udělat některé chyby, tím lépe.
Přičemž přehlednost a krátkost se mohou navzájem tlouci, takže zkracovat ano, ale nikdy na úkor přehlednosti.
Líbí se mi třeba konstrukce with, nebo zákaz používání přiřazení v podmínkách a podobně. To jsou jednoduchá opatření, která snižují počet chyb spolehlivěji, než statické typy, protože oproti nim si nenesou s sebou negativa.
To je zase blábol ::)
Svou vlastní reakci jsi vystihnul naprosto přesně. Můj příspěvek je založen na 30+ leté praxi, která se poněkud liší od školních teorií, s kterými mladá ucha chodí do týmu ze školních projektů. Typy nejsou to, na čem kvalita kódu stojí, jejich přínos je z hlediska praktické kvality kódu pofiderní, spíše negativní. Jejich benefit spočívá ve výkonu, což je pro některé úlohy významný a pro jiné bezvýznamný faktor. Bez testování se naopak žádná aplikace neobejde a čím více je testovaní prováděno jako standardizovaná rutina, tím lépe. Kdo tohle neví nebo nechápe, ten si žádnou praxí neprošel a je jen něčím, co nazývám salonním programátorem, který nikdy nestrávil pár nocí u zákazníka, kterému záhadně kolabuje regulační systém a podobně. Tohle vás naučí rozlišovat podstatné od nepodstatního a jak si vytvořit dobrou QA.
-
A něco poučného na téma složitosti: http://www.knesl.com/budoucnost-programovacich-jazyku
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí. Jeden blud za druhým, ach jo, to už na těch VŠ nic kloudného neučí?
-
A něco poučného na téma složitosti: http://www.knesl.com/budoucnost-programovacich-jazyku
Ten článek není úplně špatný. Akorát na konci se autor dopustil poměrně zásadní a docela časté chyby. Formuloval závěr na základě jim specifikovaných předpokladů, ale jaksi opomněl, že mu tam další předpoklady chybí.
Vynechal totiž nejdůležitější faktor, ovlivňující prodloužení doby vývoje: programátora. S bandou opic nejnovější funkcionalitu prostě nenaprogramujete, i když budete mít ty nejlepší nástroje. A protože poptávka po programátorech neustále stoupá, tak za současné situace logicky jejich kvalita klesá. A tady narážíme na limitující prvek. Klesající kvalita programátorů (nebo třeba nemožnost získat dostatečně kvalitní programátory) způsobí prodloužení doby implementace v případě použití složitého a vysoce sofistikovaného jazyka. Tak, jak se někdo v matematice zastaví u trigonometrických funkcí, někdo u logaritmů a další u integrálů a derivací, tak se zastaví u různé složitosti konstrukcí programovacích jazyků. A protože se jedná o pyramidu (skoro všichni zvládnou goniometrické funkce, logaritmy už menší skupina a integrály a derivace jen "hrstka"), můžete mít sice dokonalý jazyk, ale jeho zvládnutí vás může stát více času (pokud to vůbec dáte), než to funkčně naprogramovat v něčem primitivnějším.
A to je taky problém celého tohoto vlákna. Zatímco typový systém ekvivalentní unit testům možná dokáže navrhnout autor (a možná ještě další jeden nebo dva), napsat nějaký unit test dokáží víceméně všichni. A po nějakém tréninku velká většina z množiny všichni bude schopna psát kvalitní unit testy. Kolik dalších lidí zvládne Haskell na úrovni, kdy nahradí unit testy správnou volbou typů si netroufnu ani odhadovat.
-
můžete mít sice dokonalý jazyk, ale jeho zvládnutí vás může stát více času (pokud to vůbec dáte), než to funkčně naprogramovat v něčem primitivnějším.
A jaké jazyky jsou ty složité k pochopení? Kromě Haskellu teda.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí. Jeden blud za druhým, ach jo, to už na těch VŠ nic kloudného neučí?
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A kterou že to VŠ jste studoval vy?
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
-
Smalltalk ma protokoly ne? Neni to totez co interface respektive typ?
A btw. nejsem si jisty, ze mel SB tohle na mysli.
@SB: Je to tak? Co je to ten netypovy interface?
Protokolem ve Smalltalku je seznam jmen zpráv, kterým objekt rozumí. Není definován odděleně jako interface, ale v rámci třídy (třídně-instanční systém). Pokud si pamatuju, Smalltalk žádný mechanismus definice samostatného rozhraní a ověřování objektů na shodu s ním nemá.
Je-li interface (třeba v OOP) jakousi dohodou mezi systémem (objektem) a jeho uživatelem o poskytované funkcionalitě, pak asi bude logicky v netypových jazycích taky netypový. Není důvodu, proč by to nešlo, ale nikde jsem to neviděl (což na podstatě nic nemění).
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí. Jeden blud za druhým, ach jo, to už na těch VŠ nic kloudného neučí?
Vytrženo z kontextu. Tvá první věta je nepodložená. Druhá je zavádějící a zcela zbytečná, neboť neobsahuje argumenty.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
Takže nevíte...
Aby některé rádobyobjektové jazyky zvýšily rychlost zpracování, nahradily zasílání zpráv voláním funkcí. Protože by tím ale přišly o polymorfismus, oprasily to tak, že zavedly tzv. "podtypový polymorfismus", kdy volaná funkce je dohledávána právě v VMT z omezené množiny podtypů daných typovým stromem. Měl to tak Pascal, Java bude mít pravděpodobně něco podobného.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
Vytrženo z kontextu.
Kontext tam žádný nebyl, jen snůška nesmyslů. Ale jestli si taky myslíš, že typy mají přímý vliv na výkon, dej příklad. Obratem to ho vyvrátím ;)
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
Statické typy umožňují určit už v době kompilace, která metoda bude použita. Virtuální metoda se musí vybírat ze seznamu před každým voláním.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
Takže nevíte...
Aby některé rádobyobjektové jazyky zvýšily rychlost zpracování, nahradily zasílání zpráv voláním funkcí. Protože by tím ale přišly o polymorfismus, oprasily to tak, že zavedly tzv. "podtypový polymorfismus", kdy volaná funkce je dohledávána právě v VMT z omezené množiny podtypů daných typovým stromem. Měl to tak Pascal, Java bude mít pravděpodobně něco podobného.
Virtuální metody fungují úplně stejně jako dispatch - objekty mají odkaz na tabulku metod svého typu, Java stejně jako třeba ObjC. Vzhledem k type erasure Javě typy v runtimu nijak nepomáhají, slouží jen k seřvání vývojáře, když píše blbě, v době překladu.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
Statické typy umožňují určit už v době kompilace, která metoda bude použita. Virtuální metoda se musí vybírat ze seznamu před každým voláním.
Tak C++ má statické typy i virtuální metody. Proč asi?
-
Virtuální metody fungují úplně stejně jako dispatch - objekty mají odkaz na tabulku metod svého typu, Java stejně jako třeba ObjC.
Co když volaná metoda v té tabulce není? Musí hledat dál, což je další režie.
-
Vzhledem k type erasure Javě typy v runtimu nijak nepomáhají, slouží jen k seřvání vývojáře, když píše blbě, v době překladu.
Však se o Javě nebavíme jako o typovém jazyce. V runtimu jsou typy jen jako atributy.
-
Vzhledem k type erasure Javě typy v runtimu nijak nepomáhají, slouží jen k seřvání vývojáře, když píše blbě, v době překladu.
Však se o Javě nebavíme jako o typovém jazyce. V runtimu jsou typy jen jako atributy.
Tak se nejdřív vy tři domluvte, co je podle vás “typový” (sic!) jazyk. Pokud by to měl být jen Haskell, tak pak jo, ovlivní to výkon.
-
A něco poučného na téma složitosti: http://www.knesl.com/budoucnost-programovacich-jazyku
Ten článek není úplně špatný. Akorát na konci se autor dopustil poměrně zásadní a docela časté chyby. Formuloval závěr na základě jim specifikovaných předpokladů, ale jaksi opomněl, že mu tam další předpoklady chybí.
Vynechal totiž nejdůležitější faktor, ovlivňující prodloužení doby vývoje: programátora. S bandou opic nejnovější funkcionalitu prostě nenaprogramujete, i když budete mít ty nejlepší nástroje. A protože poptávka po programátorech neustále stoupá, tak za současné situace logicky jejich kvalita klesá. A tady narážíme na limitující prvek. Klesající kvalita programátorů (nebo třeba nemožnost získat dostatečně kvalitní programátory) způsobí prodloužení doby implementace v případě použití složitého a vysoce sofistikovaného jazyka. Tak, jak se někdo v matematice zastaví u trigonometrických funkcí, někdo u logaritmů a další u integrálů a derivací, tak se zastaví u různé složitosti konstrukcí programovacích jazyků. A protože se jedná o pyramidu (skoro všichni zvládnou goniometrické funkce, logaritmy už menší skupina a integrály a derivace jen "hrstka"), můžete mít sice dokonalý jazyk, ale jeho zvládnutí vás může stát více času (pokud to vůbec dáte), než to funkčně naprogramovat v něčem primitivnějším.
A to je taky problém celého tohoto vlákna. Zatímco typový systém ekvivalentní unit testům možná dokáže navrhnout autor (a možná ještě další jeden nebo dva), napsat nějaký unit test dokáží víceméně všichni. A po nějakém tréninku velká většina z množiny všichni bude schopna psát kvalitní unit testy. Kolik dalších lidí zvládne Haskell na úrovni, kdy nahradí unit testy správnou volbou typů si netroufnu ani odhadovat.
Souhlasim. Neslo mi o jazyky s dynamickou syntaxi, o jejichz realne prakticnosti mam pochyby, ale uvidime, co prinese budoucnost. Slo mi o fenomen slozitosti, ktery se tu prehlizi a je imho vyznamne podstatnejsi ohledne kvality a spolehlivosti vysledne aplikace. Chci-li vysokou spolehlivost, nevyresim to typovym systemem, ale a) vhodnou metodou vyvoje software, zalozenou na dukladnych testech, viz treba extremni programovani, b) kvalitnim testovacim prostredim a c) zvolenám prostredku, ktere mi rozumne snizi druhotnou slozitost, jenz je vyznamnym zdrojem chyb (proto typicky neprogramujeme ve strojovem kodu nebo asm a proto se vyvoj nezastavil ani u jejich nastupcu C, C++, Java /C# nebo dnes popularni JS a Python, kde Python je nejpokrocilejsi, ale take nejmene vykonny). Ony ty testy take zvysuji druhotnou slozitost, ale maji vyhodu, ze nejsou soucasti produkcni aplikace a nezasahuji do ni, ale to uz se ale opakuji. Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí. Jeden blud za druhým, ach jo, to už na těch VŠ nic kloudného neučí?
Datove typy s vykonem aplikace souvisi velmi. Staticke typy umoznuji instrukce programu optimalizovat v dobe prekladu a zvysit jeho efektivitu. Dynamicke typy se musi vyhodnocovat runtime, takze a) instrukce nejde tak dobre optimalizovat, b) je s tim spojen vyssi overhead, navic to typicky vyzaduje behovou vrstvu navic, ktera zere pamet a ma vlastni overhead.
Co vas na VS ucili nevim, ale co jste si z toho odnesl je zalostne. Ale nezoufejte, bud realne programovat neco duleziteho nikdy nebudete a nebo si parkrat v produkci nabijete cumak na staticky typovanem jazyku a ono se vam v hlave srovna, jaky prinos maji typy a jaky testy.
-
Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
Z příspěvků zde uváděných mám občas pocit, že k zvládnutí Haskellu je nutné mít vystudovaný matfyz. Když však nahlédnu do reálných aplikací, tak vidím, že mnoho programátorů nezvládá ani namespace, které má Haskel na velmi dobré úrovni. Nejde tedy jen o to, jak moc je daný jazyk kvalitní, ale také jak jednoduché či složité je jeho používání.
-
Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
Z příspěvků zde uváděných mám občas pocit, že k zvládnutí Haskellu je nutné mít vystudovaný matfyz.
Haskell je naopak snadný na používání.
-
Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
Z příspěvků zde uváděných mám občas pocit, že k zvládnutí Haskellu je nutné mít vystudovaný matfyz. Když však nahlédnu do reálných aplikací, tak vidím, že mnoho programátorů nezvládá ani namespace, které má Haskel na velmi dobré úrovni. Nejde tedy jen o to, jak moc je daný jazyk kvalitní, ale také jak jednoduché či složité je jeho používání.
To imho neni vlastnost haskellu, ale funkcionalniho programovani, ktere se, alespon nam starym praktickým programatorum, jevi jako hodne nekompatibilni s lidskym myslenim. Ale mozná je to jen o zvyku. Je to takove ufonske, nebo by se to mohlo brat jako jakysi druh nepraktickeho umeni. Ma to smysl zkoumat akademicky, vysledky badani mohou obohatit ostatni jazyky. Ze by to nahradilo zavedene strukturovo objektove paradigma v nejblizsich letech neocekavam.
-
Nejde tedy jen o to, jak moc je daný jazyk kvalitní, ale také jak jednoduché či složité je jeho používání.
Ano, slozitost je potreba posuzovat na nekolika urovnich. Jak jednoduse je v jazyce mozno vyjadrit myslenku, kolik tomu klade formalnich prekazek. Jak prehledny a citelny/pochopitelny je zapis. Jak bohate a uzitecne jsou standardni knihovny a odladene knihovny tretich stran. Jak je jazyk intuitivni/logicky a chova se dle ocekavani, tj. jak snadno se da naucit a na kolik se musi myslet speku. Jak dobre je zdokumentovany. Jakou ma podporu v produkci, kvalitni ide, podporu pro debugovani, testovani, psani vlastni dokumentace. Jakou ma podporu u vyrobce nebo komunity, kdyz se vyskytne nejaky zapeklity problem - chyba ve vlatnim programovacim jazyce, at kompileru nebo behovem prostredi nebo systemovych knihovnach. A dalsi me asi hned nenapadly.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
Statické typy umožňují určit už v době kompilace, která metoda bude použita. Virtuální metoda se musí vybírat ze seznamu před každým voláním.
Tak C++ má statické typy i virtuální metody. Proč asi?
Dědičnost?
Protože C++ není schopen zajistit v době kompilace objektu (třídy) A, která bude volat metodu m instance b, zda to bude přímo té instance, nebo z jejího předka?
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
https://en.wikipedia.org/wiki/Virtual_method_table (https://en.wikipedia.org/wiki/Virtual_method_table)
A co s tím? Virtuální metody nijak nesouvisí s tím, jestli má jazyk (statické) typy nebo ne. Ten odkaz by klidně mohl být na Kozinovu větu a vyšlo by to nastejno.
Statické typy umožňují určit už v době kompilace, která metoda bude použita. Virtuální metoda se musí vybírat ze seznamu před každým voláním.
Tak C++ má statické typy i virtuální metody. Proč asi?
Dědičnost?
Protože C++ není schopen zajistit v době kompilace objektu (třídy) A, která bude volat metodu m instance b, zda to bude přímo té instance, nebo z jejího předka?
Samozřejmě, to byl příklad pro Kita.
-
Nejde tedy jen o to, jak moc je daný jazyk kvalitní, ale také jak jednoduché či složité je jeho používání.
Ano, slozitost je potreba posuzovat na nekolika urovnich. Jak jednoduse je v jazyce mozno vyjadrit myslenku, kolik tomu klade formalnich prekazek. Jak prehledny a citelny/pochopitelny je zapis. Jak bohate a uzitecne jsou standardni knihovny a odladene knihovny tretich stran. Jak je jazyk intuitivni/logicky a chova se dle ocekavani, tj. jak snadno se da naucit a na kolik se musi myslet speku. Jak dobre je zdokumentovany. Jakou ma podporu v produkci, kvalitni ide, podporu pro debugovani, testovani, psani vlastni dokumentace. Jakou ma podporu u vyrobce nebo komunity, kdyz se vyskytne nejaky zapeklity problem - chyba ve vlatnim programovacim jazyce, at kompileru nebo behovem prostredi nebo systemovych knihovnach. A dalsi me asi hned nenapadly.
Významnou roli hraje také křivka učení. XSLT je jednodušší než Haskell (nepracuje s typy) ale pro objektové programátory má poměrně vysokou vstupní bariéru, než se dostaví aha-efekt. Haskel sice má jednodušší zápis, ale o to víc musí začátečník zápolit s typy. Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
Takový Lisp je na pochopení mnohem jednodušší. Typy má jen jako atributy. Pokud mi nějaký jazykový konstrukt chybí, tak si ho prostě dodělám.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí. Jeden blud za druhým, ach jo, to už na těch VŠ nic kloudného neučí?
OMG! Zjisti si laskavě nejdřív něco o historii zavedení datových typů než začneš z neznalostí osočovat jiné. Protože nyní sis dal čistou ránu do vlastní brány. Prozradím ti, že historický důvod byl pouze - to podtrhuji! - pouze efektivní kod!
-
Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
Takhle přímo se tu ještě nikdo neptal. Na slušnou otázku by dostal slušnou odpověď.
-
Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
I skladník ve šroubárně si může přečíst Eilenberga a Mac Lana v originále ;)
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
Prozradím ti, že historický důvod byl pouze - to podtrhuji! - pouze efektivní kod!
Jistě to můžeš doložit ;)
-
Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
I skladník ve šroubárně si může přečíst Eilenberga a Mac Lana v originále ;)
To je od teba konečne niečo z praxe? To je to, čo robíš? Snažíš sa vyhrabať zo skladu? Ale na to ti citovanie úryvkov prác matematikoch nepomôže, tam pomôže jedine že tomu budeš aj rozumieť. Len či to nie je za hranicou mentálnych schopnosti nejakého čehúňa s maďarským nickom ;)
-
Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
I skladník ve šroubárně si může přečíst Eilenberga a Mac Lana v originále ;)
To je od teba konečne niečo z praxe? To je to, čo robíš? Snažíš sa vyhrabať zo skladu? Ale na to ti citovanie úryvkov prác matematikoch nepomôže, tam pomôže jedine že tomu budeš aj rozumieť. Len či to nie je za hranicou mentálnych schopnosti nejakého čehúňa s maďarským nickom ;)
Si opět koleduješ o smazání moderátorem. Slibovals, že se budeš chovat slušně. Moc dlouho ti to nevydrželo.
-
Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
I skladník ve šroubárně si může přečíst Eilenberga a Mac Lana v originále ;)
To je od teba konečne niečo z praxe? To je to, čo robíš? Snažíš sa vyhrabať zo skladu? Ale na to ti citovanie úryvkov prác matematikoch nepomôže, tam pomôže jedine že tomu budeš aj rozumieť. Len či to nie je za hranicou mentálnych schopnosti nejakého čehúňa s maďarským nickom ;)
Si opět koleduješ o smazání moderátorem. Slibovals, že se budeš chovat slušně. Moc dlouho ti to nevydrželo.
Ale keď s tebou sa tak dobre háda... No tak jo, no tak idem pokračovať v slušnom správaní :/
-
Když se tady zeptá, co je to monáda, tak dostane jen drzou odpověď, že si má nastudovat Teorii kategorií, nejlépe v originále.
I skladník ve šroubárně si může přečíst Eilenberga a Mac Lana v originále ;)
To je od teba konečne niečo z praxe? To je to, čo robíš? Snažíš sa vyhrabať zo skladu? Ale na to ti citovanie úryvkov prác matematikoch nepomôže, tam pomôže jedine že tomu budeš aj rozumieť. Len či to nie je za hranicou mentálnych schopnosti nejakého čehúňa s maďarským nickom ;)
Si opět koleduješ o smazání moderátorem. Slibovals, že se budeš chovat slušně. Moc dlouho ti to nevydrželo.
Ale keď s tebou sa tak dobre háda... No tak jo, no tak idem pokračovať v slušnom správaní :/
Köszönöm.
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
Prozradím ti, že historický důvod byl pouze - to podtrhuji! - pouze efektivní kod!
Jistě to můžeš doložit ;)
Viz poznámky Johna Backuse k návrhu FORTRANu. Bez datových typů by byl generovaný kód zbytečně dlouhý - kompilátor by musel vložit kód pro všechny možné podporované typy a konverze mezi nimi v dané operaci - a pomalý - rozhodovalo by se až za běhu, rutina pro který typ se má vlastně zavolat. Proměnné s deklarovanými datovými typy daly překladači potřebnou informaci v době kompilace, ale i tak to bylo chápáno jako nutné zlo, technikálie, proto se to snažili nějak eliminovat aspoň implicitním typováním (které převzal např. BASIC a částečně i původní C dle K&R ještě 10 let po FORTRANu).
Je dobré si uvědomit, že tenkrát se kolem počítačů pohybovala úplně jiná sorta lidí než dnes. Byly to čestné pozice pro ty nejlepší z nejlepších. Kdybych použil příměr - bývaly doby, kdy člověk, který by v rukopisu normostrany textu při diktátu šel pod 240 úhozů za minutu a udělal víc jak 1,5 promile chyb, nemohl dělat písaře. Raději by vybrali někoho zdatnějšího. Dnes je třeba zapisovat takové množství textů, že se vymýšlejí nástroje, které umožní zaměstnat jako písaře i cvičenou opici. Co tu řešíte okolo těch typů je přesně na této úrovni - považuješ za nevzdělance lidi, kteří tě upozorňují, že textový editor byl v první řadě vymyšlen jako nástroj pro rychlé pořizování a editace textů. Už jsi z toho tak zblbnul (myšleno v dobrém), že tvrdíš, že to s tím nijak nesouvisí, že hlavní funkcí editoru je automatická oprava pravopisu a doplňování slov.
P.S. - jeden takový příhodný citáteček na popíchnutí:
I’m not against types, but I don’t know of any type systems that aren’t a complete pain, so I still like dynamic typing.
-
P.S. - jeden takový příhodný citáteček na popíchnutí:
I’m not against types, but I don’t know of any type systems that aren’t a complete pain, so I still like dynamic typing.
To by chtělo rozvést, udělal to Kay nebo to je jen věta vytržená z kontextu? Jinak obecně absence of evidence ain’t evidence of absence.
Jinak nemá smysl a je hloupé prosazovat extremistické názory, ať už na jedné nebo druhé straně. Já třeba spoustu let dělal v ObjC a tamní způsob posílání zpráv mi vyhovoval (doteď ho považuju za takřka geniální), ale taky je jasné, že typová kontrola při překladu (typy místo prostého id všude) je užitečná, i když za běhu se s typy nepracuje. Na druhou stranu dokážu ocenit i typový systém Haskellu nebo podobných jazyků s “typovým našeptáváním”.
-
Souhlasim. Neslo mi o jazyky s dynamickou syntaxi, o jejichz realne prakticnosti mam pochyby, ale uvidime, co prinese budoucnost. Slo mi o fenomen slozitosti, ktery se tu prehlizi a je imho vyznamne podstatnejsi ohledne kvality a spolehlivosti vysledne aplikace. Chci-li vysokou spolehlivost, nevyresim to typovym systemem, ale a) vhodnou metodou vyvoje software, zalozenou na dukladnych testech, viz treba extremni programovani, b) kvalitnim testovacim prostredim a c) zvolenám prostredku, ktere mi rozumne snizi druhotnou slozitost, jenz je vyznamnym zdrojem chyb (proto typicky neprogramujeme ve strojovem kodu nebo asm a proto se vyvoj nezastavil ani u jejich nastupcu C, C++, Java /C# nebo dnes popularni JS a Python, kde Python je nejpokrocilejsi, ale take nejmene vykonny). Ony ty testy take zvysuji druhotnou slozitost, ale maji vyhodu, ze nejsou soucasti produkcni aplikace a nezasahuji do ni, ale to uz se ale opakuji. Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
Jen pro doplnění. Kdysi jsem četl jeden zajímavý článek (bohužel už ho teď nedohledám), kde autor považoval za velice důležitý parametr jazyka konzistentní hustotu informací (to je moje parafráze, jak to nazval on už si nepamatuji). Šlo o to, aby nebylo na 3 řádcích "prázdno" a pak na jednom řádku složitá konstrukce. Tímhle nešvarem dle mého názoru trpí třeba Perl nebo Python, naopak jazyky jako Lua nebo Go jsou skoro až řídké (alespoň dle mých zkušeností). Nejzajímavější na tom je to, že ve výsledku nevidím, že by program v Go nebo Lue byl delší než odpovídající program v v Perlu nebo Pythonu, skoro naopak.
Tahle ta konzistentní hustota je podle autora článku klíčová pro snadnou čitelnost/udržitelnost kódu.
-
Jen pro doplnění. Kdysi jsem četl jeden zajímavý článek (bohužel už ho teď nedohledám), kde autor považoval za velice důležitý parametr jazyka konzistentní hustotu informací (to je moje parafráze, jak to nazval on už si nepamatuji). Šlo o to, aby nebylo na 3 řádcích "prázdno" a pak na jednom řádku složitá konstrukce. Tímhle nešvarem dle mého názoru trpí třeba Perl nebo Python, naopak jazyky jako Lua nebo Go jsou skoro až řídké (alespoň dle mých zkušeností). Nejzajímavější na tom je to, že ve výsledku nevidím, že by program v Go nebo Lue byl delší než odpovídající program v v Perlu nebo Pythonu, skoro naopak.
Tahle ta konzistentní hustota je podle autora článku klíčová pro snadnou čitelnost/udržitelnost kódu.
Moc pěkné. Děkuji.
-
Jen pro doplnění. Kdysi jsem četl jeden zajímavý článek (bohužel už ho teď nedohledám), kde autor považoval za velice důležitý parametr jazyka konzistentní hustotu informací (to je moje parafráze, jak to nazval on už si nepamatuji). Šlo o to, aby nebylo na 3 řádcích "prázdno" a pak na jednom řádku složitá konstrukce. Tímhle nešvarem dle mého názoru trpí třeba Perl nebo Python, naopak jazyky jako Lua nebo Go jsou skoro až řídké (alespoň dle mých zkušeností). Nejzajímavější na tom je to, že ve výsledku nevidím, že by program v Go nebo Lue byl delší než odpovídající program v v Perlu nebo Pythonu, skoro naopak.
Tahle ta konzistentní hustota je podle autora článku klíčová pro snadnou čitelnost/udržitelnost kódu.
Mel bys priklad? Zajimal by me ten nesvar u perlu nebo pythonu... jak to vypada.
-
Souhlasim. Neslo mi o jazyky s dynamickou syntaxi, o jejichz realne prakticnosti mam pochyby, ale uvidime, co prinese budoucnost. Slo mi o fenomen slozitosti, ktery se tu prehlizi a je imho vyznamne podstatnejsi ohledne kvality a spolehlivosti vysledne aplikace. Chci-li vysokou spolehlivost, nevyresim to typovym systemem, ale a) vhodnou metodou vyvoje software, zalozenou na dukladnych testech, viz treba extremni programovani, b) kvalitnim testovacim prostredim a c) zvolenám prostredku, ktere mi rozumne snizi druhotnou slozitost, jenz je vyznamnym zdrojem chyb (proto typicky neprogramujeme ve strojovem kodu nebo asm a proto se vyvoj nezastavil ani u jejich nastupcu C, C++, Java /C# nebo dnes popularni JS a Python, kde Python je nejpokrocilejsi, ale take nejmene vykonny). Ony ty testy take zvysuji druhotnou slozitost, ale maji vyhodu, ze nejsou soucasti produkcni aplikace a nezasahuji do ni, ale to uz se ale opakuji. Typovy system slozitost programu zvysuje a to primo umerne se svou silou. Tedy cim dukladneji resi jeden zdroj chyb, tim posiluje jiny zdroj chyb, druhotnou slozitost. Argument kvality a spolehlivosti je u staticky typu proto falesny. Jejich opodstatneni je jine, v moznosti lepsi optimalizace a vyssiho vykonu aplikace. Ale k tomu neni potreba, hadam, vyssi typovy system, staci k tomu datove typy na urovni architektury.
Jen pro doplnění. Kdysi jsem četl jeden zajímavý článek (bohužel už ho teď nedohledám), kde autor považoval za velice důležitý parametr jazyka konzistentní hustotu informací (to je moje parafráze, jak to nazval on už si nepamatuji). Šlo o to, aby nebylo na 3 řádcích "prázdno" a pak na jednom řádku složitá konstrukce. Tímhle nešvarem dle mého názoru trpí třeba Perl nebo Python, naopak jazyky jako Lua nebo Go jsou skoro až řídké (alespoň dle mých zkušeností). Nejzajímavější na tom je to, že ve výsledku nevidím, že by program v Go nebo Lue byl delší než odpovídající program v v Perlu nebo Pythonu, skoro naopak.
Tahle ta konzistentní hustota je podle autora článku klíčová pro snadnou čitelnost/udržitelnost kódu.
Java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
C
#include <stdio.h>
int main(){
printf("Hello, World!");
return 0;
}
Go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
Python 3, Lua
print("Hello, World!")
Perl
print "Hello, World!\n";
Python 2
print "Hello, World!"
Python není jazyk vycpaný vatou, na to tu jsou jiní experti, třeba Java.
A i co se týče zápisu algoritmu není Python nijak zbytečně ukecaný a jde přímočaře k věci, oproštěn od všeho zbytečného. Následující jsem převzal z nějakého benchmarku jazyku.
Python 2
import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
Lua
local h, max, n = {}, 0, 0
for l in io.lines() do
if (h[l]) then
h[l] = h[l] + 1
else
n, h[l] = n + 1, 1
end
max = max > h[l] and max or h[l]
end
print(n, max)
Go
package main
import (
"fmt"
"bufio"
"os"
)
func main() {
r := bufio.NewReader(os.Stdin)
h := make(map[string]int, 1e6)
max := 1
for {
b, e := r.ReadSlice('\n')
if e != nil {
break
}
l := string(b)
v := h[l] + 1
h[l] = v
if v > max {
max = v
}
}
fmt.Printf("%d\t%d\n", len(h), max)
}
Java
import java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
Ano, jsou to primitivní demonstrační příklady. Zajímavé to začne být ve chvíli, kdy chceme doplnit třeba unit testy o kterých je tu řeč. Python nabízí několikero možností, pro malé věci se nabízí třeba velmi pohodlný doctest. Následuje drobná úprava předešlého kódu:
import sys
def counter(lines):
r"""
>>> from cStringIO import StringIO as fwrap
>>> counter(fwrap('a\nb\nb\n'))
(2, 2)
>>> counter(fwrap('a\nb\nb'))
(3, 1)
>>> counter(fwrap(''))
(0, 0)
>>> counter(fwrap('a a'))
(1, 1)
"""
h, m = {}, 0
for l in lines:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
return len(h), m
if __name__ == '__main__':
print counter(sys.stdin)
A takto se to použije:
python -m doctest -v dict-test.py
Trying:
from cStringIO import StringIO as fwrap
Expecting nothing
ok
Trying:
counter(fwrap('a\nb\nb\n'))
Expecting:
(2, 2)
ok
Trying:
counter(fwrap('a\nb\nb'))
Expecting:
(3, 1)
ok
Trying:
counter(fwrap(''))
Expecting:
(0, 0)
ok
Trying:
counter(fwrap('a a'))
Expecting:
(1, 1)
ok
1 items had no tests:
dict-test
1 items passed all tests:
5 tests in dict-test.counter
5 tests in 2 items.
5 passed and 0 failed.
Test passed.
Bez verbose to vypisuje jenom chyby. Doctest lze separovat do pomocného txt souboru, pokud by někomu vadilo mít testy přímo v kódu. Pro složitější projekty pak python nabízí komplexnější modul unittest. Testy jsou důležité, ale důležité je také aby byly snadno použitelné, jinak je nikdo u menších věcí používat nebude.
-
A mimochodem, byl to právě doctest, kdo mě upozornil na to, že výstup z funkce se liší podle toho, zda je poslední řádek ukončen znakem \n nebo ne. Reálně bych to ve funkci ošetřil, aby na tom nezáleželo, ale nechtěl jsem do ní zasahovat. A tohle jde už imho za hranici možností statických typů. Tedy premisa tohoto téma - dobrý typový systém činí unit testy zbytečnými, je dle mého vyvrácena.
-
...
Tedy premisa tohoto téma - dobrý typový systém činí unit testy zbytečnými, je dle mého vyvrácena.
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
-
Mel bys priklad? Zajimal by me ten nesvar u perlu nebo pythonu... jak to vypada.
Než jsem stačil odpovědět, tak jsou tady příklady. Pokud vezmu uvedený příklad
import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
tak řádek h[l] = h[l] + 1 if l in h else 1
má významně vyšší hustotu informací než ostatní řádky. Neříkám, že je špatně, v Pythonu je to celkem idiomatická konstrukce, jen to vypichuju jako ten příklad.
-
Zajímavé to začne být ve chvíli, kdy chceme doplnit třeba unit testy o kterých je tu řeč. Python nabízí několikero možností, pro malé věci se nabízí třeba velmi pohodlný doctest.
python -m doctest -v dict-test.py
Bez verbose to vypisuje jenom chyby. Doctest lze separovat do pomocného txt souboru, pokud by někomu vadilo mít testy přímo v kódu. Pro složitější projekty pak python nabízí komplexnější modul unittest. Testy jsou důležité, ale důležité je také aby byly snadno použitelné, jinak je nikdo u menších věcí používat nebude.
Díky, o této možnosti jsem netušil. Pokud něco budu psát v Pythonu, určitě to použiji.
-
řádek h[l] = h[l] + 1 if l in h else 1
má významně vyšší hustotu informací než ostatní řádky. Neříkám, že je špatně, v Pythonu je to celkem idiomatická konstrukce, jen to vypichuju jako ten příklad.
To by vysvětlovalo, proč mnozí vývojáři nemají rádi SQL. Také má významně vyšší hustotu informací než ostatní řádky.
-
Java
import java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
A nedalo by se to napsat treba takhle?
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Map<String, Integer> h = new HashMap<>();
stdin.lines().forEach(l -> h.compute(l, (k, v) -> v == null ? 1 : v + 1));
System.out.println(h.size() + " " + h.values().stream().max(Integer::compare).orElse(0));
}
Ja vim, ze je to furt skaredy, a kdybych to dostal na code review tak bych k tomu mel minimalne 3 komentare, ale ...
-
Mel bys priklad? Zajimal by me ten nesvar u perlu nebo pythonu... jak to vypada.
Než jsem stačil odpovědět, tak jsou tady příklady. Pokud vezmu uvedený příklad
import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
tak řádek h[l] = h[l] + 1 if l in h else 1
má významně vyšší hustotu informací než ostatní řádky. Neříkám, že je špatně, v Pythonu je to celkem idiomatická konstrukce, jen to vypichuju jako ten příklad.
OK. Rozumim. Diky
-
Java
import java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
A nedalo by se to napsat treba takhle?
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Map<String, Integer> h = new HashMap<>();
stdin.lines().forEach(l -> h.compute(l, (k, v) -> v == null ? 1 : v + 1));
System.out.println(h.size() + " " + h.values().stream().max(Integer::compare).orElse(0));
}
Ja vim, ze je to furt skaredy, a kdybych to dostal na code review tak bych k tomu mel minimalne 3 komentare, ale ...
Mozna jeste elegantnejsi zapis:
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Map<String, Integer> h = stdin.lines().collect(Collectors.toMap(k -> k, v -> 1, (i, j) -> i + j));
System.out.println(h.size() + " " + h.values().stream().max(Integer::compare).orElse(0));
}
-
v pythonu přesně na tohle existuje specializovaná kolekce Counter, když už se bavíte o idiomatickém kódu
import sys
from collections import Counter
c = Counter(sys.stdin)
print(len(c), c.most_common(1)[0][1])
-
...
Tedy premisa tohoto téma - dobrý typový systém činí unit testy zbytečnými, je dle mého vyvrácena.
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
Záleží na definici dobrého typového systému. Pokud je to takový, že dělá unit testy zbytečnými, pak jazyk s dobrým typovým systémem neexistuje.
-
Mel bys priklad? Zajimal by me ten nesvar u perlu nebo pythonu... jak to vypada.
Než jsem stačil odpovědět, tak jsou tady příklady. Pokud vezmu uvedený příklad
import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
tak řádek h[l] = h[l] + 1 if l in h else 1
má významně vyšší hustotu informací než ostatní řádky. Neříkám, že je špatně, v Pythonu je to celkem idiomatická konstrukce, jen to vypichuju jako ten příklad.
Imho nemá vyšší informační hustotu, než třeba ve většině jazyků běžný for( ; ; ), takže se to ničemu běžnému nevymyká. Zajímavé je, že tě nezaujalo hůře čitelné 'max = max > h[l] and max or h[l]' u jazyku Lua, který dáváš za vzor jazyka, který má údajně hustotu rovnoměrnou. Pokud je řádek krátký a dobře čitelný, není jednořádkový if na škodu, právě naopak, dělá program přehlednější a pro složitější podmínky má python if klasický, nezatížený vatou prázdných řádků se závorkou, jak je ostatně vidět o řádek níž.
-
Java
import java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
A nedalo by se to napsat treba takhle?
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Map<String, Integer> h = new HashMap<>();
stdin.lines().forEach(l -> h.compute(l, (k, v) -> v == null ? 1 : v + 1));
System.out.println(h.size() + " " + h.values().stream().max(Integer::compare).orElse(0));
}
Ja vim, ze je to furt skaredy, a kdybych to dostal na code review tak bych k tomu mel minimalne 3 komentare, ale ...
Dalo, ale je to hůře čitelné a srozumitelné. Cíl není nejmenší počet řádků, ale nejvyšší přehlednost a čitelnost, aby se programator nedopouštěl chyb z nepozornosti a nepochopení.
-
Java
import java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
A nedalo by se to napsat treba takhle?
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Map<String, Integer> h = new HashMap<>();
stdin.lines().forEach(l -> h.compute(l, (k, v) -> v == null ? 1 : v + 1));
System.out.println(h.size() + " " + h.values().stream().max(Integer::compare).orElse(0));
}
Ja vim, ze je to furt skaredy, a kdybych to dostal na code review tak bych k tomu mel minimalne 3 komentare, ale ...
Dalo, ale je to hůře čitelné a srozumitelné. Cíl není nejmenší počet řádků, ale nejvyšší přehlednost a čitelnost, aby se programator nedopouštěl chyb z nepozornosti a nepochopení.
1. Zalezi na tom co ses zvyklej cist. Kdyz sem poprve videl lambdu tak mi to taky neslo prez rohovku.
2. Zajimave je, ze v te tve javove verzi jsou dve chyby z nepozornosti...
-
Jejich benefit spočívá ve výkonu
Typy s výkonem nijak nesouvisí.
Prozradím ti, že historický důvod byl pouze - to podtrhuji! - pouze efektivní kod!
Jistě to můžeš doložit ;)
Viz poznámky Johna Backuse k návrhu FORTRANu
byl by odkaz nebo alespoň původní název textu?
-
Dalo, ale je to hůře čitelné a srozumitelné. Cíl není nejmenší počet řádků, ale nejvyšší přehlednost a čitelnost, aby se programator nedopouštěl chyb z nepozornosti a nepochopení.
1. Zalezi na tom co ses zvyklej cist. Kdyz sem poprve videl lambdu tak mi to taky neslo prez rohovku.
2. Zajimave je, ze v te tve javove verzi jsou dve chyby z nepozornosti...
Nejde o lambdu, ale o příliš dlouhé řádky, na kterých se toho děje příliš mnoho. Tyto úsporné zápisy dobrou čitelnost kódu nepodporují. Moje javova verze byla stažena z webu z nějakého benchmarku, ktery porovnaval ruzne jazyky. Divím se spíš, že nikdo neprotestoval proti používání proměnné l, to je prasárna, ale nechtěl jsem do těch kódů zasahovat.
-
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
To už tady bylo hodněkrát:
A Typy nejsou zázračný lék
B Jsou
A Tady máš příklady v jazycích A, B, C, D, E, F, G, H
B Haha, jenže to nejsou jazyky s dobrým typovým systémem...
A ?
B Haskell, pyčo! Všichni tři, co ho používáme, si ho nemůžeme vynachválit.
-
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
To už tady bylo hodněkrát:
A Typy nejsou zázračný lék
B Jsou
A Tady máš příklady v jazycích A, B, C, D, E, F, G, H
B Haha, jenže to nejsou jazyky s dobrým typovým systémem...
A ?
B Haskell, pyčo! Všichni tři, co ho používáme, si ho nemůžeme vynachválit.
Pobavilo :-).
Haskell nepouzivam, snazil jsem se poukazat na to, ze nemuze vyvracet hypotezu o typovych sytemech ukazkama kodu z jazyku, ktery bud nemaji staticke typy vubec, nebo je maji tak zprasene, ze spis prekazi... (nechci hodnotit go, pac ho neznam).
[metafora]
A: Dospel jsem k nezdravemu presvedceni, ze oktavka ujede trasu z Prahy do Brna rychleji nez BMW M3.
B: To ti muzu snadno vyvratit... podivej se treba na tenhle pomeranc
[/metafora]
-
Dalo, ale je to hůře čitelné a srozumitelné. Cíl není nejmenší počet řádků, ale nejvyšší přehlednost a čitelnost, aby se programator nedopouštěl chyb z nepozornosti a nepochopení.
1. Zalezi na tom co ses zvyklej cist. Kdyz sem poprve videl lambdu tak mi to taky neslo prez rohovku.
2. Zajimave je, ze v te tve javove verzi jsou dve chyby z nepozornosti...
Nejde o lambdu, ale o příliš dlouhé řádky, na kterých se toho děje příliš mnoho. Tyto úsporné zápisy dobrou čitelnost kódu nepodporují. Moje javova verze byla stažena z webu z nějakého benchmarku, ktery porovnaval ruzne jazyky. Divím se spíš, že nikdo neprotestoval proti používání proměnné l, to je prasárna, ale nechtěl jsem do těch kódů zasahovat.
Nejde o usporne zapisy, ale o deklarativni vs. imperativni pristup.
Diky deklarativnejsimu zapisu, muzu spoustu veci vynechat a to citelnost zvysuje. Proste tim, ze je tam min veci na cteni a pochopeni.
A je podle me jedno kdo tu javovou verzi psal. Tvuj argument byl, ze je napsana takovym stylem, ze tam bude min chyb z nepozornosti. A stejne tam jsou. Tudiz je podle me predpoklad mylny. Imperativni pristup nijak nezvysuje citelnost/prehlednost/udrzovatelnost kodu. Spis naopak.
-
Java
import java.util.HashMap;
import java.io.*;
class dict_v1 {
public static void main(String[] args) {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
HashMap<String, Integer> h = new HashMap<String, Integer>();
String l;
int max = 0;
int x = 0;
while ((l = stdin.readLine()) != null) {
if (h.containsKey(l)) {
x = h.get(l) + 1;
h.put(l, x);
if (x > max){
max = x;
}
} else h.put(l, 1);
}
System.out.println(h.size()+" "+max);
}
}
A nedalo by se to napsat treba takhle?
public static void main(String[] args){
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
Map<String, Integer> h = new HashMap<>();
stdin.lines().forEach(l -> h.compute(l, (k, v) -> v == null ? 1 : v + 1));
System.out.println(h.size() + " " + h.values().stream().max(Integer::compare).orElse(0));
}
Ja vim, ze je to furt skaredy, a kdybych to dostal na code review tak bych k tomu mel minimalne 3 komentare, ale ...
Mně zas přijde divné, že nikomu na hustotu nevadila kostrukce "while ((l = stdin.readLine()) != null)".
Dále (jak si správně všimnul Listoper) je tato konstrukce vyloženě pozůstatkem z dob sraček typu C++ - dnes nejsme v době primitivních jazyků, abychom museli iterovat přes collection ručně!!!
-
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
To už tady bylo hodněkrát:
A Typy nejsou zázračný lék
B Jsou
A Tady máš příklady v jazycích A, B, C, D, E, F, G, H
B Haha, jenže to nejsou jazyky s dobrým typovým systémem...
A ?
B Haskell, pyčo! Všichni tři, co ho používáme, si ho nemůžeme vynachválit.
Pobavilo :-).
Haskell nepouzivam, snazil jsem se poukazat na to, ze nemuze vyvracet hypotezu o typovych sytemech ukazkama kodu z jazyku, ktery bud nemaji staticke typy vubec, nebo je maji tak zprasene, ze spis prekazi... (nechci hodnotit go, pac ho neznam).
[metafora]
A: Dospel jsem k nezdravemu presvedceni, ze oktavka ujede trasu z Prahy do Brna rychleji nez BMW M3.
B: To ti muzu snadno vyvratit... podivej se treba na tenhle pomeranc
[/metafora]
Aha, jenze to jsi se ztratil v debate. To nebyla reakce na typovy system, ale na hustotu kodu. Ten pomeranc je tvuj.
-
Dalo, ale je to hůře čitelné a srozumitelné. Cíl není nejmenší počet řádků, ale nejvyšší přehlednost a čitelnost, aby se programator nedopouštěl chyb z nepozornosti a nepochopení.
1. Zalezi na tom co ses zvyklej cist. Kdyz sem poprve videl lambdu tak mi to taky neslo prez rohovku.
2. Zajimave je, ze v te tve javove verzi jsou dve chyby z nepozornosti...
Nejde o lambdu, ale o příliš dlouhé řádky, na kterých se toho děje příliš mnoho. Tyto úsporné zápisy dobrou čitelnost kódu nepodporují. Moje javova verze byla stažena z webu z nějakého benchmarku, ktery porovnaval ruzne jazyky. Divím se spíš, že nikdo neprotestoval proti používání proměnné l, to je prasárna, ale nechtěl jsem do těch kódů zasahovat.
Nejde o usporne zapisy, ale o deklarativni vs. imperativni pristup.
Diky deklarativnejsimu zapisu, muzu spoustu veci vynechat a to citelnost zvysuje. Proste tim, ze je tam min veci na cteni a pochopeni.
A je podle me jedno kdo tu javovou verzi psal. Tvuj argument byl, ze je napsana takovym stylem, ze tam bude min chyb z nepozornosti. A stejne tam jsou. Tudiz je podle me predpoklad mylny. Imperativni pristup nijak nezvysuje citelnost/prehlednost/udrzovatelnost kodu. Spis naopak.
Nemyslím si, ze by chyba v nejake nahodne vybrane ukazce kodu na netu byla statisticky vyznamna. Ano, v prehlednem a snadno citelnem zapisu bude mene chyb. Java takovou syntaxi nema, a nahrazujes pouze jednu neprehlednou formu druhou a to at to napises zpusobem jakym chces. Pricemz ja tvuj styl zapisu povazuji za zvlast neprehledny.
-
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
To už tady bylo hodněkrát:
A Typy nejsou zázračný lék
B Jsou
A Tady máš příklady v jazycích A, B, C, D, E, F, G, H
B Haha, jenže to nejsou jazyky s dobrým typovým systémem...
A ?
B Haskell, pyčo! Všichni tři, co ho používáme, si ho nemůžeme vynachválit.
Pobavilo :-).
Haskell nepouzivam, snazil jsem se poukazat na to, ze nemuze vyvracet hypotezu o typovych sytemech ukazkama kodu z jazyku, ktery bud nemaji staticke typy vubec, nebo je maji tak zprasene, ze spis prekazi... (nechci hodnotit go, pac ho neznam).
[metafora]
A: Dospel jsem k nezdravemu presvedceni, ze oktavka ujede trasu z Prahy do Brna rychleji nez BMW M3.
B: To ti muzu snadno vyvratit... podivej se treba na tenhle pomeranc
[/metafora]
Aha, jenze to jsi se ztratil v debate. To nebyla reakce na typovy system, ale na hustotu kodu. Ten pomeranc je tvuj.
Ale notak. Koukni na co jsem reagoval.
...
Tedy premisa tohoto téma - dobrý typový systém činí unit testy zbytečnými, je dle mého vyvrácena.
Myslis, ze nektery z tech jazyku ve tvych ukazkach ma dobry typovy system?
-
Dalo, ale je to hůře čitelné a srozumitelné. Cíl není nejmenší počet řádků, ale nejvyšší přehlednost a čitelnost, aby se programator nedopouštěl chyb z nepozornosti a nepochopení.
1. Zalezi na tom co ses zvyklej cist. Kdyz sem poprve videl lambdu tak mi to taky neslo prez rohovku.
2. Zajimave je, ze v te tve javove verzi jsou dve chyby z nepozornosti...
Nejde o lambdu, ale o příliš dlouhé řádky, na kterých se toho děje příliš mnoho. Tyto úsporné zápisy dobrou čitelnost kódu nepodporují. Moje javova verze byla stažena z webu z nějakého benchmarku, ktery porovnaval ruzne jazyky. Divím se spíš, že nikdo neprotestoval proti používání proměnné l, to je prasárna, ale nechtěl jsem do těch kódů zasahovat.
Nejde o usporne zapisy, ale o deklarativni vs. imperativni pristup.
Diky deklarativnejsimu zapisu, muzu spoustu veci vynechat a to citelnost zvysuje. Proste tim, ze je tam min veci na cteni a pochopeni.
A je podle me jedno kdo tu javovou verzi psal. Tvuj argument byl, ze je napsana takovym stylem, ze tam bude min chyb z nepozornosti. A stejne tam jsou. Tudiz je podle me predpoklad mylny. Imperativni pristup nijak nezvysuje citelnost/prehlednost/udrzovatelnost kodu. Spis naopak.
Nemyslím si, ze by chyba v nejake nahodne vybrane ukazce kodu na netu byla statisticky vyznamna. Ano, v prehlednem a snadno citelnem zapisu bude mene chyb. Java takovou syntaxi nema, a nahrazujes pouze jednu neprehlednou formu druhou a to at to napises zpusobem jakym chces. Pricemz ja tvuj styl zapisu povazuji za zvlast neprehledny.
Chapu. Je to tvuj nazor. Docela by me zajimalo jestli je vas s tim nazorem vic.
-
Mel bys priklad? Zajimal by me ten nesvar u perlu nebo pythonu... jak to vypada.
Než jsem stačil odpovědět, tak jsou tady příklady. Pokud vezmu uvedený příklad
import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
tak řádek h[l] = h[l] + 1 if l in h else 1
má významně vyšší hustotu informací než ostatní řádky. Neříkám, že je špatně, v Pythonu je to celkem idiomatická konstrukce, jen to vypichuju jako ten příklad.
Imho nemá vyšší informační hustotu, než třeba ve většině jazyků běžný for( ; ; ), takže se to ničemu běžnému nevymyká. Zajímavé je, že tě nezaujalo hůře čitelné 'max = max > h[l] and max or h[l]' u jazyku Lua, který dáváš za vzor jazyka, který má údajně hustotu rovnoměrnou. Pokud je řádek krátký a dobře čitelný, není jednořádkový if na škodu, právě naopak, dělá program přehlednější a pro složitější podmínky má python if klasický, nezatížený vatou prázdných řádků se závorkou, jak je ostatně vidět o řádek níž.
Nic jsi nepochopil.
1. Jestli to nevidíš, tak jsi prostě slepý.
2. Argumentovat výrazem, který ve všech těch jazycích bude vypadat zhruba stejně je další nesmysl. Bavíme se o konstrukcích jazyka, ne o tom, jak kdo dokáže znepřehlednit program složitými výrazy.
3. Já nebojuji žádnou válku proti Pythonu, tak se uklidni. Dal jsem k dispozici (podle mne) zajímavý názor, pokud se ti nezamlouvá, tak si řekni, že je to kokotina a klidně to tu napiš. Ale z toho co jsi sem napsal to spíš vypadá, že máš pocit, že jsme ti sebrali lopatičky a tvé argumenty se snaží vyvrátit něco, s čím nikdo nepolemizuje.
4. Poznámka o for cyklu je dobrá.
-
Mel bys priklad? Zajimal by me ten nesvar u perlu nebo pythonu... jak to vypada.
Než jsem stačil odpovědět, tak jsou tady příklady. Pokud vezmu uvedený příklad
import sys
h, m = {}, 0
for l in sys.stdin:
h[l] = h[l] + 1 if l in h else 1
if m < h[l]:
m = h[l]
print len(h), m
tak řádek h[l] = h[l] + 1 if l in h else 1
má významně vyšší hustotu informací než ostatní řádky. Neříkám, že je špatně, v Pythonu je to celkem idiomatická konstrukce, jen to vypichuju jako ten příklad.
Imho nemá vyšší informační hustotu, než třeba ve většině jazyků běžný for( ; ; ), takže se to ničemu běžnému nevymyká. Zajímavé je, že tě nezaujalo hůře čitelné 'max = max > h[l] and max or h[l]' u jazyku Lua, který dáváš za vzor jazyka, který má údajně hustotu rovnoměrnou. Pokud je řádek krátký a dobře čitelný, není jednořádkový if na škodu, právě naopak, dělá program přehlednější a pro složitější podmínky má python if klasický, nezatížený vatou prázdných řádků se závorkou, jak je ostatně vidět o řádek níž.
Nic jsi nepochopil.
1. Jestli to nevidíš, tak jsi prostě slepý.
2. Argumentovat výrazem, který ve všech těch jazycích bude vypadat zhruba stejně je další nesmysl. Bavíme se o konstrukcích jazyka, ne o tom, jak kdo dokáže znepřehlednit program složitými výrazy.
3. Já nebojuji žádnou válku proti Pythonu, tak se uklidni. Dal jsem k dispozici (podle mne) zajímavý názor, pokud se ti nezamlouvá, tak si řekni, že je to kokotina a klidně to tu napiš. Ale z toho co jsi sem napsal to spíš vypadá, že máš pocit, že jsme ti sebrali lopatičky a tvé argumenty se snaží vyvrátit něco, s čím nikdo nepolemizuje.
4. Poznámka o for cyklu je dobrá.
Nezlob se, ale ublizene mi znis ty sam.
ad 0) jak muzu mit dobrou poznamku o for, kdyz jsem nic nepochopil?
ad 1) neni jasne o cem mluvis
ad 2) neni to nesmysl, je to dukaz toho, ze lua ti nebrani psat informacne ruzne huste radky, neni to totiz jen vec jazyka, ale i programatora, viz ty dalsi ukazky javy, ktere to řadne 'vylepsily' a jejich autori jsou dokonce presvedceni ze je to tak lepsi
ad 3) jsem klidny, jen poukazuji na tvuj omyl, python se informacni homogenitou nevymyka standardu, naopak je v tom spise nadprumerne lepsi, protoze ma malo syntakticke vaty. Obecne si nemyslim ze je to kokotina, byt jsi to napsal spatne, ma to racionalni zaklad. Zakladni problem neni informacni nehomogenita, zakladni problem jsou slozite vyrazy na jednom radku u kterych se pri cteni kodu zadrhnes a chvili trva, nez je pochopis. Kdyz ten zapis udelas informacne homogenni tak, ze vsechny radky budou huste a zadrhnes se u vsech, tak to bude porad spatne. Takze a) je potreba mit informacni hustotu takovou, aby zapis byl snadno a rychle pochopitelny a to je spis vec programatora nez jazyka a b) je potreba se zbavit vaty, coz je predevsim vec jazyka.
-
co je "typ"?
-
co je "typ"?
metadata k hodnote?
-
co je "typ"?
metadata k hodnote?
metadata to je neco vagniho, to muze byt treba cas vytvoreni.
Datovy typ je spis dvojice: mnozina hodnot a mnozina operaci, ne?
-
co je "typ"?
metadata k hodnote?
metadata to je neco vagniho, to muze byt treba cas vytvoreni.
Datovy typ je spis dvojice: mnozina hodnot a mnozina operaci, ne?
Množina operací asi nebude stačit. Ještě je třeba název kategorie pro nominální typování.
-
co je "typ"?
metadata k hodnote?
metadata to je neco vagniho, to muze byt treba cas vytvoreni.
Datovy typ je spis dvojice: mnozina hodnot a mnozina operaci, ne?
Množina operací asi nebude stačit. Ještě je třeba název kategorie pro nominální typování.
Já bych to omezil na pojmenovanou množinu hodnot. Operace běžně pracují s více hodnotama různého typu, takže by se stejná operace dala najít ve spoustě typů.
-
Datovy typ je spis dvojice: mnozina hodnot a mnozina operaci, ne?
Množina operací asi nebude stačit. Ještě je třeba název kategorie pro nominální typování.
Já bych to omezil na pojmenovanou množinu hodnot. Operace běžně pracují s více hodnotama různého typu, takže by se stejná operace dala najít ve spoustě typů.
buildPerson :: Name -> Name -> Age -> Person
bmi :: Age -> Sex -> Weight -> Height -> BMI
Samozřejmě často si vystačím jen s rozhraním na základě operací. Ale ten nominální typ mi pomůže ohlídat, že tam nervu blbost.
... ale možná že "pojmenovaná množina hodnot" je to, o čem mluvím :-) Age je pojmenovaný subset Intu. Kde potřebuju Int mohu dát Age, kde potřebuju Age nemohu dát Int.
-
Na tohle sem dnes narazil: https://serokell.io/blog/2018/12/17/why-dependent-haskell (https://serokell.io/blog/2018/12/17/why-dependent-haskell)
-
Na tohle sem dnes narazil: https://serokell.io/blog/2018/12/17/why-dependent-haskell (https://serokell.io/blog/2018/12/17/why-dependent-haskell)
Dost zajímavé, ale není to pro BFP.
-
Pro rozšíření obzorů: https://www.manning.com/books/programming-with-types
-
Před pár dny jsem narazil na indexikální typy a vzpomněl si, že tebe typové systémy a intuicionistická logika zajímají, tak jen dávám tip ;) Je to něco jako “this”, ale na úrovni typů. Jdou skrz to implementovat higher-kinded typy v systému prvního řádu (bez explicitních HKT), takže ve výsledku je takový systém formálně silnější (a kompatibilní s dědičností).
-
Před pár dny jsem narazil na indexikální typy a vzpomněl si, že tebe typové systémy a intuicionistická logika zajímají, tak jen dávám tip ;) Je to něco jako “this”, ale na úrovni typů. Jdou skrz to implementovat higher-kinded typy v systému prvního řádu (bez explicitních HKT), takže ve výsledku je takový systém formálně silnější (a kompatibilní s dědičností).
Díky. Jsem rád za každý hint.
Nějaký odkaz, článek, by nebyl?
-
Před pár dny jsem narazil na indexikální typy a vzpomněl si, že tebe typové systémy a intuicionistická logika zajímají, tak jen dávám tip ;) Je to něco jako “this”, ale na úrovni typů. Jdou skrz to implementovat higher-kinded typy v systému prvního řádu (bez explicitních HKT), takže ve výsledku je takový systém formálně silnější (a kompatibilní s dědičností).
Díky. Jsem rád za každý hint.
Nějaký odkaz, článek, by nebyl?
Takhle z hlavy mě napadá jen dokumentace ke Swiftu, zejména použití Self a jeho spojení s asociovanými typy. Teď zrovna nemám na nic čas, ale za pár dnů k tomu můžu něco napsat tady.
-
Před pár dny jsem narazil na indexikální typy a vzpomněl si, že tebe typové systémy a intuicionistická logika zajímají, tak jen dávám tip ;) Je to něco jako “this”, ale na úrovni typů. Jdou skrz to implementovat higher-kinded typy v systému prvního řádu (bez explicitních HKT), takže ve výsledku je takový systém formálně silnější (a kompatibilní s dědičností).
Díky. Jsem rád za každý hint.
Nějaký odkaz, článek, by nebyl?
Takhle z hlavy mě napadá jen dokumentace ke Swiftu, zejména použití Self a jeho spojení s asociovanými typy. Teď zrovna nemám na nic čas, ale za pár dnů k tomu můžu něco napsat tady.
To by bylo super. Na Swift se podívám. Já hledal obecně, a našel jen něco pro TypeScript, ale to odhadem je něco jiného stejného jména.
-
To by bylo super. Na Swift se podívám. Já hledal obecně, a našel jen něco pro TypeScript, ale to odhadem je něco jiného stejného jména.
Jo, to bylo asi “indexable types”, já zmiňoval “indexical types.” To jsou typy, jejichž denotát závisí na kontextu. V podstatě něco jako “this”, ale na úrovni typů. Jsou to obecně higher-kinded typy, které žádný z hlavních OO jazyků vyjma C++ nemá. V metodách se dá používat Self[T] a podobné srandičky, což vede k mnohem silnějšímu typovému systému, než má třeba Java.
-
Zjistil jsem, že Julia má (nevím, od které verze) něco jako závislostní součtový typ (píšu “něco jako”, protože to zřejmě není zamýšlená vlastnost jejího typového systému). Dávám to sem jen jako doplňující poznámku související s tématem tohoto starého vlákna, kdyby si někdo (BoneFlute :) ) chtěl hrát se závislostními typy a nechce se mu otravovat s haskelloidními jazyky — Julia je přece jenom stravitelnější.
-
Zjistil jsem, že Julia má (nevím, od které verze) něco jako závislostní součtový typ (píšu “něco jako”, protože to zřejmě není zamýšlená vlastnost jejího typového systému). Dávám to sem jen jako doplňující poznámku související s tématem tohoto starého vlákna, kdyby si někdo (BoneFlute :) ) chtěl hrát se závislostními typy a nechce se mu otravovat s haskelloidními jazyky — Julia je přece jenom stravitelnější.
Zavislostni typy jsou dnes mainstream
-
Zjistil jsem, že Julia má (nevím, od které verze) něco jako závislostní součtový typ (píšu “něco jako”, protože to zřejmě není zamýšlená vlastnost jejího typového systému). Dávám to sem jen jako doplňující poznámku související s tématem tohoto starého vlákna, kdyby si někdo (BoneFlute :) ) chtěl hrát se závislostními typy a nechce se mu otravovat s haskelloidními jazyky — Julia je přece jenom stravitelnější.
Zavislostni typy jsou dnes mainstream
;D
-
Zjistil jsem, že Julia má (nevím, od které verze) něco jako závislostní součtový typ (píšu “něco jako”, protože to zřejmě není zamýšlená vlastnost jejího typového systému). Dávám to sem jen jako doplňující poznámku související s tématem tohoto starého vlákna, kdyby si někdo (BoneFlute :) ) chtěl hrát se závislostními typy a nechce se mu otravovat s haskelloidními jazyky — Julia je přece jenom stravitelnější.
Díky.
-
Zjistil jsem, že Julia má (nevím, od které verze) něco jako závislostní součtový typ (píšu “něco jako”, protože to zřejmě není zamýšlená vlastnost jejího typového systému). Dávám to sem jen jako doplňující poznámku související s tématem tohoto starého vlákna, kdyby si někdo (BoneFlute :) ) chtěl hrát se závislostními typy a nechce se mu otravovat s haskelloidními jazyky — Julia je přece jenom stravitelnější.
Díky.
Není zač. Jsem si hrál s typem Vect n a (haskelloidní zápis) a funguje to podobně jako třeba v Agdě. Ještě zkusím rovnostní typy :)
-
Zjistil jsem, že Julia má (nevím, od které verze) něco jako závislostní součtový typ (píšu “něco jako”, protože to zřejmě není zamýšlená vlastnost jejího typového systému). Dávám to sem jen jako doplňující poznámku související s tématem tohoto starého vlákna, kdyby si někdo (BoneFlute :) ) chtěl hrát se závislostními typy a nechce se mu otravovat s haskelloidními jazyky — Julia je přece jenom stravitelnější.
Díky.
Malé doplnění: Je to za cenu typové nestability (ale výsledek se dá typově stabilizovat za běhu).