Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web development, networking and server security. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

Go programski jezik


Syntax-K

Go programski jezik,
ili: zašto su svi jezici kao što je C bez veze, osim jednog.

07.06.2011

napisao: Jörg Walter <golang@syntax-k.de>


Uvod

Ovaj tekst zamišljen je kao pregled programskog jezika Go koga od 2007. razvijaju Robert Griesemer, Rob Pike i Ken Thompson u Google-u. U međuvremenu, jezgru tima pridružili su se: Ian Lance Taylor, Russ Cox i Andrew Gerrand. To je programski jezik poput C jezika, s nekim karakteristikama dinamičkih, skriptnih jezika i novim pristupima konkurentnosti i objektima orijentacije. Zamišljen je kao sistemski, programski jezik zbog čega ga, u ovom članku, poredim s drugim C jezicima, a ne sa skriptnim jezicima.

Tokom pisanja ovog pregleda, primetio sam da mnogi aspekti programskog jezika Go zaslužuju detaljnije objašnjenje pre nego što se izrekne konačna ocena o njima. Go je jednostavno drugačiji, ne možete suditi o njemu na osnovu klasične OO pozadine. Dakle, ovo je uvod u Go, isto koliko je i pregled. I za mene je Go novost. Pisanje ovog pregleda pomoglo mi je da shvatim šta je, u stvari, Go i šta radi, ali imajte na umu da sam još na svojoj prvoj Go aplikaciji. Kodirao sam na mnogim jezicima, pa ću uporediti Go s nekim njihovim aspektima.

Go je mlad jezik. Tek je ove godine proglašen stabilnim. Nadam se da ovim pregledom doprinosim diskusiji o njegovom budućem pravcu razvoja u jedan sjajan jezik. Tom cilju doprinosi i ukazivanje na nedostatke koji još uvek postoje.

Povika na C-oidne jezike

Uvek me zanimaju novi programski jezici. Obično koristim zgodne, dinamičke jezike kao što su JavaScript, Perl ili, u poslednje vreme, Python. Više volim čitljivost, lakoću održavanja i efikasnost programiranja, nego sirovu brzinu označenu reperima. Prevremena optimizacija obično nije vredna toga. Takođe, važna mi je i bezbednost, a programski jezici štite vas od prekoračenja bafera, ranjivosti formatiranja niza i svih drugih napada na niskom nivou (pod pretpostavkom da se vreme trajanja, samo po sebi, ne može iskoristiti).

Navedeni jezici imaju i jednu manu. Oni ne rade dobro u različitim razmerama, a moj rad obuhvata sve, od 8-bitnih mikrokontrolera, preko ugrađenih ARM sistema do pametnih telefona i klasičnih računarskih aplikacija. Obično za njih koristim C(+ +), ali, u tom slučaju, trpi ekspresivnost. Nema zgodnih operacija s nizovima, ali zato ima nezgrapnih regularnih izraza kojima su potrebne spoljne biblioteke, uputstava za upravljanje memorijom i svih bezbednosnih košmara nastalih tokom proteklih 40 godina. Ali, ono što ti jezici dobro rade brže je i memorijski efikasnije od svega što ste ikad imali.

Dakle, na niskom nivou jezičkog prostora ima fundamentalnih nedostataka. Ono što mi koristimo za pisanje alata niskog nivoa i operativnih sistema, staro je već desetinama godina i više ne može da odgovori na izazove modernih sistemskih okruženja. Ovde hoću da pokažem zašto. Ovaj pregled pokriva samo C jezike na zalasku pošto su ljudi navikli na njih, ali možete lako da dodate i stavke u vezi s drugim jezicima kao što su: Pascal, Modula, Oberon, Smalltalk, Lisp i svim ostalim što se nalazi u središtu jednog računarskog sistema.

C

Volim C. Zaista. Lep je zbog svoje jednostavnosti. Osim ako ne uradite neku glupost kao što je pisanje složenog alata za grafički interfejs gde je C primarni API.

Jedina stvarno dobra karakteristika je kontrola o tome šta se dešava, gotovo kao u asembleru, što je prilično važno u određenim situacijama. Ako ne koristite optimizaciju, naravno. Tada zamršena semantika C-a uzvraća tako što, na primer, ne briše memoriju koja sadrži osetljive podatke ili menja raspored izjava preko sinhronizacije barijera. To se ne može izbeći. Ako imate pokazivače s aritmetikom na njima, potrebna vam je semantika koja nije toliko očigledna da bi vam optimizacija bila koliko-toliko uspešna.

Najveći nedostaci su: nizovi, upravljanje memorijom, skup varijabli... Pa, gotovo sve što se ekploatiše. I nezgodni su za upotrebu. Dakle, iako je C nešto najlakše što se trenutno može naći, nije pogodan za projekte sa više od 10k LOC.

C++

C++ predstavlja poboljšanja nekih C aspekata, ali i pogoršanja nekih drugih; a potpuno je beskoristan kad je reč o opširnosti sintakse. Oduvek je bio zavrtanj i to je očigledno. To je superiorna alternativa za klasični razvoj aplikacija; neki lepi, slabi i puni opcija GUI kompleti alata dobro koriste njegove kvalitete.

Ali, kad pokušate da primenite savremenu gipkost dinamičkih jezika (koja podrazumeva lambda funkcije, smanjenje mapa, nezavisnost tipova), obično reagujete na sledeći način: “Hej super, C++ može i to!” Samo treba da uradite

