Autor má pravdu, že Java je otřesně navržená a s Kayovým OOP nemá mnoho společného. Dost ale pochybuju, že spásou je zrovna funkcionální programování. V OO jazyce může funkční (byť většinou blbě navržený) kód spáchat i průměrný lepič (jichž je většina), kdežto v FP jsou intelektuální nároky podstatně vyšší. Proto se ostatně FP mimo akademickou sféru moc nerozšířilo.
Spásou je Golang, 2 roky prace v ňom a totalne ti zmení myslenie, a to tak v akomkoľvek projekte v akomkoľvek štádiu budeš vedieť skočiť medzi ostatnych typkov čo to programovali, a do 5 sekund vieš čo to robí, jak je kód psaný, a hneď vieš nadviazať, a sám efektivne napíšeš za chvíľu tucet novej funkcionality do softwaru. V Jave nemožné, ani kdyby ten projekt byl napsaný sebevíc dokonale. V Jave máš furt obavu že když zmeníš jeden riadok kódu v metóde ktorá pečie zemiaky, že to spôsobí že ti už nenastartuje auto.... Najhoršie je polimorfizmus, Inheritence, dokopy vytvára závislosti všetkého na všetkom. Presný opak toho čo by malo byť cieľom pôvodného OOP.
v Golangu jsem bohuzel delal pul roku a snad uz nikdy vice.
Z nejake priciny nekdo zamerne odignoroval 20 let vyvoje CS a udelal cosi z roku 1980 s pridanyma gorutinama, coz je jedina pekna zalezitost golangu a s pridanym garbage collectorem.
Neumi to vyjimky a jeste to prezentujou jako znouzectnost.
Kod je pak plny bordelu typu
x,err=func(blabla)
if(err) {
defer handler()
}
y,err2 = func2(bleble)
if(err2) {
handler(2)
}
V libovolnem jazyce s vyjimkama mam jasne oddeleny blok business funkce a error handlingu.
V tom hnoji ukazanem vyse mam z celkem 8 radku kodu 2 radky tykajici se business logiky, 3/4 je balastni hnuj.
A kdyz chci prohledat error handling, musim si najit ty handlery, nekde na druhem konci zdrojaku... Nebo to strcim inline primo do defer function{} - pak mam pomer business logika/balast tak 1:10...
Hnus, porad musim procitat hromady balastniho hnoje a pracne preparovat business logiku/error handling.
Nebo neexistence generik. Vzdyt golang nema ani takovou trivialitu jako je sorted map. V C++ od pocatku veku.
Ale chapu, ze pro cloveka, co srandovne jednoduchou Jawu poklada za slozity jazyk, je Golang dobry.
Zaklad golangu obsahne gibbon za odpoledne, kdyz to nic neumi, neni toho moc se ucit.
Tady je ale problém trochu jiný. C++ dlouho nemělo unordered_map ve standardní knihovně. Ale nestandardních hashmap bylo k dispozici celkem dost, protože se přes templaty dala implementovat bez jakékoliv změny v samotném jazyce. V Go máš prostě smůlu.
C++ je složité mimo jiné protože je to obecný jazyk pro hromadu různorodých věcí. Go je doménově specifický jazyk navržený přesně na problémy, které řeší Google.
píšeš jeden príklad, kde to je najviac problémové, ostatne ale "try-catch" zabere 4 riadky taky. I v jave mohu napsať:
try {
// funkcionalita
}
catch (Expection e) {
// handle error
}
a vidíš, 6 riadkov, a len jeden je funkcionalita.
ak si odpustíš catch, tak to je to isté ako napsať podtržítko v e promennej. Navyše pri komplexnejších kódoch naopak u Javy sa nabalí balastu omnoho viac. A Java určite neni srandovne jednoduchy jazyk, keby bol, nemuselo by byť vymyslené stovky design patternov, aby sa nestávali situácie že zmením kód v stroji na obrábanie zemiakov, a ono to rozbije atomovú elektráreň.
A proc bych mel proboha kazde volani metody balit do separatniho try-catch bloku?
V Jawe muj go priklad vypada takto
try {
x = obj.method1();
y= obj.method1();
} catch (Exception e) {
..handle
}
Abych vedel, co dela business logika, stavi precist 2 radky volani metod uvnitr try.
Abych vedel co dela handler - staci precist obsah v catch bloku.
V GO je debilne zmatlana business logika s error handlingem, navic jeste v pripade defer funkci si musim i analyzovat poradi vkladani na defer zasobnik.
Defacto, abych pochopil business logiku, musim dekodovat kompletni kod vcetne error handlingu. Kontrolovat si, jestli tam nekdo nezavolal defer, co se spusti uplne mimo flow pri opousteni funkce.
V Jawe vidim proste zavolani 2 metod po sobe - to je vse.
V catch bloku je kompletne lokalni handling.
Nebe a dudy.
A netusim co to tu melse o zemiakach a atomovych elektrarnach.
Java ma naopak mnohem vymakanejsi ochranu proti nechtenemu zasahu do objektu zvenci (public, private, protected, package specific, final)
Go ma jenom primitivni public/private rozliseni pres uppercase prvni pismeno funkce.
Design patterny jsou prosty popis best practices jak resit bezne problemy, netusim co to ma mit spolecneho s kvalitou jazyka.
Bezne GoF paterrny jsou v Golangu nepouzitelne, protoze to je jazyk tak nemohouci, ze tyto implementovat nelze.
Golang design patterny jsou samozrejme standard, tady mas popis pipeline patternu:
https://blog.golang.org/pipelines
Vyuziva kanaly a gorutiny, coz je jedina pekna vec na golangu. Jinak je go zoufalstvi.
A? To chces "usetrit" tim, ze odstranis to handlovani?
Kazdopadne zrovna tenhle pripad je krasne citelny a primocary. Urcite vic, nez ten bordel v golangu.
(A jde to samozrejme i jinak, pri osetreni chyb muzes uz nejaky cas v Java pouzit i postupy inspirovane FP. V tom golangu mas smulu a nemuzes pouzit prakticky nic.)
Sice ne zrovna dlouho (v poměru k věku), ale Java dneska má spoustu užitečných věcí jako Optional, lambdy a streamy. Také moc pěkný executor mechanizmus, až ho Python zkopíroval [1]. Jo, `go moje_metoda()` je kratší než `Executor.submit(moje_metoda)`, ale ve výsledku to dělá skoro to samé.
[1] https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor
Golang naopak nemá nic z těch dobrých vlastností ostatních.. generika, čitelný error handling.
A dynamické struktury jsou v Golang peklo. Zkuste si přistupovat k pod.spec.template.spec.metadata.annotations.neco, když tam může cokoliv z toho chybět. V Javě s Optional nebo v Pythonu alespoň s výjimkami je to triviální a čitelné.
Totálně možná změnilo myšlení tobě, ale když se na Go podívám já, tak to takhle nevidím. Nemám nic proti jednoduchým jazykům a Go jde v této linii, ale žádné nové a zajímavé paradigma nepřidává, nic mi v hlavě nového nedocvaklo. Když to porovnám třeba s konkatenativními jazyky, Lisp a ML jazyky, "pure" OO (Eiffel, Smalltalk), prototypovými (Self) a dokonce i C++ (šablony). Třeba Python je fajn a dělám v něm skoro vše, ale že bych ho takhle adoroval, to už mám za sebou. S Pythonem je to jen sňatek z rozumu. V Javě jsem taky něco napsal -- tenkrát jsem byl blázen do DDD (a stále jsem) a věř mi, že i po letech se ten "dobře nadyzajnovanej" kód refaktoruje a mění líp než co jsem psal v Pythonu, což je nejen kvůli dostupným nástrojům, ale i jazykem samotným. Java není tak špatná a Go není spása.
23. 7. 2019, 10:38 editováno autorem komentáře
Na dědičnosti není nic špatného, když je nepovinná (např. ve Smalltalku, Pythonu, ...). To ale neplatí u Jávky (a dalších s*aček), protože tam se kýženého polymorfismu nedosahuje zasíláním zpráv, ale voláním podtypově příbuzných (tento hovadismus se zove „podtypový polymorfismus“), čímž se dědičnost stává povinnou, takže zabřednete buďto do vymýšlení správné hierarchie, nebo (u vícenásobné dědičnosti) do bordelu mezi předky. Nebo do smršti rozhraní.
Nadměrné používání dědičnosti považuju za selhání výuky programování. Z praxe vidím, že je to celkem okrajová featura, většina tříd nepotřebuje být v nějaké hierarchii.
Ohledně "smršti rozhraní" - interface je prostě způsob, jak automaticky ověřit, že objekty dostávají zprávy, které očekávají. V některých jazycích to musí hlídat sám programátor, v některých to (alespoň částečně) ověří překladač. Obojí má své místo pod sluncem. Pokud tam je těch rozhraní hodně, tak to svědčí o špatném návrhu, jazyk nic takového nevynucuje.
Ehm?
O interfacech jsi uz nejspis slysel. Proc je teda dedicnost v Jave povinna?
Hlava mi to prilis nebere, osobne jsem jsem nepsal dedenou tridu ani nepamatuju, na vsecko pouzivam interfaces.
A vicenasobna dedicnost a bordel mezi predky v Jave?
Pan bude zrejme znalec.
V mem vesmiru Java vicenasobnou dedicnost nepodporuje.
V mem vesmiru se pouziva dedeni pro pripady, kdy chci rozsirovat funkcionalitu pri zachovani stavajicic.
Typicky HashMap -> LinkedHashMap
Pro proty polymofrni pristup k objektum se pouzvaji vetsinou intrefaces.
Rozhraní jsem zmínil, takže ano, pak platí, že k dosažení polymorfismu je třeba buďto dědičnosti nebo rozhraní. Ve Smalltalku a Pythonu ani jednoho, a o to tu šlo.
Měl jsem na mysli např. C++, napsal jsem to špatně.
V mém vesmíru se používá dědičnost všude tam, kde je to výhodné ke sdílení kódu. V mém vesmíru se také používá diakritika, aniž by k tomu bylo třeba velkého znalectví.
Ta smršť rozhraní je i v tom Golangu. Jediný rozdíl je v tom, že v Javě je musíte uvádět. Ta implicitní rozhraní v Golangu jsou opravdu docela fajn, ale Java také nespí a má od v. 8 rozumný počet dobře definovaných rozhraní pro funkcionální přístup - https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
V tom Golangu pak také není všechno růžové. Java sice vyžaduje uvádět typy i pro výjimky, zatímco Golang má obecný error. Jenže zjistit z hlavičky jaké errory může funkce v Golang vrátit je nemožné (a z kódu skoro - někdy to bublá pěkně z hluboka).
Spíš FP dobře funguje na "čistých" problémech. V praxi jsou ale problémy skoro vždy "chlupaté", mají různé výjimky "když tohle" a "když tamhleto". Ne, že by se to FP nedalo řešit, ale už to zdaleka není tak elegantní. "Čisté" problémy tak řeší hlavně akademici. Aneb "mám řešení, ale funguje jen pro sférickou slepice ve vakuu" :-)