Dobrý den, jestli jsem něco nepřehlédl, chybí v přehledu (a seznamu pro následující díl) porovnání ukazatelů na funkce/uzávěrů, to je podle mě hezké téma (možná i na samostatný článek). Nabízí se i srovnání s uzávěry v C (nestandardní rozšíření __block a ^{...} clangu) a řešení přístupu k proměnným vnějšího kontextu (idiom x:=x apod.), v tom se často chybuje i v JS a C#.
Jsem primárně rusťák, ale Go mi připadá taky zajímavý a sympatický jazyk, který bych si rád vyzkoušel v praxi při nějakém hobby projektu. Jenže se mi zdá (možná mylně), že prakticky celý ekosystém Go se točí kolem webovek, což je problematika, která mě nikdy příliš nelákala, tak bych bych byl vděčný, kdyby tady nějací Gočkaři mohli uvést příklady jiných typů aplikací, na které se Go hodí.
Užitečné projekty jsou například MinIO a NATS
https://min.io/
https://nats.io/
A potom věci okolo Kubernetes včetně samotného Kubernetes
Ač mám nějaké výhrady, tak bych si rád taky Go vyzkoušel na nějakém hobby projektu, kdybych měl víc času. Některé koncepty - např. gorutiny - se mi hodně líbí a v pozadí hlavy tak trochu přemýšlím, jak se z toho poučit pro zlepšení stávajících projektů.
Je tu ale jedna věc, která mne prakticky odrazuje od jakéhokoliv většího nasazení. Upozorňuji ale, že se to týká něčeho, co je hodně kontroverzní, takže jakékoliv reakce zavánějící flamewarem budu kompletně ignorovat a žádám ostatní komentátory o totéž. Tím je automatické formátování. Resp. to by mi vlastně vůbec nijak nevadilo, ale mám problém s jednou konkrétní volbou - začátek bloku na stejném řádku, jako podmínka, cyklus, funkce, atd. Z určitých důvodů teď pracuji na Drupalu (PHP) a čistě z důvodu konzistence jsem si v IDE (pro vlastní moduly) nastavil automatické formátování dle jejich konvencí, které pracují s bloky stejně, jako Go. A za boha si na to nemohu zvyknout - ten kód je pro mne mnohem méně čitelnější a nijak se mi nezdá, že by se to den-ode-dne zlepšovalo. Když se projeví chyba, tak u běžných programů mám automaticky pocit „ok, tak jdeme na to, stack-trace, popis chyby, ok, ...“, kdežto v tomto projektu to je spíš „néééé, nechci se v tom hrabat“ - i když jsem to napsal před 10 minutami... Zbývající rozhodnutí ohledně formátování jsou mi ale totálně šumák. Už před nějakou dobou mi začalo být jedno jestli mezery nebo taby (ale u nás ve firmě si myslím, že by byly lepší taby, protože kolegové kašlou na auto-formátování a ignorují, když jim tam přibude nebo zmizí nějaká ta mezera a blok se posune), nebo zda 2 mezery VS 4 (Drupal používá 2 a na to jsem si zvykl takřka okamžitě i přesto, že používám 4 mnohá léta). Jen ty bloky nejsem schopný do svého mozku namlátit...
Autoformátování je se dneska prosazuje všude, i v Rustu. Nemluvně o jazycích jako je Python nebo Haskell kde je syntaxe dvourozměrná neboli existuje v podstatě jediný přípustný způsob, jak formátovat kód. Obecně myslím, že to má spoustu výhod. Jednotně formátovaný kód a prostředky, jak to vynucovat, značně usnadňuje správu záplat, mergování, code review atd. a samozřejmě, že je vždycky nějaký detail, který se danému jednotlivci nelíbí a chtěl by ho jinak. Byly věci, které mě v rustovském autoformátování zpočátku vytáčely. Na většinu jsem si zvykl, na některé ne ale zvykl jsem si aspoň pokrčit rameny a neřešit je. Možná by se dalo říct, že do budoucna by na tom nemělo až tolik záležet, protože inteligentní editor, resp. IDE a jeho nástroje, by ideálně měl pracovat na úrovni syntaktického stromu a ne na úrovni řádků textu, ale tam bohužel všeobecně ještě nejsme.
Náhodou, i v Pythonu je dost formátovacích nuancí, nad kterýma se dá v rámci review zhádat :D
Každopádně, osobně mi autoformátování vyhovuje. Začala jsem ho používat právě u Rustu a… Ony jsou ty oblíbené způsoby zápisu hlavně o zvyku. Sjednocení formátování kódu je věc, která za tu chvilku nepohodlí a zvykání si stojí.
„Ony jsou ty oblíbené způsoby zápisu hlavně o zvyku. Sjednocení formátování kódu je věc, která za tu chvilku nepohodlí a zvykání si stojí.“
No a můj problém je v tom, že toto se mi podařilo u úplně všech konvencí (a to celkem rychle), kromě té jedné, kterou jsem zmínil - když „{“ není na novém řádku, pro mne je ten kód výrazně méně čitelnější, mnohem hůř se mi v něm orientuje.
Nebo možná jsem jen netrpělivý? Kolik je „chvilka“? Nad oním projektem jsem strávil už víc, jak 50 hodin...
Edit: překlep
19. 9. 2019, 10:12 editováno autorem komentáře
V Pythonu se také používá autoformátování, problém je, že některé formátovače umožňují zbytečně moc voleb. Formátovač bez voleb podobný gofmt je black. https://github.com/psf/black
nastavení formátovače by každopádně mělo být součástí projektu, nemělo by se o tom diskutovat při review.
19. 9. 2019, 14:34 editováno autorem komentáře
Myslel jsem to tak, že když je kód všude formátovaný stejně, tak se v něm reviewer snáz zorientuje a posupem času s většími zkušenostmi už ho některé potenciální problémy budou samy bít do očí, aniž by musel vyvíjet zbytečně velké úsilí na to, aby zdroják mentálně parsoval. Samozřejmě, že nejde o to, že review by byla ta pravá chvíle se začít hádat, jestli má být někde mezera nebo tab a hestli má být { na novém řádku...
„a samozřejmě, že je vždycky nějaký detail, který se danému jednotlivci nelíbí a chtěl by ho jinak.“
To je mi jasné a právě proto, že tento princip chápu, neřeším ostatní konvence, které se mi tak úplně nelíbí na různých projektech. Když si uvědomím, že to nemá žádný výrazný praktický vliv, tak to hodím za hlavu a vím, že si na to zvyknu. Že snaha s tím něco dělat jsou jednak žabomyší války a jednak by to bylo vlastně dost sobecké a sebestředné. Ale to, co jsem popisoval, vidím jako problém, protože to mi to dlouhodobě překáží. Zpomaluje. A nakonec, vytváří odpor k dané práci (což je o to horší, že je to není projekt ze zaměstnání, ale ve volném čase).
Souhlasím s Vámi - moderní jazyky dnes trpí na "scope creep", zahrnují do sebe funkce, které tradičně byly externí. Např. package management (cargo, pip, gems, ...) podle mě smysl dává, ale integrovaný a povinný linter je už trochu za hranou. Styl psaní je jako dialekt u přirozených jazyků a tak je to jako nutit Ostraváka mluvit hantecem.
To je částečně pravda, ale jakmile se pracuje ve větší skupině nebo dokonce distribuovaně, tak už to zase spíš spadá do kategorie nezbytné kázně. Stejně jako je nějaký pracovní jazyk (nemyslím programovací) a Ostravák, Pražák i Plzeňák si při chytání bugů můžou nadávat každý po svém, ale do mailing listu budou všichni psát spisovnou češtinou, aby si vzájemně rozuměli.
v tom nejdál je Jai, kde je nastavení buildu součástí zdrojového kódu. Zajímavý projekt. Autor vychází ze zkušeností s vývojem AAA her. Vývoj jazyka streamuje na Twitchi.
https://www.twitch.tv/naysayer88/videos
19. 9. 2019, 14:56 editováno autorem komentáře
Pořád se nemohu ubránit pocitu, když se snažím sledovat vývoj jazyků, že tyto nové jazyky (go, rust) jsou na půli cesty mezi C a C++.
C -> (go, rust) -> java -> C++
A proto, jakákoliv snaha pochopit tyhle jazyky pro mne znamená snížit se na úroveň myšlení, kde jsem byl před 10-15 lety. Mí přátele znají můj názor, který by se dal jednoduše vyjádřit větou: "na to se vykašlete a naučte se pořádně C++"
(no flame)
Gorutiny, kanály, koherentní syntax s přímou podporou pro věci, jako jsou seznamy, vícenásobné vratné hodnoty, automatickou typovou inferenci (postupně se do C++ zavádí, ale Go jde dále, i když samo o sobě je v tomto bodě dost primitivní), integrovanou správu balíků, velmi rychlou kompilaci, která umožňuje Go používat i jako v podstatě skriptovací jazyk, apod.
U věcí jako je garbage collector a duck typing se nedá říct, že je "postrádá", protože u některých problémů představují výhodu a u jiných naopak nevýhodu. Nicméně tam, kde jsou žádoucí, je tím pádem Go lépe vyhovující jazyk.
C++20 nedožene jednoduchost a programátorskou produktivitu, jakou nabízí Go. Stejně tak nedožene typový systém Rustu a statickou prokazatelnost, kterou tento umožňuje. Dohnat takovéto vlastnosti není možné, pokud to má zůstat C++.
Což samozřejmě neznamená, že by C++ nemělo taky svoje výhody a silné stránky jak proti Go, tak proti Rustu. Ale je absolutní blbost tvrdit, že jím vývoj v oboru programovacích jazyků na věky skončil a od té doby je všechno jenom jakási náhražka pro ty, co se nedokáží naučit C++.
Tak především když pronášíte takovéto generalizace o Go a Rustu, tak to svědčí o tom, že je moc neznáte, protože oba tyto jazyky jsou koncepčně úplně jiné a kladou si naprosto odlišné cíle. Mluvit o tom, jak si údajně stojí "Go a Rust" nemá o mnoho větší smysl, než mluvit obecně o "Javě a Fortranu".
Dále ten údajný názor "vašich přátel" by se dal přirovnat k tvrzení, že nemá moc velký smysl se zabývat věcmi, jako je Cairo a Vulkan, lepší je se pořádně naučit xlib
Jazyk, ve kterém by nebylo nic, co by se mi nelíbilo, jsem jaktěživ neviděl, ačkoli kdyby mi někdo chtěl tvrdit, že takovým jazykem má být C++, tak se na to vykašlu a půjdu radši pást kozy
O D se taky trochu zajímám, i když pro něj v hobby projektech nemám použítí. Kdo hledá přímou náhradu za C++, pro toho je D dneska možná ideální volba a navíc i částečně zpětně kompatibilní. Bohužel na výsluní se už asi nedostane. Dlouho trpěl problémy na úrovni komunity (dvě různé, nekompatibilní "standardní" knihovny), má omezený ekosystém a novější jazyky, jako právě Go, Swift a Rust už jsou ve svých nikách vývojově zase někde jinde.
Já si osobně nemohu pomoci, ale go, rust, javu apod. bych neskládal mezi C a C++, spíš do samostatné větve (začínající v C, ale nekončící v C++). V mnohých ohledech mi nové jazyky (teď spíše mluvím o C# a Pythonu, se kterými mám víc zkušeností, než javou (už je to dávno) či go a rustem (žádné)) přijdou (ve srovnání s C++) jeden krok vpřed a dva do strany (myšleno negativně).
Posledních pár let pracuji primárně v C# a zrovna poslední rok mám na starosti kód, který má být dost výkonný v reálném čase (o čemž bych mohl klidně napsat rozsáhlý silně hate článek) a v podstatě je mi celý jazyk překážkou, než pomůckou (pro tento účel). (Na přepnutí do C++ je dávno pozdě.)
Na druhou stranu ale jednoznačně uznávám, že jestliže neřeším každou milisekundu, ale mám jich pár volných (toto není nadsázka), tak implementace C# (často řádově násobně pomalejší, než v C++) dostačuje a vývoj je výrazně rychlejší a tedy levnější. A pohodlnější. A umožňuje tedy i víc/rychleji/snadněji experimentovat s různými řešeními. Tedy to, co bych potřeboval, je jazyk, který má rychlost vývoje odpovídající javě/C#, ale s možností se přepnout do „výkonného módu“ na úrovni C++. A unsafe C# je (s přihlédnutím na integraci se „safe“ C#) hluboko pod čistým C.
Navíc C++ má spousty vlastních problémů (často z historických důvodů + zpětné kompatibility, občas celkem nešťastné rozhodnutí), takže jako vývojář bych si hrozně moc přál něco jako ++C (C++ 2). Který by se poučil s řešení moderních jazyků, ale vyhnul se jejich problémům. Už jenom ta tendence psát si vlastní „STL“, kterou v jiných jazycích nemám, o čem vypovídá (a rozhodně nejsem sám).
C# dejme tomu patří celkově do podobného směru, jako Go (myšleno ve smyslu orientace na síťové služby a business aplikace, GC, filozofie zaměřená na snadnou použitelnost atd) ale přiznám se, že snažit se ho používat na RT kód by mě nenapadlo ani ve zlém snu. Totéž platí o Go. Rust je úplně jiná kapitola a pro aplikace tohoto typu naopak exceluje, možná, že právě v něm byste nalezl vhodného nástupce C++. Na druhou stranu psát v něm web službu nebo nějakou aplikaci používající SQL backend je jen pro otrlé masochisty, to snad už i v samotném C++ by to byl menší opruz!
20. 9. 2019, 08:41 editováno autorem komentáře
„ale přiznám se, že snažit se ho používat na RT kód by mě nenapadlo ani ve zlém snu“
Ne vždy si může člověk vybrat, v čem se bude dělat...
„Totéž platí o Go.“
A přitom gorutiny - aspoň, jak jsem je pochopil - umožňují daleko efektivnější využití CPU, než co jsem viděl jinde. Když si v jiném jazyce vytvořím frontu úloh a spustím N vláken (N = počet jader), ale přitom některé čekají na pomalejší zdroj (např. HDD)...
Z diskuze začínám mít dojem, že bych měl upřesnit, že výrazem „mám na starosti kód, který má být dost výkonný v reálném čase“ nemám na mysli „kritickou real-time aplikaci“, ale když už, tak „soft real-time“ (tedy nestihnu není konec světa, ale není to ani dobře).
(Což samozřejmě nic nemění na problémech, které GC nebo výše zmíněný nedeterminismus gorutin přináší.)
Co přesně myslíte tím “nedeterminismem gorutin”? Ty jsou přece rozvrhovány kooperativně a tedy deterministicky (na rozdíl od preemptivních vláken) a čekají jen na vnější podněty (zámky, síť, disk...).
A jaké problémy přináší GC? Ten má v Go někde od verze 1.5 minimální latenci a téměř se neprojevuje (na tom má zásluhu hlavně alokace většiny objektů na zásobníku díky pokročilé escape analýze). Upřímně by mě zajímalo, na jaký problém jste v Go v souvislosti s GC narazil.
Jinak v RT (včetně soft) se alokuje veškerá paměť na začátku a později už se na haldu nesahá (ať už jazyk používá GC nebo explicitní alokaci), ovšem jak jsem psal, v Go je to jedno, není-li problémem latence v řádu 100 μs.
Viz https://www.root.cz/clanky/programovaci-jazyk-go-pro-skalni-ceckare/nazory/#o1027611. Já osobně zkušenosti s go nemám žádné (takže jej nehodnotím), jen mi přišlo, že diskuze částečně může vycházet z určitých předpokladů, tak jsem je chtěl upřesnit a zároveň jsem chtěl vyjádřit, že tím nijak neoponuji výše odkazovanému názoru.
Aha, tak to bylo nedorozumění. Jinak ten odkazovaný “názor” je nebetyčná blbost.
Co se týče .NET (potažmo C#), kritické (řekneme RT) věci se dají řešit přes C++/CLI, kde má člověk plnou kontrolu nad alokací a zároveň nepotřebuje (relativně pomalé) P/Invoke. Kdysi o této kombinaci vyšla obsáhlá bichle zaměřená na high frequency trading. Tím neříkám, že bych .NET na něco takového použil, ale pokud už do toho člověk zabředne, může to být jediné schůdné řešení (a poměrně rozumné, zvlášť dnes v době C++17).
Není to blbost, natož nebetyčná. Jednoduchý příklad (převzatý a pozměněný z A Tour of Go):
package main
import (
"fmt"
"time"
)
func main() {
for k := 0; k < 20; k++ {
go func() {
fmt.Println("running")
for {}
} ()
}
timer1 := time.NewTimer(2* time.Second)
<- timer1.C
fmt.Println("Timer 1 expired")
timer2 := time.NewTimer(time.Second)
go func() {
<- timer2.C
fmt.Println("Timer 2 expired")
} ()
stop2 := timer2.Stop()
if stop2 {
fmt.Println("Timer 2 stopped")
}
}
Prvních 20 gorutin cykluje naprázdno, samozřejmě je to simulace nějakého dlouhého výpočtu, který plně využívá všechna jádra a všechna vlákna na úrovni OS. Následuje soft-RT část. Když si to pustíte, uvidíte, že čekání na timery bude trvat různě dlouho a někdy (u mě často) se nedočkáte nikdy, protože runtime je plně vytížen stávajícími gorutinami. Neboli je nutné programovat kooperativním způsobem se všemi složitostmi, co to obnáší. Netvrdím, že v Go není v tomto případě možné dosáhnout žádoucího výsledku, tvrdím, že gorutiny soft-RT aplikace nijak neusnadňují, naopak jsou zdrojem problémů.
Já nevim, tak zkus třeba V language https://vlang.io/ nebo Zig https://ziglang.org/. Ale je to ve vývoji.
Zrovna tento díl byl vytvořen "na přání", protože se mi ozvali lidi, kteří by si Go chtěli vyzkoušet a zatím dělají právě v céčku (a jeden v C++). Namísto dlouhého čtení seriálu chtěli spíš porovnání syntaxe ve stylu: takto je to v C a takto to vypadá v Go.
Jinak mi (trošku OT, protože to asi nebyl dotaz na mě) nepřijde, že se jede jen Go a Python: bylo tady 39 dílů o Rustu, 9 článků o jazyce Julia, seriál o TCL (no to je hooodně old school), Java+JVM, Squeak, Scratch, Lua (to vyšlo i jako e-book), Forth, + lispovské jazyky.
Do jisté míry s vámi souhlasím, jenže realita je taková, že 90% čtenářů, co něco programují, nejspíš buď přímo používají Go a Python, nebo se aspoň zabývají aplikacemi, na které jsou tyto jazyky ideální. Kdyby byly články o numerických výpočtech, o práci s Metasploitem v Ruby, o Haskellu nebo třeba i Rustu, tak by si zase všichni stěžovali, že tohle pro ně nemá praktický význam...