dynamic_cast<MyData*>(funky_iterator<MyData &const*>(foo::iterator_type<MyData>(obj))

Da. Kako da ne.

Nemojte me pogrešno shvatiti, ja volim šablone, ali savremeni C++ koji koristi STL podseća na klasični slučaj "ako imate samo čekić, onda vam sve izgleda kao ekser". GCC je morao da sprovede posebna dijagnostička pojednostavljenja samo da biste saznali kako je poruka da se u 5. liniji nalazi greška, jednostavan propust u vezi s tačnošću konstante kad se koristi std::string metod. Još gore, mogu biti pakleno spori. Jeste li ikad čekali da se Boost kompajlira? Dobra ideja, loša realizacija.

Objective C

Sad se osećam pomalo kao jeretik. Ne bi trebalo da vređam ništa što potiče od NeXT-a. Ipak, ne mogu da se obuzdam - čini mi se da princip zavrtnja funkcioniše i kad je u pitanju Objective C. Nije ni izbliza tako besmisleno opširan kao C++, ali njegov nosač sintakse izgleda kao ulazak u paralelni svet C-a, jedino tako se ne narušava sveta C sintaksa.

Ovde ne dobijate pisanje impresivnih šablona kao što što je slučaj u C++ (ovo može biti i prednost ^^), a upravljanje memorijom još uvek je pomalo manualno. U C++ bar dobijate besplatne pokazivače referenci (ako slučajno nađete jednu ispravnu sintaksu šablona među hiljadama netačnih).

Objective C zaobilazi ovaj problem tako što zvanično nudi opcioni GC. Čekajte, GC je oduvek bio izborni za C-oide. Koliko godina već postoji boehm-gc? Memorijski bazeni su standardni, što je korisno nužno zlo za mnoge situacije, ali ipak nužno zlo.

Java

Niste, valjda, stvarno pomislili da bih, u svojoj povici na C-oidne jezike, zaboravio Java jezik, zar ne? Java gotovo predstavlja rešenje. Gotovo, kad ne bi bilo realnosti.

Dobili smo nezavisnost binarne platforme, detaljnu specifikaciju jezika s različitim primenama i bez značajnih zamki, klasičan OO, skupljanje smeća, neke veoma dinamične karakteristike, u poslednje vreme čak i generičke, zatim zabranu potrošnje memorije i sporo vreme za pokretanje.

Nema stvarne potrebe za tim. Napredni JIT kompajleri (u teoriji) mogu optimizovati bolje nego što bi bilo koji statički kompajler ikad mogao, čak i ako ide ispred svog vremena. GCJ kompajlira do nivoa koda mašine, ako vi to želite. VM je pogodna za kompletnu hardversku implementaciju. Ali, JDK izaziva preopterećenje, a mnogi savremeni Java projekti postaju nepotrebno kompleksni.

Sada možete da pišete veoma udobno u modernom Java jeziku. Web servisi nude neke zaista lepe apstrakcije. Sve dok ne pogledate ispod haube i ne otkrijte mašinu koju je napravio Rube Goldberg. Svaki sloj izgrađen je na omiljenom prošlogodišnjem sloju apstrakcije. Ne možete ugroziti kompatibilnost s prethodnim, zar ne?

Pogledajte svoj prosečni lib direktorijum web aplikacije. Ne bih se iznenadio da tamo nađete stotinu JAR datoteka samo za jednostavnu pretragu baze podataka ili sajt za kupovinu koji bi čak i PHP uradio kao 10k LOC. Ako ste avanturista, pokušajte da ga sami izgradite. Čeka vas lud provod! Postavljanje Linux sistema od nule, bez uputstva korak-po-korak, je lakše. Verujte mi, uradio sam i jedno i drugo. Pobrinite se da naučite napamet slova u rečima "pakao zavisnosti" s leva na desno i s desna na levo, pre nego što počnete.

I sve je to umotano u preopširnu sintaksu i objektni model stare škole. U suštini, nema ničeg lošeg u tome, ali drugi mogu bolje. Umetnost je nešto sasvim drugo. Bacite pogled na Perl 6, koji se zaista trudi da pretoči rezultate modernog jezika dizajna u upotrebljiv (u određenom smislu te reči) jezik. A te prve karakteristike koje su se našle u proizvodnji još uvek su decenijama stare! Java nije ni blizu ovome, osim, možda, kad je reč o generici.

C#

Umalo da zaboravim ovo. U stvari, i jesam zaboravio, samo me je povratna informacija podsetila. Iskreno, jedva poznajem C#. Kao jezik, izgleda lepo, kao velika evolucija u odnosu na C i C++. Izbegavam ga zbog toga što nije besplatan. Da, postoji Mono, ali ne bih voleo da zasnivam svoj rad na jeziku koji je tu zbog dobronamerne dozvole Microsoft-a i koji bi se svakog časa mogao pretvoriti u probnu tužbu. Svi znamo kakve trikove kompanija (zapravo, svaka velika kompanija) ima u rukavu.

Ne vidim svrhu pisanja koda koji nije na ukrštenoj platformi. Pošto je Mono previše preteći, držim se podalje od njega. Osim toga, CLR tek treba da izgradi svoju reputaciju, dok su prednosti i mane Java virtuelne mašine dobro poznati. Možda ću jednog dana pisati C# kod, ali taj dan neće biti uskoro.

Uz nedostatak otvorenog ekosistema jezičkih alata i alternativnih i/ili implementacija posebnih namena, jednostavno nije sposoban da bude sistemski programski jezik. To je samo još jedan trik kompanije.

A da, i činjenica da kompanija želi da zaradi na razvoju samog jezika nije put ka zdravom razvoju. Korporativni interesi jednog dana će usmeriti izbore loše za kvalitet jezika. Postoji konstantan pritisak za poboljšanje, inače ništa ne mogu prodati. Nasuprot tome, pogledajte TeX, koji je manje-više isti već duže od 30 godina, a slobodan je od bagova koliko jedan softver može biti. Ne možete ih stvarno porediti, ali neka vam posluži kao pokazatelj gde se spektar završava, a C# je na pogrešnom kraju.

JavaScript

Ne zvuči kao da JavaScript pripada ovde jer je potpuno dinamičan programski jezik. Predstavlja jedan od najrasprostranjenijih programskih jezika. Međutim, i on je C-oid. Što je još važnije, JS ovih dana usavršavaju napredne, optimizovane JIT kompajlere, pa se performanse mogu svrstati u isti koš s performansama pomenutih jezika.

Dakle, šta suštinski nije u redu s JavaScript-om? Ne mnogo toga. Samo što nije pogodan za male sisteme. To je veliki jezik s ugrađenim aplikacijama, zgodan za pisanje mrežnih usluga ali njegov dizajn ne pruža mogućnost interakcije sa spoljašnjim svetom. Hosting aplikacija definiše sve API interakcije na način koji je definisan implementacijom tako da, po definiciji, ne može biti sistemski hosting jezik.

Štaviše, JIT i uslovi rada zahtevaju da mogućnosti ugradnje budu ograničeni. Ako posedujete Palm Pre, već koristite JS kao ugrađeni jezik, i to je veoma zgodno. Samo, 500MHz/256MB sistem nalazi se na niskom stupnju onoga što se smatra korisnim. Možda je uređaj s najnižom specifikacijom koji koristi JS (ili, bolje rečeno, ECMAScript) kao svoj glavni sistemski jezik, Chumby, koji pušta Adobe Flash Lite filmove na 450MHz/64MB. Nije baš univerzalan jezik.

Spisak želja

Dragi Deda Mraze, svi jezici za niske nivoe su bez veze. Za Božić bih želeo programski jezik koji ima sledeće karakteristike (sa primerima iz poznatih jezika). Važnost ovih karakteristika nema veze sa redosledom nabrajanja:

Opšti principi dizajna

1. Ekspresivnost
Želim jezik koji je na dovoljno visokom nivou da njime mogu izraziti svoje ideje i algoritme, a ne onaj koji mi traći vreme i prostor na ekranu s dosadnim zadacima ili obrascima koji se 80% sastoje od opštenamenskih kodova. Važniji elementi ekspresivnosti odvojeno su navedeni. Dobar test je pisanje parsera. Ako krajnji kod ima dosta sličnosti sa konstrukcijama koje raščlanjujete, to je pravi smer. (Primer: Perl 6 gramatika)
2. Jednostavnost
Želim jezik koji je elegantno jednostavan. Samo nekoliko koncepata treba da izraze sve mogućnosti. Pravilnost je ključni aspekt. Jednostavnost takođe doprinosi lakoći učenja jezika. Ponovna upotreba sintaksičkih konstrukcija za slične svrhe i kontrola tih konstrukcija koju sprovodi korisnički interfejs doprinose vrednosti jezika. Takođe, ne treba mučiti korisnike komplikovanim strukturama. Nema ničeg lošeg u ponuđenim klasama, testiranju jedinica ili komentarima dokumenata, ali neka budu van vidokruga ako ih korisnik ne želi. U idealnom slučaju, neka budu kao DWIM.
3. Jednaka prava
Ako je ugrađeni asocijativni niz algoritama neefikasan za moj konkretan skup podataka, želim da mi se omogući da kreiram alternativnu implementaciju koja se koristi isto kao i ugrađena. Jezik ne treba da bude privilegovan. Shodno tome, trebalo bi da operateri mogu da se preopterete. Oh, kakvu magiju sam napravio u Python-u... Takođe, ugrađeni tipovi podataka moraju biti upotrebljivi u objektima sintakse jezika. Sve ovo ne treba da bude dinamično, većina ovoga može se oceniti kao sintaksički zaslađivač. (Primer: Perl-ov prototip subs, Python-ov operater preopterećenja)
4. Meta-programiranje
Meta-programiranje ima dva aspekta. Jedan od njih je šablon ili generika; previše korisna da bi se izostavila. Čak je i C imao neke zle pokušaje imitiranja: Preprocesor. Svakome je to potrebno. Napredniji aspekt je izvršni kod koji u vreme kompajliranja generiše kod, kao što su Lisp-ovi macros-i ili Perl-ovi izvorni filteri. Ako zahvaljujući tome mogu da se stvore nove jezičke konstrukcije ili specifični jezik za određeni domen, to donosi bonus poene.
5. Efikasnost i predvidljivost
Ako jezik ima za cilj sistemsko programiranje, onda mora biti efikasan, a složenost predvidljiva. Moram intuitivno proceniti u kom redu veličine vremena i memorijskim zahtevima leži određena operacija. Osnovne jezičke funkcije moraju biti dobro optimizovane. Biblioteka može da ponudi konstrukcije na visokom nivou koje efikasnije kodiraju u kraćem vremenskom roku, ali im je vreme izvršavanja operacija slabije. Objektni sistem ne mora da zahteva skupu podršku (ni u pogledu vremena, niti memorije), a statičke optimizacije treba omogućiti.

U idealnom slučaju, trebalo bi omogućiti korisnu kontrolu aplikacija u ​​nekoliko KiB koda i nekih stotinak bajtova memorije. Naravno, efikasnost i karakteristike najčešće se potiru, pa bih voleo da mi jezik pruži priliku da sam odlučim.

6. Upotrebljivost
Na kraju krajeva, jezik mora biti upotrebljiv. Svi ti ideali na stranu, pre svega mora da rešava stvarne probleme. Malo pragmatizma ne škodi. Jezik treba da bude, po efikasnosti, blizak drugim jezicima, tako da o njemu možete razmišljati u smislu upotrebljivosti. Ako drastično odstupate od toga, morate imati veoma dobar razlog. Cenite princip: bez iznenađenja!
7. Biblioteka i skladište modula
Hoću sve sitnice na koje sam navikao u okviru standardne ili ugrađene biblioteke, ili njenih delova u programskim jezicima. Skladište s javnim paketima ili, možda bolje, prenosni menadžer paketa. Tipični paketi uključuju internet protokole, raščlanjivanje zajedničke sintakse, GUI, crypto, zajedničke matematičke algoritme, obradu podataka itd. (Primer: Perl 5 CPAN)

Specifične karakteristike

8. Strukture podataka
Želim svoje hash-eve! Jezik bez asocijativnih nizova, kao i integrisanog tipa podataka je šala. OO (ili neki drugi praktičan metod zaključavanja) je, očigledno, obavezan. Logički tip je lep, ali još je važnije razumno tumačenje bilo kog tipa podataka u logičkom kontekstu. Bonus poeni dobijaju se i za napredne strukture podataka u standardnoj biblioteci, kao i za različita stabla, liste, skupove itd. Ako imate skip listu, na pravom ste putu.

I neka nizovi budu poput OO, tj. iste operacije (recimo, len()) trebalo bi da rade na nizu promenljivih ili na objektu koji podražava niz. Bonus se dobija ako svi primitivni tipovi podataka dele istu OO sintaksu poput ostalih objekata. Ipak, nema potrebe da bude kao Ruby. Neka to bude sintaksički zaslađivač. (Primer: Python i njegova standardna biblioteka)

9. Kontrolne strukture
Zvuči očigledno, ali pristojne konstrukcije petlje omogućavaju izlaz iz višestrukih isprepletenih nivoa odjednom. Eliminišite goto, stvarno. Samo da se setim kad sam ga poslednji put koristio... Ok, priznajem, bilo je to prošle nedelje. Prikazivao sam retro programiranje na mašini Commodore C64 u Muzeju kompjutera u Oldenburgu. To se ne računa. Dakle obrišite goto, ali dajte mi foreach. Ne treba mi mnogo pored toga. Možda neki izuzeci, ali nemojte za svaki ekser koristiti isti čekić. Nikad nisam koristio JavaScript sa izjavom. Iako mi se ta ideja dopada, pretpostavljam da se i ovde može primeniti pravilo: "manje je više". (Primer: svi programski jezici dobri su u tome)

Zapravo, ne postoji ništa što već negde nisam video. U poslednje vreme naišao sam na mnogobrojne petlje čiji se ulazi, uslovi za testiranje i izlazi ne odvijaju jedan pored drugog. Dakle, ako postoji način da se izrazi petlja koja počinje slobodno izabranom tačkom u sredini, bilo bi to strašno kul! U suprotnom, moraćete da duplirate deo petlje. Nešto kao Duff-ov uređaj, samo ne za optimizaciju, već za kod koji neće biti preveliki.

10. Sintaksa izraza
Mnogi ljudi ga izbegavaju, ali ?: trinarni operator je dobra ideja ako se pravilno koristi. Pyton omogućava opciju foo if bar else baz, koja je malo opširnija, ali još uvek u redu. Najdinamičniji jezici, međutim, ljuljaju se između svojih logičkih operatora AND i OR, ne samo procenjujući true i false, već i stvarnu vrednost onoga što se smatra da je true. Zamislite vrednost dodeljivanja: value = cmdline_option || "default" koje, međutim, zahteva pristojno logičko tumačenje svih tipova podataka.
11. Funkcionalni kvaliteti izraza
Da sam hteo da pišem Lisp, uradio bih to. Ne treba mi potpuno funkcionalan programski jezik. Ali, ništa bolje od dobre map(). Zaključci i anonimne funkcije (lambda izrazi) su ubice funkcija. Verovatno bi u "previše kompleksnoj" zoni bili hiper-operateri (kako ih Perl 6 naziva), kao any() i all() (kako ih Python naziva), ali oni mnogo znače i obezbeđuju priliku za implicitnu paralelizaciju. Dobro došli u novi milenijum ili, bar, u 90-te.
12. Objekti
Postoje različiti modeli objektne orijentacije, ali zahtevi svedeni na minumum obuhvataju enkapsulaciju i polimorfizam. Trebalo bi da postoji i neki način za formiranje klasa, ili višestruko nasleđe kao zamenu. Preopterećenje je važno ili mi, bar, dajte podrazumevane argumente. Kad smo već kod argumenata, navedeni argumenti su super.
13. Konkurentnost
Koristim ovaj izraz u najširem smislu te reči. Generatori i ko-rutine takođe se uklapaju ovde. Poenta je da više nema ugrađenih nizova, ali da višestruki kodovi istovremeno rade neometano. Ne moraju da izvršavaju operacije u isto vreme, ali trebalo bi da to bude moguće na nekoliko delova podataka postavljenih u isto vreme. Strukturiranje aplikacije oko obrade dešavanja trebalo bi da bude lako. Ako je to mehanizam za višestruke obrade - tim bolje! (Primer: Perl 5 POE, Python-ovi generatori)
14. Nizovi i Unicode
Ipak je 2011. godina i više nam ne treba ništa drugo, osim Unicode-a. Dakle, molim vas da svuda stavite bezbedan niz i Unicode, bez izuzetka. Muka mi je od implicitnih konverzija s pogrešnim dvostrukim kodiranjem i čime sve ne, ili od ručnih konverzija bez jezičke podrške. Uzgred, više volim UTF-8. Koga je briga za konstantno indeksiranje nizova? Koristite nizove karaktera za taj neuobičajeni slučaj. Za uobičajene slučajeve, koristite regex-e. Neka vam regex-i budu deo regularnog API niza!
15. Interfejs niskog nivoa
U nekom trenutku, poželećete da se ručno poigrate nekim bitovima. Pogotovo kada se ciljaju mikrokontroleri ili ugrađena ARM jezgara, trebalo bi da postoji način da se spustite do golog metala. U idealnom slučaju, bilo bi moguće napisati jezgro OS-a na programskom jeziku bez ikakvog asemblera koda (osim koda koji pokreće i koji se ne može zameniti ni na koji drugi način i specifičan je za određenu platformu)

Zakoračite u Go

Pregled

Bio sam pomalo skeptičan kada sam čitao o novom programskom Google jeziku. Jednostavno sam ignorisao tu vest. Uostalom, novi veliki jezik samo što se nije pojavio. Neki uživaju poneseni entuzijazmom, a zatim se spuste na zemlju, neki ostaju u sferama nezainteresovanosti, ostali će biti spremni da ga javno koriste, sad ili za koju deceniju.

Nešto kasnije, ponovo sam nabasao na njega. Ovaj put sam malo bolje pogledao. Na prvi pogled, nešto mi je promaklo: jedan od pronalazača je Ken Thompson koga su proslavili Unix and Plan9, a indirektno je učestvovao i u stvaranju C programskog jezika. Dakle, ako je novi programski jezik dizajniran od strane nekoga ko je već služio u rovovima ere sistemskih datoteka, možda i bude nešto od tog jezika.

Dakle, šta tačno može da uradi Go, a što ne mogu da mi pruže Perl, Python i JavaScript? I šta može da uradi od onoga što su prethodni jezici mogli? Po čemu se razlikuje od svih neuspešnih jezika ili jezika čiji je uspeh ograničen? Hoće li i dalje biti tu za tridesetak godina? I, što je najvažnije: Da li odgovara mojim potrebama?

Prvi kontakt

Najvažniji aspekt Go jezika predstavlja ciljna grupa. Dizajniran je kao sistemski programski jezik, tako da cilja na niži nivo softvera, možda čak i na jezgro OS-a. Shodno tome, viši nivoi konstrukcije možda nedostaju jer su kompleksni i ne mapiraju dobro hardverska uputstva. Smešna strana toga je činjenica da je većina pogodnosti, zapravo tu.

Sledeće što naučite je da taj jezik vodi poreklo od C jezika, tako da pripremite svoje tastature na US raspored za lakši pristup. Ali, ako vidite neke primere izvornog koda, manje će vam ličiti na C-oide nego što očekujete. Ima manje zagrada, nema tačke i zareza i ima svega nekoliko deklaracija varijabli, a možda i manje. Bar na prvi pogled. Sintaksa je jasna, s primetno drugačijim ključnim rečima i kontrolnim strukturama, ali još je razumljiva.

Ključne razlike u odnosu na C

Za sve koji su navikli na C/C++, napravićemo malo poređenje:

Nema tačke i zareza!
Ne šalim se! U stvari, tačka i zarez postoje, ali ne koriste se često. Go funkcioniše kao JavaScript: postoji jednostavno pravilo koje čini da parser ubacuje tačku i zarez na krajevima redova. To pravilo zaista je jednostavno, tako da je lako replicirati ga u alatima za obradu izvora. Zato je malo čvršći nego JavaScript.
OTBS
Sledeća kategorija "čiste jeresi”: Go definiše kanonsko uvlačenje reda i priznaje samo jedan istiniti stil zagrada. RMS neće se obradovati tome. To ide dotle da snabdeva gofmt, alat za rutinsko menjanje izvora. Java programeri su navikli na to, samo su zaglavili sa nekoliko komatoznih aspekata (alineja dubina 2? SRSLI?). Formatiranje izvora u programskom jeziku Go može se rezimirati na sledeći način:
  • Uvlačenje s novim redovima (što korisniku omogućava da se igra opcijama uređivanja da bi dobio onoliko praznog prostora koliko mu treba)
  • Zagrade pripadaju istoj liniji kao i kontrolna izjava na koju se odnose
  • Neprekidne linije ne smeju se završiti zatvorenim zagradama ili identifikatorima, tj. operator ne može biti poslednji deo stare linije, niti prvi deo nove linije.
Treća tačka je posledica jednostavnih pravila o umetanju zareza. Voleo bih da postoji način da se to zaobiđe pošto više volim da kombinujem operator na početku nastavka linije da bih naglasio šta se tamo dešava, umesto da ga krijem među mnoštvom drugih stvari.

Osim toga, za većinu ovo je sasvim razumno. Drugi su to detaljnije objasnili. Poenta je u čitljivosti s manje vizuelne buke. Kao Python, samo mislim da Python ima premalo vizuelnih signala. Samo uvlačenje reda ponekad nije dovoljno jasno, pa moramo da zadržimo naša voljena pomagala.

Obavezne vitičaste zagrade
Kad smo kod zagrada, nema nijednog oblika petlje ni reči if slobodnog od zagrada. Iako sam veliki obožavalac navedenog, ipak mislim da ovo nije baš najsrećnije rešenje. Možda će se puristma svideti stil kodiranja. Na kraju krajeva, nije toliko ni važno. Kad su u pitanju kratke izjave, još uvek mogu da uradim
if cur < min { min = cur }
Manje zagrada
Jedan važan tehnički razlog za prethodnu tačku jeste činjenica da te kontrolne izjave više nemaju zagrade. Samo Perl6 pokušava da izuzme if iz vitičastih zagrada, a svi znamo kako su nekad bili komplikovani Perl parseri (i još uvek su, očigledno). Dakle, to je zapravo zamena obaveznih i neobaveznih elemenata. Budući da vam je u većini slučajeva potrebno neko pomagalo, to je sasvim razumno. Neobično je za čitanje, morate se navići na odsustvo tih vizuelnih elemenata za razdvajanje, ali, kad se naviknete na to, Go kod vam postaje mnogo lakši nego C kod.
Eksplicitno davanje naziva tipovima, funkcijama i varijablama
Za predstvaljanje toga, koristiću ključne reči type, func i var. Ovo je daleko jasnije, dobijete bolji “tok” za čitanje. Ipak, nastavite da čitate ako vas zanimaju tehnički podaci.
Implicitne deklaracije, automatsko kucanje
Promenljive su uvek statično otkucane, baš kao i u C-u. Ipak, mogu da izgledaju kao da nisu. Ako izostavite tip, biće preuzet iz zadatka. Možete čak i da potpuno izostavite deklaraciju pomoću novog proglasi-i-inicijalizuj operatora:
foo := Bar{1,2,3}
Ovako se deklariše promenljiva nazvana foo i dodeljuje joj se objekat tipa Bar uz pomoć sintakse inicijalizatora objekta. Ovo je potpuno isto kao i
var foo Bar = Bar{1,2,3}
Ovo ne predstavlja dinamičko kucanje jer ne dozvoljava promenu deklarisanog tipa varijable, ne dozvoljava vam da dva puta proglasite promenljive. Semantički, isto je kao i pre, samo mnogo lakše. Imate osećaj da je ad-hoc programski jezik, ali na raspolaganju su vam sve pogodnosti statičkog kucanja.
Deklaracije promenljivih idu unazad
U Go jeziku, vrsta promenljive i povratni tip funkcija slede naziv. U C-u, lako možete da se prevarite:
int* ptr_to_amount, amount; // a pointer and an integer
int* ptr1, ptr2; // uh-oh, this isn't what it seems to be
Go reorganizuje vrste koje sadrže pokazivač, pa sada specifikatori nizova mogu čitati mnogo bolje. Jedna deklaracija odnosi se isključivo na jednu vrstu promenljivih, pa se navedeni problem ne može pojaviti:
var ptr1, ptr2, ptr_to_amount *int
var amount int
Sve to ima još više smisla kad vam prethodna karakteristika omogućava da izostavite specifikaciju određene vrste.
Pokazivači bez aritmetike
Još uvek su pokazivači, ali sada služe kao obične reference vrednosti. Svi objekti su vrste vrednosti, tako da dodeljivanje kopira cele objekte. Pokazivači vam daju reference za semantiku podrazumevanu za Java-u. Ali, nema pokazivača aritmetike. Primorani ste da izrazite pristupe nizovima onakavim kakvi jesu, a time se eliminiše mnoštvo bezbednosnih problema. Da, gospodine, imamo kontrolu granica!

Dakle, pokazivači nisu više centralni deo algoritama. Jedini cilj im je da navedu referentne vrednosti u poređenju sa semantičkim vrednostima. Ovo je dodatno pojednostavljeno činjenicom da pokazivači nemaju poseban pristup za de-referenciranje. foo.Bar() radi s pokazivačima i vrednostima na sličan način.

Sakupljanje đubreta
Prethodna tačka imala bi mnogo više smisla da ste bezbedno prošli oko svakog pokazivača i da ste preuzeli adresu svake vrednosti, kao što ne možete da uradite u C i C++.

Ali možete nešto drugo: upravljanje memorijom vrši se pomoću sakupljača đubreta. Konačno! Korist od integrisanog skupljača đubreta u odnosu na boehm-gc je u tome što bezbedno možete predati pokazivač lokalnoj promenljivoj ili čak uzeti adresu privremene vrednosti i sve će to raditi! Jupi!

One koji nisu u toku s istraživanjima o skupljanju smeća možda će zanimati činjenica da GC nije samo bezbedniji za upotrebu jer izbegava bezbroj grešaka koristeći malloc/besplatno. Pristojan skupljač đubreta može biti brži od ručnog upravljanja memorijom tako što će odlagati knjigovodstvo dok god ima vremena i potpuno ga izbegavati tako što će ponovo koristiti neiskorišćene objekte. Neki od najnaprednijih GC-a kombinuju to s većom efikasnošću memorije i upotrebom keš memorije zbog manje fragmentacije. Ovo više nije C64.

Go trenutno ima prilično jednostavan GC, ali radi se na njegovom usavršavanju. U većini slučajeva GC je pobednik, ali ponekad ima i boljih rešenja. U kritičnim situacijama možete koristiti nizove prethodno raspoređenih objekata.

Nizovi promenljive veličine
Ovde nije reč o nizovima čija veličina se određuje u toku rada, a posle je statična. Reč je o onome za šta treba da koristite realloc(). Nizovi uvek imaju konstantnu veličinu, što predstavlja korak unazad u odnosu na GNU-prošireni C. Ali, u zamenu dobijate kolutove.

Kolutovi liče na nizove, ali u stvari samo odgovaraju pod-opsegu običnog niza konstantne veličine. Pošto imamo skupljač đubreta, kolutovi se mogu odnositi na anonimni niz. Tako dobijate prave nizove dinamičke veličine. Postoje ugrađene funkcije za promenu veličine koluta i zamene za osnovni niz ako je premali, tako da je pisanje klase vektora na vrhu potpuno nebitno.

Reflection
Go podržava Reflection, tj možete pogledati proizvoljne oblike i naći informacije o njihovoj vrsti, strukturi, metodama itd. Ovu mogućnost podržavaju Java i C++ RTTI, ali ne i C.
Konstante izmenjene veličine
Konstante mogu da se preprave, odnosno da im se promeni veličina. Numerička konstanta može da se koristi u bilo kom kontekstu gde važi ta vrsta broja i koristiće preciznost vrste podataka koja mu je dodeljena. Konstantni izrazi obračunavaju se potpunom preciznošću i tek tada odlaze na odredište. Ne postoje sufiksi stalne veličine kao u C-u.
Upravljanje greškama
Go nema izuzetaka. Čekajte, šalite li se? To prkosi svim opštim, prihvaćenim znanjima o bezbednom i stabilnom programiranju! Zar to nije veliki korak unazad?

Ispostavilo se da nije. Budite iskreni, kad ste koristili izuzetke da biste obavili finu proveru grešaka i upravljanje? Najčešće, to izgleda ovako:

try {
	openSomeFile();
	doSomeWorkOnTheData();
	yadda...
	yadda...
	yadda...
	closeItAgain();
} catch (IOException foo) {
	alert("Something failed, but there's not enough time to do proper error handling");
}
Ovo je opširnije, uvodi još jedan nivo uvlačenja zbog premale koristi, a ne leči uzrok - lenjost programera. Ako želite da upravljate greškama pojedinačno za svaki poziv, opširnost samo pogoršava stvari jer zaista umanjuje jasnoću koda.

Dakle, možemo i dalje raditi sa složenim protokom koda i vratiti se na staromodno upravljanje greškama na licu mesta. Povratne vrednosti godinama su žigosane, ali Go ima tu lepu, modernu funkciju višestrukih povratnih vrednosti. Zaboravite na mentalnu umrtvljenost koju nudi atoi(), sad imamo odgovarajuću signalizaciju kad dođe do odstupanja. Govorim onima koji se brinu. Oni koji se ne brinu, nisu ni trepnuli kad je Java pokušala da nametne upravljanje greškama.

Zatim, tu je panic. Rezervisana je za greške u stilu: "nije moguće nastaviti". Tu ubrajamo ozbiljne greške inicijalizacije, uslove koji vam ugrožavaju integritet podataka ili proračuna, tu vrstu problema. Nepopravljive greške, ukratko. Vreme pokretanja jezika takođe može izazvati paniku, na primer kad se prekorače granice niza.

Naravno, to nas vraća na problem čišćenja iskorišćenih resursa. Za to postoji defer izjava, i to je veoma lep način da se upravljanje greškom smesti tamo gde i pripada, pravo u središte problema:

handle, err := openSomeFile()
if err != nil { return nil, err }
defer closeSomeFile(handle)

return happilyDoWork()
defer je gotovo kao finalna klauza u Javi, ali liči na doterani poziv funkcije. Stara se za poziv closeSomeFile bez obzira na to kako se izlazi iz funkcije. Propratni efekat je to što možete preskočiti zatvaranje kad uspete. Manje dupliranja koda, koncizno i vidljivo upravljanje greškama. Dozvoljeno je više odlaganja (defer) ako se pravilno pozovu po LIFO redu.

Za slučajeve kad ne želite da nastavite posle panike, postoji recover. Zajedno, panic i recover mogu se (zlo)upotrebiti za ponovno kreiranje izuzetaka opšte namene. Pošto su zamračili tok programa, zvanična preporuka je da panika koja nije fatalna ne treba da pređe granice paketa. Nema idealnog rešenja za upravljanje greškama, tako da ćete dobiti dobru podršku za oba slučaja, a vi treba da izaberete manje komplikovanu varijantu za svoj zadatak.

Strukture kontrole
Postoji samo for za petlju i ponaša se kao foreach zahvaljujući ključnoj reči range. S obzirom na to da je while uvek poseban slučaj za for, i da je sintaksa lakša (vidi gore), za mene je to sasvim u redu. Što je još bolje: možete staviti oznake na svoje isprepletane petlje i izaći (break) iz više nivoa uz njihovu pomoć. Konačno!

Još uvek možete da se upucate u nogu koristeći goto. Pa dobro, ne možete baš jer je zlo jednostavno zabranjeno. Ali, oni koji vole malo da varaju, radi jednostavnosti, mogu to da urade.

Sve ovo dolazi iz malog broja dodataka. Ima tu i nekoliko bora, o kojima ću kasnije govoriti, ali kao celina predstavlja veliki napredak u odnosu C. Samo po sebi, to bi već bilo dovoljno za mnoge vesele noći pisanja proceduralnog koda bez objekata.

Ekstenzije

Prava snaga Go jezika potiče otuda što se ne može poklopiti sa jezicima kao što su C, C++ ili bilo kojim dosad pomenutim jezikom. Sledeće karakteristike čine Go blistavim:

Objekti na osnovu tipa protiv enkapsulacije
Nema klase. Vrste i metode su nezavisne jedna od druge. Možete da proglasite metod bilo kog tipa, a isto tako i bilo koju vrstu za novi tip, slično kao typedef u C jeziku. Razlika u odnosu na C ili C++ je takva da novoimenovana vrsta dobija svoj skup metoda, i to primitivne vrste (one koje se zasnivaju na njima), a mogu nositi i metode:
type Handle int64

func (this Handle) String() string {
	return "This is a handle object that cannot be represented as String."
}

var global Handle
U ovom primeru, sad može biti pozvan i global.String(). Rezultat toga je da dobijamo jednostavan objektni sistem bez virtuelnih metoda. Ima nulto vreme prekoračenja, predstavlja samo sintaksički zaslađivač.
Duck-Typing protiv polimorfizma
Deklaracije tipa ne mogu se koristiti da bi približile dva različita tipa. To su različiti tipovi i u strogo kucanom jeziku nije vam dozvoljeno da kreirate neku vrstu polimorfnog, generičkog tipa. Popularan primer iz gotovo svih jezika je konverzija vrednosti u niz. Handle type proglašava takve metode konvencionalnim u okviru Go jezika, ali ne pokazuje kako da se ponašate prema bilo kom tipu koji ima takav string metod.

C++ koristi nasleđe (verovatno s apstraktnim baznim klasama) i operator preopterećenja za to. toString iz Jave je deo njene klase korena i zato je nasleđen dok se ostale konvencije poziva izražavaju kroz interfejse.

Go koristi isključivo interfejse. Za razliku od Jave ne izjavljujete da određeni tip odgovara nekom interfejsu. Ako se to desi, automatski je upotrebljiv kao taj interfejs:

type Stringer interface {
	String() string
}
To je sve što nam je potrebno. Automatski, Handle objekti sada su, takođe, upotrebljivi kao Stringer objekti. Ako hoda kao patka, kvače kao patka i izgleda kao patka, onda je, za sve praktične namene, patka. A sada najbolji deo: Ovo funkcioniše dinamično. Deklaracija interfejsa ne treba da se uveze, čak ne mora ni da bude poznata programeru.

Kad god se tip koristi kao interfejs, dužina trajanja pravi tabelu funkcije pokazivača za taj interfejs preko svoje sposobnosti refleksije. Dakle, ovde imamo neke dodatke za vreme izvršavanja. Optimizovani su, pa su i kazne relativno male. Interfejs tabele se obračunavaju samo po jednom za svaki tip. Dodaci za dužinu trajanja mogu se izbeći ako se uključene vrste mogu odrediti na osnovu vremena sastavljanja. Brzina metoda treba da bude malo veća nego kod Apple-ovog Objective C dispatcher-a (što je već prilično dobro).

Ugrađivanje tipova protiv nasleđa
Tipovi služe kao neka vrsta klase, ali postoje bitne razlike jer nema hijerarhije nasleđivanja. U prethodnom primeru, Handle ne nasleđuje nikakve metode iz int64. Možete dobiti nešto slično nasleđu tako što ćete proglasiti struct tip koji ugrađuje osnovne tipove podataka u svoje telo: (primer je besramno ukraden iz "Effective Go")
type ReadWriter struct {
	*bufio.Reader
	*bufio.Writer
}
Ovaj tip ima sve metode koje imaju bufio.Reader i bufio.Writer. Konflikti se rešavaju na osnovu jednostavnog pravila. Ovo nije višestruko nasleđe! Obe vrste baza podataka postoje kao nezavisni objekti u okviru kompozitnog tipa, a svaki metod podtipa vidi isključivo svoj objekat. Na taj način, dobijate savršeno predvidljiivo ponašanje lišeno svih nevolja u vezi s klasičnim višestrukim nasleđivanjem. I bez svih dodataka -- manje-više sintaksičkih zaslađivača, zbog čega je kod ekspresivniji i sa manjim troškovima izvršavanja.

Ovo dobro funkcioniše i sa interfejsima. Kompozitni tip odgovara svim interfejsima kojima odgovara najmanje jedan konstitutivni tip. Naravno, to može dovesti do isprepletene kompozicije što ga čini vrstom nasledstva. Pravila koja rešavaju dvostruke reference metoda prilično su jednostavna, a ne-intuitivni slučajevi jednostavno su zabranjeni: Ako se dva ista metoda nađu na istom nivou preplitanja, došlo je do greške za vreme sastavljanja. Inače bi pobedio onaj s najnižim nivoom preplitanja. Kao rezultat toga, kompozitni tip može slobodno zameniti metode svojih konstituenata.

Kontrola vidljivosti
Primarna jedinica razvoja je paket. Jedna ili više datoteka implementira jedan paket, a vi dobijate kontrolu nad onim što je vidljivo sa spoljne strane paketa. Ne postoji složen sistem vidljivosti -- ili je vidljivo, ili nije. To je pod kontrolom tipografske konvencije: Javna imena počinju velikim slovom, privatna imena malim. Taj princip primenjuje se na sve nazive.

Ovo je sasvim pragmatično rešenje. Za razliku od tipskog sistema, koji je moćan barem koliko i konkurencija, Go u ovome drži srednju poziciju: većina programskih jezika uopšte ne brine o vidljivosti, ili se oslanja na dobrovoljne konvencije dok C-oidi stare škole imaju detaljne kontrole pristupačnosti. Ipak, čini se da je to dobro rešenje za objektni model Go-a. Pošto ne postoji klasično nasleđe i ugrađeni objekti ostaju potpuno zatvoreni, nema potrebe za specifikacijom zaštite pristupa. Ostaje da se vidi kako to funkcioniše u praksi.

Nema konstruktora
Objektni sistem nema posebne konstruktore. Postoji pojam nulte vrednosti, tj. nulom inicijalizovana vrednost svih oblasti vašeg tipa. Od vas se očekuje da napišete svoj kod tako da je vrednost “nula” značajna predstava važećeg "praznog" objekta. Ako to nije moguće, možete obezbediti funkcije paketa kao konstruktore.
Goroutines i kanali
Ovo je najneobičnija karakteristika za takve opšte namene programskog jezika. Goroutines mogu se videti kao izuzetno lagane niti. Go ih mapira kao združene pseudo-niti za razne zadatke, poput pth-a ili niti pravog operativnog sistema, prve sa niskim dodatnim zahtevima, druge sa očekivanim ponašanjem pravih niti koje ne blokiraju, tako da dobijamo najbolje od oba sveta.

Kanali su otkucani redovi poruka koje mogu da se smeste u pomoćnu memoriju ili da se izvuku iz nje. Stvarno jednostavno. S jedne strane unesete objekte, s druge strane ih izvadite. Većina onoga što biste uradili u trenutnom algoritmu više vam nije potrebno.

Go se zaista trudi da Goroutines postanu građani prvog reda koji mogu da formiraju jezgra mnogih algoritama. Segmentirane gomile održavaju nisku upotrebljivost niti i, osim ako ne koristite blokiranje sistemskih poziva, dobijate performanse u vrednosti pseudo-niti tj. malo više od običnog poziva funkcije.

U kombinaciji s činjenicom da Go ima mogućnost pravog zaključavanja, Goroutines mogu se koristiti za mnoge stvari koje ne predstavljaju trenutne algoritme. Njima se mogu oblikovati Python-ove funkcije generatora ili se može podesiti upravljač memorije sa listom slobodnih objekata. Pročitajte dokumentaciju na internetu; neverovatno je koliko je konkurencija svestrana i jeftina.

Uzgred, postavljanjem okruženja promenljive možete odrediti koliko jezgara procesora želite da Go koristi, tako da će Goroutines biti mapirane na nekoliko izvornih niti od samog početka (što je suprotno podrazumevanom da se ne počinje drugi niz dok ne dođe vreme da se pozove blokiranje sistema)

Regresija

Nijedan sistem nije savršen. I Go ima svojih mana. Evo spiska nedostataka koje sam, do sada, otkrio:

Binarna veličina/Zahtevi za izvršenje
Osnovni, binarni Go statički je povezan i ima oko 750k, ako je izgrađen bez simbola za otklanjanje grešaka. Otprilike je iste veličine kao sličan C program. Testirao sam ga uz pomoć primera Tree Comparison koji se može naći na Go Homepage, poredeći ga sa strukturno sličnom C implementacijom koju sam isprobao.

Gccgo može da sastavi dinamički povezane izvršioce, ali libc je na svakom sistemu i obično se ne smatra dodatnom zaradom, dok bi libgo bio u dodatnom paketu od 8MB package. Poređenja radi: libstdc++ je manji od 1MB, libc je manji od 2MB. Istini za volju, oni rade mnogo manji posao od Go standardne biblioteke. Ipak, u pitanju je velika razlika i dodatna zarada.

6g/8g, originalni Go kompajler proizvodi slične izvršioce, ali oni čak i ne zavise od libc-a, samostalni su. Ipak, nije moguće dinamičko povezivanje izvršavanja.

To je, takođe, briga malih sistema. Pored mene je drevni 16MB Pentium-100 laptop koji pokreće X i JWM desktop prilično uspešno i pušta moju muziku iz kolekcije. Čak ima i 5MB memorije za disk keš. Da li bi to bilo moguće sa sistemom koji je napisan Go programskim jezikom?

Nema jednakih prava
Jezik je privilegovan na nekoliko mesta. Na primer, specijalna funkcija make() obavlja ono što korisnički kod ne može da produži. Ovo nije tako loše kao što izgleda na prvi pogled, pošto možete napisati nešto što se ponaša skoro kao make(), samo nema šanse da se priključite u konstrukciju tog jezika. Isto važi i za neke druge pozive i ključne reči koje bi trebalo da budu proširive, kao range. Manje-više, primorani ste da koristite goroutines i kanale za proširenje opsega.

Nisam siguran da je ovo, u stvari, problem. Pod pretpostavkom da se mape, kolutovi, goroutines i kanali optimalno sprovode, ova ograničenja nemaju nikakav uticaj. Ne ometa čitljivost, ni jasnoću koda, ali se čini vam se nepravednim ako ste navikli da “podražavate” jezike kao što su Perl ili Python.

Nema preopterećenja
Preopterećenje je izvor mnogih semantičkih dvosmislenosti. To je dobar razlog da se izostavi. Ipak, operater preopterećenja je tako prokleto zgodan i čitljiv, da mi zaista nedostaje. Go nema automatske konverzije tipa, tako da situacija neće postati ni izbliza čupava kao u C++.

Kao primeri za šta bi preopterećenje moglo da se iskoristi, zamislite BigNum biblioteku, (numeričke) vektore, matrice ili čuvane tipove podataka ograničenog dometa. Kada se radi sa razmenom podataka ukrštene platforme, mogućnost da se semantika matematike zameni za posebnu vrstu podataka predstavljaće veliku pobedu. Mogli biste da imate 1s-komplementarni tip broja, ako se bavite datotekama drevnih mašina, na primer, i da se bavite aritmetikom koja tačno imitira ciljnu platformu umesto da se nadate kako se aktuelna platforma za semantiku neće razlikovati.

Ograničeno kucanje - Duck Typing
Nažalost Duck Typing nije kompletno. Zamislite interfejs poput ovog:
type Arithmetic interface {
	Add(other int) Arithmetic
}
Parametar funkcije i povratna vrednost za Add ograničiće automatsko kucanje. Objekat koji ima metod func (this MyObj) Add(other int) MyObj nije odgovarajući za Arithmetic. Postoji više primera kao što je ovaj. Za neke od njih nije lako odlučiti da li je bolje koristiti Duck Typing ili su sadašnja pravila bolja. Možete se uvaliti u nevolju koja na početku nije bila očigledna, pa ponovo imamo situaciju “možda je bolje da sve bude što jednostavnije", ali nisam potpuno uveren u to.

Russ Cox, jedan od autora programskog jezika Go, kaže:

To ne funkcioniše jer se raspored memorije za MyObj razlikuje od rasporeda memorije za aritmetiku. Drugi jezici muče se s tim čak i kad se rasporedi memorija poklapaju. Go jednostavno kaže - ne.
Valjda treba da objavimo func (this MyObj) Add(other int) Arithmetic umesto toga. To je kompromis koji nam obezbeđuje jednostavnost kompajlera i generisanog koda mašine.
Pokazivači protiv vrednosti
Nisam siguran da li sam zadovoljan tim poslom pokazivač/vrednost. Semantika jave gde svaka stvar označava semantiku mnogo je jednostavnija. Refererentna vrednost naspram sintakse u jeziku C++ prilično je lepa. Pozitivno je što dobijate više kontrole o rasporedu memorije i korišćenju strukture, posebno kad sadrže druge strukture, a ta je vrednost protiv semantike referenci eksplicitnija na lokacijama poziva funkcije što C++ čini nepredvidljivim.

Uzgred, mape i kolutovi jesu tipovi referenci. U početku sam se opterećivao njima, ali možete napraviti sopstvene objekte koji se slično ponašaju: strukture koje sadrže (privatne) pokazivače, što mape i kolutovi, manje-više, predstavljaju. Kad bi samo postojao neki način da se zakači za njihovu [...] sintaksu...

Boolean Context
Boolean context nudi mnoge mogućnosti za uprošćavanje koda. Nažalost, čak i pokazivači moraju da se uporede s nil, iako je !pointer potpuno očigledan. Čak i više od toga, jer nema aritmetike pokazivača. Pogledajte stavku broj 10 u mojoj listi želja. Ovako bi sve imalo mnogo više smisla, a kod bi bio kraći i jezgovitiji.

Pošto već imamo nultu vrednost za svaki tip, nema razloga produžavati to i pretvarati ga u boolean context.

Stvari koje nedostaju

Neke stvari nisu stale u Go i zaista mi nedostaju. Nadam se da će zajednica naći način da ih doda, isto onako lagano kakvo je sve u ovom jeziku. Voleo bih da vidim još neke, malo manje značajne, karakteristike. Neke stvari su samo moja pusta želja, ali zaista bih voleo jedno -- meta-programiranje.

Ne govorim o generici, niti o šablonima. Interfejsi ih mogu zameniti, manje ili više uspešno. Zbog navedenih ograničenja Duck Typing je trenutno nekompletna zamena.

Govorim o nečemu što je prava stvar - varijanti kod-koji-generiše-kod. Zamislite mogućnost da implementirate jezike specifične za različite domene. Ako ja radim na SQL-u, onda će SQL biti deo izvornog koda bez obzira na sve. SQL paket bi mogao ponuditi integrisano rešenje za pisanje SQL-a, vreme sastavljanja, proveru sintakse i tipa. Možda će povećati vreme kompajliranja, ali radije bih izabrao statičku proveru svakog svog koda, nego da u vreme rada otkrijem sintaksičku grešku u SQL-u (plus utrošeno vreme za svaki poziv umesto samo za jedan).

Takva olakšica doprinela bi evoluciji jezika, a eksperimentalne karakteristike lako bi se mogle primeniti i testirati pre nego što se razmotri njihovo ubacivanje u jezičko jezgro. Uz dobro dizajniranu implementaciju, naravno. Niko ne želi da se ponovi nered kao što je bio u C/C++.

Preopterećenje operator/metod imao bi smisla, pa možete i to uračunati. Go bi time dobio mnogo na ekspresivnosti. Python model sa posebno imenovanim metodama ima pristojnu semantiku i rešava probleme iz stvarnog sveta, na primer.

Nažalost, o ovome je već mnogo puta bilo reči, a za novajliju poput mene, to je jednostavno previše diskusije i premalo rezultata da bih video kuda sve to ide. Da citiram jedan post:

> Povratna informacija više je nego dobro došla.

Pretražite listu za ove teme i naći ćete hiljade mejlova za svaku.

To je uznemirujuće. Ako su neke teme toliko puta pretresane, zašto još ništa nije zvanično dokumentovano? Argumenti poput ovog obeshrabruju ljude koji bi mogli da daju svoj doprinos. Istovremeno, oni koji redovno odgovaraju na pitanja, počinju da se zamaraju.

U najboljem slučaju, trebalo bi da to bude proces zajednice (kao što imaju Python, Java, Perl6, XMPP) koji prati predloge, navodi uslove za ispunjenje datog predloga i rezimira trenutno stanje razvoja. Zatim, ideje mogu da sazrevaju, mogu da se odbiju razumljivim argumentima, mogu se zameniti još boljim idejama i, konačno, mogu dospeti u jezik bez ugrožavanja ciljeva dizajnera. Iz dobro dokumentovanih odbijanja, potencijalni saradnici mogu naučiti šta da izbegnu, šta ne treba da očekuju i šta da urade umesto toga.

Ovo ne mora da bude demokratski proces. Podjednaki broj uspeha zasnovan je na zajedničkom i na diktatorskom pristupu upravljanju projektom. Isti je slučaj i sa neuspesima. Najvažnije je da postoji proces koji je transparentan i razumljiv.

Nemojte steći pogrešan utisak o onome što sam rekao. Zajednica nije tvrdoglava i arogantna. Zajednica sluša. Zapravo, više liči na opis jednogh člana koji je objavio:

Kad dodate neku funkciju, problem je u tome što je ne možete povući.

Potpuno se slažem s tim. Hoću meta-programiranje jer je neverovatno zgodno, a potpuno usklađeno s onim što Go može. Za PHP možemo da ostavimo gluposti.

Otvorena pitanja

Ovi bitovi mi trenutno nisu jasni. Kad otkrijem odgovore na ova pitanja, ažuriraću ovaj pregled. Neka od njih su u velikoj meri hipotetična, dok druga nose direktan interes za jezik. Prosudite sami. Tekst u kurzivu je moj rezime odgovora koje sam dobio, a ne citati, osim ako ih nisam tako naveo.

  • Da li umetanje funkcioniše? Kako bi funkcionisalo umetanje među paketima?

    Ne još, ali nalazi se na listi stvari koje će raditi kompajler. Lako je omogućiti umetanje između paketa, tako da je zbrka izazvana kodom u fajlovima zaglavlja, u C++, konačno sređena.

    Pretpostavljam da se to odnosi na 6g/8g. Ne znam da li će gccgo takođe dobiti umetanje među paketima.
  • Da li bi bilo moguće osposobiti Go da bude 8-bitni? C se spušta do 8-bitnih mikrokontrolera. Koji je hardverski minimum potreban (verovatno ograničen) da bi Go mogao da radi?

    Ne sa kompajlerima koje trenutno ima. 32-bitni je minimum.

    Nadam se da će jednog dana neko pokušati da prenese Go na manje sposobne mašine. Možda će biti potrebno neko vreme, ali ni C64 nije dobio C preko noći ;)
  • Mogu li Go datoteke objekata da se učitavaju za vreme rada? Da li se vrste u ovim fajlovima integrišu u hosting aplikaciju?

    Ne još, ali nema razloga zašto se to ne bi moglo sprovesti. Možda je to već i u planu.

  • Kakva su ograničenja optimizatora? Ako uzmemo u obzir gccgo, da li koristi sličan nivo optimizacije kao prilikom sastavljanja jezika C++, ili su neki značajni koraci ostali bez podrške?

    Za 6g/8g, optimizator još uvek ima nekoliko propusta koji su standardni problemi u kompjuterskoj tehnologiji, ali na njima se radi. Još nema odgovora za gccgo.

    To je zapravo dobro. Kompajleri još uvek nisu vrhunski, ali Go lepo radi. Go je dizajniran da lako pravi statičke optimizacije zbog čega su neke karakteristike namerno ograničene. Izgleda da će se srediti kako treba.
  • Da li bi bilo moguće otkriti prekoračenja celog broja, još jedan veliki propust bezbednosti? Pretpostavljam da bi bilo lako implementirati tip čuvanih podataka sa operatorom preopterećenja. Možda bi ipak vredelo imati to u samom jezgru jezika, pod uslovom da je moguća implementacija sa pristojnim performansama. C# to već radi.

    Trenutno ne. Go eksplicitno definiše aritmetiku celih brojeva kao razlomak. C je smatra nedefinisanom, pa C kompajler može da uradi čitav niz provera ako želi, ali Go kompajler ne može.

    Što znači da bi jezičke specifikacije morale da se menjaju neki način da bi to postalo izvodljivo. Bilo bi vredno imati čuvani ceo broj kao podrazumevanu vrednost, a razlomak kao opciju za matematičke trikove.
  • Koliko je visoko prekoračenje memorije iznad interfejsa? Iznad strukture? Ili nizova?

    U suštini, onoliko optimalno koliko je to moguće. Postoji tip informacije za svaku vrstu, a vrednosti interfejsa su do 2 pokazivača, ali ako nema toga, nema ni prekoračenja.

  • Koliko je CPU vreme otpremanja metoda interfejsa? Ili vreme potrebno da se kreiraju goroutines? Ili da se rasporede?

    Metod raspoređivanja interfejsa je kao virtuelna funkcija u C++. Kreiranje goroutine samo zauzima malo memorije. Raspoređivanje se vrši pomoću jednostavnog round-robin rasporeda. Dakle, prilično je brzo, ali možda neće funkcionisati na nekim radnim opterećenjima.

  • Da li je moguće dodati metode tipovima koji nisu deklarisani u određenom paketu? Možda čak i do int64?

    Ne, i kao posledica toga, ne. Samo se paket koji deklariše tip može dodati. Dakle, nema mešanja. To je namerno napravljeno da bi bilo jasno šta kod radi. Inače bi zavisio od paketa uvezenog tokom trajanja programa, a kad jednom dođe do dinamičkog opterećenja, neodređenost počinje da vlada!

  • Da li je moguće dodati metode interfejsima tj. metod koji ima interfejs kao prijemnik zbog čega je isti za sve objekte koji primenjuju taj interfejs?

    Ne, iz sličnog razloga. Umesto toga, ispišite funkcije paketa koje funkcionišu na određenim tipovima. Ako su nazivi funkcije pravilno razmaknuti, nisu zli.

  • Kako se raspoređuju goroutines: Može li goroutine iscrpeti sve ostale goroutines i glavni program ako se kreće u beskrajnoj petlji ili postoji neka mera predostrožnosti kao zaštita?

    Nema zaštite. Goroutines ne zamenjuju nizove za konkurentnost niske latencije/paralelno procesiranje.

    S jedne strane, to je žalosno. S druge strane, zajedničko raspoređivanje je mnogo jednostavnije i ima bolji protok. Samo pogledajte Linux jezgro i vidite koliko iteracija je prošao njegov planer da bi postigao optimalne performanse. Teško je postići nisku latenciju, dodatke, skalabilnost, a da sve to bude bez iscrpljivanja, a u tom slučaju replicirate pogodnosti operativnog sistema. Možda je pametnije živeti s tim i dodati neki način za umnožavanje goroutine u sopstvenom nizu.
  • Šta je sa skupljačem đubreta? Koliko dobro rukuje velikim brojevima ili malim objektima?

    Što se memorije tiče, efikasan je gotovo kao malloc(). Brzina može biti neusklađena ako se na mnoge objekte referiše putem pokazivača i ako se u njih ulazi blizu kraja (tj. u kolutove s tom osobinom).

    Imajte na umu da je ovo samo trenutno rešenje za skupljač đubreta. Doći će zamena. Ništa ga ne sprečava da postane proširiv, samo što trenutno još nije. Prioritet je jezik koji treba da postane što optimalniji.

Povratne informacije

Dobio sam određene povratne informacije, pa sam dodao i ovaj odeljak. Ovde se pominju zanimljive primedbe koje se nisu uklopile u idejni tok ovog rada. Primedbe koje pojašnjavaju moj originalni tekst ili zbog kojih sam pomislio: “Pa naravno, kako je to moglo da mi promakne?!” nalaze se u prethodnim redovima.

Ternarni operatori

Jedan čitalac detaljno je prikazao istoriju Python-ovog ternarnog operatora a if foo else b. S obzirom na to da je Python već visoko na skali čitljivosti, neko se može zapitati zašto su dodali ovaj konstrukt koji se obično posmatra s neodobravanjem.

Izgleda da je Python neko vreme bio bez njega i ljudi su srećno živeli iako su na raspolaganju imali samo booleans: some_value or "default-value". Sve dok neko nije došao na ideju da uradi condition_to_test and value_if_true or value_if_false. Od tada sve je krenulo nizbrdo. To rešenje je imalo mana, pa su smislili neke poštapalice za njega. Svaka je bila ružnija od prethodne sve dok, konačno, Python nije dobio ternarni uslovni operator.

Šta sad to znači za Go? Ako ne možete da ih pobedite, prihvatite ih. Molim vas.

D

Nisam hteo da pričao o D-u iz dobrog razloga. Nije mi nedostajao, ali neki nisu otkrili moj pregled 6-word summary of my opinion about D. Bolje reći, nemam iskustva s njim. Nisam pisao o D-u jer nisam pisao u D-u. A sada, na zahtev čitalaca, moje mišljenje o D-u:

Kad sam prvi put video D (na heise.de news, možete naći odabrane članke na engleskom na The H), bio sam prilično impresioniran. Bio je to jezik koji se zaista trudio da reši nedostatke koje imaju C/C++/Java. Ali, pošto sam neko vreme površno pregledao dokumenta, izgubio sam interesovanje.

Zašto? Jednostavno, jer nije našao lek za prave boljke. Da, on nudi sve što je u jednom jeziku koji mora biti kopiran u C++ zajedno sa šablonima i koji je u Java jeziku napravio još jedan sloj apstrakcije, ali to je to. Već sam to video. Možda je manje efikasan u tim jezicima, ali oni su se odlično poklapali s D jezikom.

Iako mi je zanimljiv pristup “sve karakteristike u jednom univerzalnom jeziku”, ne vidim gde se to uklapa u moj univerzum. Ne pokušava da bude jezgrovit. Ne nudi nikakvu novu koncepciju koju vredi istražiti. Jednostavno, ne bavi se mojim potrebama. Zašto bih se, onda, prebacio na taj jezik i navukao na sebe nevolju da nemam kod koji mogu deliti s drugima, koji mogu da objavim kao otvoreni izvor i koji lako mogu dati javnosti na upotrebu, koji lako čini interfejs sa kodovima drugih ljudi?

Da sam zagrizao veliki projekat koji treba da objavim na sva zvona, izabrao bih Java ili C++ jezike, u zavisnosti od toga koji jezik najviše odgovara zahtevima projekta, posebno stranom kodu. D se jednostavno neće uklopiti tu. Ako je projekat mali, kvaliteti D-a neće biti dovoljni za mene. Nemam nikakav motiv da bih prešao na taj jezik. Pored toga, ne dopada mi se pristup da sve stavljam u jezik. To je korporativni jezik, ali takvi su i Java i C#.

Znate li šta je smešno? D je razlog zbog koga sam isprva odbacio Go. Čitao sam o njemu na istom mestu i pomislio: "Znači, još jedan ovakav...” Ignorisao sam vesti. Tek kad sam još dva puta pročitao o njemu, neka činjanica (koje se više uopšte ne sećam), zapalila je moju radoznlost i evo me, dve nedelje kasnije, pišem ovaj pregled.

Go je zaista drugačiji. Daje vam razlog da se prebacite. Odgovara mojim potrebama i daje mi nešto što nijedan jezik za opštu svrhu nema. Ne, Haskell, Erlang itd. se ne računaju. Sviđaju mi se ti jezici, s naučne tačke gledišta, ali voleo bih da i dalje razumem svoj kod i kad sam umoran, a hteo bih da i ostali lako razumeju moj kod. Što je najvažnije, Go lako saobraća sa spoljnim svetom zahvaljujući gccgo-u i ja ću biti na dobitku ako ga koristim, čak i ako ostane relativno nepoznat jezik.

Ovaj članak na teh Internetz

Zahvaljujem internetu za sve diskusije koje nisam primetio, a koje je trebalo istaći. Bilo je mnogo spekulacija o različitim aspektima koji su mi bili zabavni. Nisi me razočarao. Ne verujem da ćeš ovo čitati, ali, za svaki slučaj, evo nekih odgovora na ono što nisam pokrio današnjim ažuriranjem:

Jedan vrlo važan podatak, koji je mnogima promakao, glasi da je programski jezik sredstvo. Jednom davno, bio sam duboko zaglibljen u Perl 5, učeći tajne crne magije. Znate li kako sam smogao snage da nastavim? Nije me na to naterala fascinantna lepota jezika (nije je bilo mnogo). Delimično i zbog toga što su me privukle meta-čarolije koje su zaintrigirale moje hakersko srce. Ali, pravi razlog je paket arhiva i ad-hoc mogućnost pisanja koda. To mi je omogućilo da rešim probleme iz stvarnog sveta za mnogo kraće vreme nego obično.

Zbog toga programiram AVR u C-u, GUI u PyQt-u, veoma stare GPU u ARB_vertex_program asembleru umesto u GLSL, pero-lake GUI programe u C++/Fltk, Emac u Lisp-u, moj MP3 plejer za kola kućne izrade u C-u, pošto sam prethodno uradio prototip u Perl-u, ARM dekompajler u Python-u i da, web servisi treba da se održavaju nezavisno u PHP-u. Mrzim PHP, ali to je pravi alat za posao. Pređite preko toga i počnite da pravite ono što vam završava posao, pogledajte celu sliku i s vremena na vreme je proveravajte.

Upravo to očekujem od Go jezika, a trenutno mi se čini da ispunjava moje zahteve. Video sam da vremenom mnogo toga može poći naopako. Niko nije bezbedan i ništa nije sigurno. Ali, ja hronično rano usvajam sve. Kad nešto radim, trudim se oko toga svim silama. Ako hoćete da znate kako je prošlo, čitajte ovde. Mogu vam samo reći da vredi pokušati, a malobrojni jezici uverili su me u to.

Veoma sam radoznao da pročitam bilo kakve naznake o boljem dizajnu jezika koje obično počinju rečima: “...ignoriše više od dvadeset godina istraživanja...” Nejasni predlozi funkcionišu isključivo za dobro poznate fenomene, ali ne i za specijalističke teme. Svako ko može da mi pokaže rezultate koji se odnose na Go, a koji se uklapaju u ograničenja ciljeva dizajna, dobro je došao. Na početku sam naveo svoju e-mail adresu!

Ostatak poglavlja možete preskočiti ako vas zanima samo programiranje i Go. Preostali odeljci odnose se na neke druge teme.

Za sve vas kojima sam stao na žulj u delu koji se zove: Povika. To je samo vika. Nije objektivno prikazivanje. Nije ni zamišljeno tako da bude objektivno. Koristi sarkazam i preterivanje. Neki ljudi ga razumeju, neki ne. Obično ga razumeju ljudi koji su imali slična iskustva kao ja. Bilo je dobro dati sebi oduška. I dalje mi se sviđa C, i dalje ću koristiti C++ i Java jezik kad god se ispostavi da su dobar alat za posao, ali to ne znači da oni čine srećnim moje programersko srce.

Uzgred, postoji razlika između fraza “nešto nije stvarno pogodno za nešto” i “nemoguće je uspešno uraditi nešto uz pomoć nečega”, čak i kad se pojavljuju u blizini broja 10000.

Izazivam dvoje koji su me optužili da ne dobijam OO odgovarajuće konkurentnosti da malo bolje objasne šta su time mislili. Ne vidim odakle potiče to pogrešno shvatanje čiji je koren pojednostavljivanje. Obrazovani čitaoci znaće prave detalje, a oni bez teoretske pozadine dobiće opštu ideju o onome što govorim.

Za čoveka koji obožava Perl6 i koji je bio uvređen mojim niskim udarcem u vezi s vremenom potrebnim za razvoj Perl-a 6: Budite spokojni jer sam, još uvek, u opštim crtama, Perl-ov fan. Instalirao sam Rakudo Star na svojoj mašini i pokušao sam da napišem nešto ozbiljno samo da bih proverio koliko je dobar. Na isti način kao što sam koristio i Go. I, ne, Perl6 još nije spreman za javnu upotrebu iako se približio tom cilju, moram priznati.

Svim cepidlakama o klasifikaciji i izboru jezika na koje sam digao viku: Naravno, mogu da pričam samo o onome što znam. Nigde ne kažem da dižem hajku na celu C porodicu ili čak na jezike koji potiču od Algol-a. U uvodu eksplicitno navodim nekoliko drugih jezika koji su glavni programski jezici i ograničio sam se na najpoznatije. Da, tu pripada i JavaScript. To je jedan od najrasprostranjenijih jezika i veoma je značajan.

Konačno, momku koji me nije shvatio ozbiljno zbog greške u kucanju. Umesto "it's" pisalo je "its". Jako mi je žao. U pravu si. U ovih 65kB teksta pojavila se jedna greška u kucanju. Ispravljena je. Nadam se da ćeš sada uspeti da pročitaš tekst. Slobodno mi ukaži na druge greške u kucanju, pošto ne koristim nikakav program za proveru pravopisa (osim tebe, očigledno).

Zaključak

Svako ko poredi izgled Go izvornog koda sa svojim omiljenim C-oidom ima priliku da izrazi svoj stav: Da li Go delimično liči na ono što volite ili na ono što mrzite? Svakoga pomalo nervira, to je neizbežno kad pokušavate da nešto uradite bolje. Stvara sopstveni osećaj, pa ne možete tek tako reći da imitira neki drugi jezik. Svaka čast!

Na kraju, dobijamo jednostavan i čist sistem koji se lako uči, iako pomalo neobičan. To bi mogla biti najveća prepreka kad Go treba da se proda CS početnicima koji uče klasične OO principe. Jednostavnost i bezbednost čine ga pogodnim za samouke programere.

"Effective Go" je odličan dokument koji treba da pročitate ako polazite od klasične OO pozadine. Važno je imati takav dokument, ali on nije kompletan. Istraživanje i pisanje ovog pregleda naučili su me više o ovom programskom jeziku nego pisanje aplikacije kojim sam se paralelno bavio. Ima toliko toga što ste navikli da radite, što Go radi drugačije, ali podjednako dobro (ili čak i bolje), a ja nisam bio svestan toga. Stalno je prisutan osećaj: “Go ne može da uradi to i to”, a u stvari može, samo na drugačiji način.

Da biste stekli bolji uvid u potencijal koji ima Go, setite se koliko je Go star. Prvi put je objavljen pre manje od dve godine, a ove godine je proglašen stabilnim. Pogledajte šta Go može danas i zamislite šta bi sve mogao kad bi imao komercijalnu podršku kao Java ili JavaScript. Najbolji primer uspešnog predstavljanja novog jezika je upravo Java. Sad uporedite skup karakteristika koje ima Go sa skupom karakteristika koje ima Java 1.0. Imamo pobednika.

Da bi iskoristio taj potencijal, jeziku treba neki zamah. Ili kroz otvorenu, aktivnu i rastuću zajednicu ili kroz korporativnu podršku. Više bih voleo zajednicu, ali u realnom svetu uspeha, verovatno mora da postoji i neki korporativni angažman. Bonus poeni dobijaju se ako Oracle još više zakomplikuje Java jezik :)

Stvarno, Go može biti odgovor na nedostatke svih trenutno popularnih programskih jezika, samo mu treba usvajanje.

Poslednja beleška: na internetu sam video kako mnogi kritikuju Go, a ne mogu to da ignorišem. Većina ga nije stvarno ni pogledala. Go je drugačiji, iako podseća na C. Ali, nije. Nije C++, niti Objective C i ne pokušava to ni da bude. Zato prestanite da pričate: "Kome treba Go kad već imamo C++/Objective C?" Proverite kako Go rešava iste probleme na potpuno drugačiji način. Prihvatite činjenicu da OO može da se uradi na nekoliko različitih načina. Možda ste i želeli da ga ignorišete, ali ako koristite JavaScript, već upotrebljavate nešto što se ne bazira na klasi OO. Nemojte samo da ga prihvatite, aktivno preuzmite moć tog različitog pristupa. Ostalima koji misle da Go nije dovoljno daleko dogurao: zapamtite da je to jezik realnog sveta. I tu je. I radi. Kakva je korist od divno konstruisanog jezika koji nije stabilan, završen ili dovoljno brz za probleme realnog sveta? Lako je zvocati zbog detalja, ali da bi proizvod zaživeo, treba da odgovori na sve izazove. A Go upravo to i radi.

I stvarno poslednja beleška: veliko hvala zajednici. Vaše povratne informacije bile su veoma korisne. Molim vas, nastavite da mi ispravljate greške, loše koncepte i sve na šta naiđete, ako naiđete. Nadam se da će ovaj dokument pomoći drugim potencijalnim korisnicima da uđu u Go. Da bi se to ostvarilo, dokument treba da bude tačan. Molim vas, budite sitničavi.


Published (Last edited): 07-01-2013 , source: http://www.syntax-k.de/projekte/go-review