Od wczoraj (a w zasadzie przedwczorajszej nocy) w sieci jest głośno o nowym języku programowania, stworzonym przez ludzi z Google. Język nazywa się Go i leży między królestwem języków niskopoziomowych (jak C/C++) a królestwem języków wysokopoziomowych (jak Python, Java czy C#) (twórcy mówią o nim 'system programming language') - czyli próbuje łączyć zalety jednych (kompilacja do kodu natywnego, szybkość działania, etc) i drugich (garbage-collector, natywne wsparcie dla wielowątkowości, etc). Wczoraj wieczorem stwierdziłem, że przetestuje ten język i przeportowałem jeden ze swoich raytracerów na niego. Po tym pierwszym rzucie oka stwierdziłem, że podzielę się paroma przemyśleniami (wszystko zawarte w tym poście należy traktować jedynie jako moją opinię, wyrobioną po około 5 godzinach pisania w tym języku; zastrzegam że opinia może mi się zmienić ;>).

(kod raytracer'a jest na końcu posta)

Na sam początek powiem że w Go pisze się całkiem wygodnie, w większości wypadków wygodniej niż w C/C++, chociaż w kilku przypadkach programiści z Google stworzyli całkiem dziwaczne potworki.

Zacznę może od tego co mi się podoba:

1. Deklarowanie i inicjowanie zmiennych za pomocą symbolu :=
W Go zmienne można deklarować i inicjować na dwa sposoby. Pierwszy z nich to:
var nazwa typ = wartosc;
var a int = 5;

Czyli w zasadzie to co znamy z C/C++/etc - wyrażenie w którym mamy jawnie podany typ, nazwę, oraz wartość (o tym sposobie inicjowania będzie jeszcze później, w wadach ;>
Druga metoda (ta która mi się tak podoba) wygląda tak:
nazwa := wartosc;
a := 5;

Jak widać nie ma tutaj nigdzie typu, a to dlatego że kompilator sam wnioskuje typ na podstawie wartości (np. stała 5 jest typu int) - okazało się to niesłychanie wygodne gdy potrzebowałem jakąś tymczasową zmienną która odebrała by od jakieś funkcji to co funkcja zwraca (ret := my_func(12,34);) (ciekawostka: w GCC możemy to częściowo wyemulować jakimś makrem typu #define VAR(a,b) typeof(b) a = b, i potem używać VAR(a,5)).

2. If i for bez ( )
Szczerze mówiąc na początku for bez ( ) wyglądał dla mnie przynajmniej dziwnie, ale jak się okazało, bardzo szybko przestawiłem się na taki zapis i wydawał mi się on intuicyjny. Natomiast if bez ( ) zaakceptowałem od razu. Oczywiście rozumiem, że jest to jedynie kwestia gustu i w Waszym przypadku możecie znienawidzić ten brak nawiasów od pierwszego wejrzenia ;>
Dodam że for się świetnie komponuje z :=, np.
for i := 0; i < 10; i++
{
...
}


3. Goroutines
Goroutines są to oddzielne wątki egzekucji, działające w obrębie zbioru threadów (przypomina mi to trochę fibery, tyle że ich przełączaniem zajmuje się biblioteka runtime) - czyli mamy natywną wielowątkowość! A jak wygodnie się tego używa! Rzućcie okiem na poniższy przykład
go moja_funkcja_dowolnego_typu(dowolne, argumenty int);
I tyle. Ani nie trzeba tworzyć funkcji wrapperów żeby pozbyć się niewygodnych typów / przekazywania argumentów w dodatkowym obiekcie/strukturze, ani nie trzeba szukać dokumentacji żeby wiedzieć ile jakiś CreateThread przyjmuje argumentów i w jakiej kolejności. Wrzuca się go przed wywołanie funkcji, i tyle.
Co ciekawe, funkcja może być zdefiniowana od razu po czasowniku go, tak więc czasami nawet nie trzeba tworzyć oddzielnej zew. funkcji (posłużę się przykładem z dokumentacji):
go func(ch chan<- bool) { for { sleep(10); ch <- true; }} (c)

4. Kanały (chan)
Kanały pojawiły się już w poprzednim przykładzie. W zasadzie taki kanał to taki lekki potok przyjmujący dane określonego typu, a korzystanie z niego przypomina korzystanie ze strumieni w C++. Nie musimy robić żadnego CreatePipe, WriteFile, czy ReadFile (z dziesiątkami parametrów), ani sprawdzania czy na pewno doszedł cały pakiet danych. Wystarczy stworzyć sobie zmienną z przymiotnikiem chan, i już mamy potok. Teraz tylko do niego pisać lub z niego czytać:
potok <- dane; // zapis
zmienna := <-potok; // odczyt (synchroniczny)

Dzięki temu że odczyt jest synchroniczny, można z tego również korzystać jako z prostej metody na poczekanie aż wątek skończy (odpalenie goroutine, i poczekanie aż przyjdą dane przez kanał).

Jest jeszcze trochę mniejszych rzeczy ;>

A teraz kilka rzeczy które mi nie podpasowało.

1. Brak jawnego zadeklarowania jaki interfejs klasa implementuje
Mamy sobie jakiś interfejs (abstrakcyjną klasę), i chcemy go zaimplementować. Jak się okazuje, wystarczy potworzyć metody które mają takie same nazwy jak metody w interfejsie. Niewątpliwie jest to wygodne, ale człowiek nieźle musi się po dokumentacji/kodzie naszperać żeby znaleźć jakąś klasę która implementuje jeden konkretny interfejs (w C++ zrobiłbym po prostu find po ": public klasa", a tutaj nici z tego, w klasie nie będzie żadnej informacji o tym co implementuje).

2. Dziwnie definiowane metody
Tym razem przykład:
func NormalnaFunkcja(argumenty typ) typ_zwracany { }
func (p *Klasa) Metoda(argumenty typ) typ_zwracany { }

To akurat może być kwestia gustu, ale Klasa::Metoda() z C++ jakoś bardziej mi pasuje niż (p *Klasa) Metoda() z Go (za dużo ozdobników). Ciekawym wyborem natomiast było pozwolenie programiście nazwania zmiennej wskazującej na 'własny' obiekt (w C++ było to this, a tutaj możemy sobie nazwać; w przykładzie na obiekt wskazuje zmienna p).

3. Inicjacja wielu zmiennych w deklaracji
Przykład:
var a,b,c,d int = 1,2,3,4;
Z jednej strony jest to wygodne - tok myślowy może lecieć jednym torem na raz - najpierw nazwy, potem wartości, nie trzeba się przestawiać (nazwa, wartość, nazwa, wartość, nazwa, wartość). Z drugiej jednak strony... nie powiem żeby czytanie tego potem było przyjemne (trzeba liczyć przecinki żeby wiedzieć co jest co). Tak w zasadzie ten przykład bardzo przypomina mi Perla - easy to write, hard to read ;>
Natomiast szczerze powiem, że prawdopodobnie przekonam się do tego zapisu w niedługim czasie.

I to w zasadzie tyle. Mimo paru rzeczy które mi się nie widzi, to bardzo prawdopodobne jest, że ten język zagości w moim edytorze na dłużej.

Na koniec dodam że język całkiem dobrze współpracuje z preprocesorem z GCC (cpp), tylko trzeba po preprocesingu wyciąć wszystkie linie zaczynające się od #. Po za tym szkoda trochę, że język jest jeszcze niedostępny na platformę Windows.

By the way...
If want to improve your binary file and protocol skills, check out the workshop I'll be running between April and June → Mastering Binary Files and Protocols: The Complete Journey


Dla zainteresowanych, kod raytracera (jest to mój drugi program w Go, zaraz po Hello World, tak więc nie spodziewajcie się cudownej czytelności kodu, czy korzystania ze wszystkich wygód które język oferuje):
t2.go (9.6 KB, go, src; btw kompilator Go jest niestety póki co dostępny tylko na *nixy)

I to chyba tyle...

UPDATE: Wygląda na to że nie byłem pierwszą osobą która napisała raytracer w Go;> Pozdrowienia dla Grammerjack ;>

Comments:

2009-11-12 14:49:29 = faramir
{
Hmm.. niektóre rzeczy ciekawe, a inne już zrobione chociażby w języku D, który też jest kompilowalny...
google-web-toolkit Google zrobiło fajne, ale czy nie za dużo wymyślają od nowa?
}
2009-11-12 15:30:51 = Malcom
{
Liczylem, ze przyjrzysz sie mu nie co blizej pod maska ;)

Automatyczne typowanie zmiennych na podstawie kontekstu, mamy to w C++0x ;)

Odonosnie () i {} to w tym temacie prym wiedzie Perl, gdzie wszedzie mozna uzywa, ale nie trzeba, do tego pozwala na ciekawe konstrukcje przypominajace potoczny humoidalny szyk zdania:

print "dupa" if a eq 0;

Nigdy jakos nie przepdalem za jezykami z garbage collectorem, procz skryptowych.
http://malcom.pinger.pl/m/540205

Anyway,
Ktos uzywa this w implementacjach klasy w Cpp? Jak dla mnie paskudnie to wyglada. Inna sprawa przy template, gdy w niektorych momentach po prostu trzeba... a tu oni jeszcze pozwalaja na wlasna nazwe, chyba tylko dla wytworzenia wiekszego zamieszania ;p

Przegladajac kilka artykulow, manuali, jakos nie przypada mi do gustu. Wole swoje stare, wyprobowane zabawki ;p

Ciekawe czy zdobedzie jakas nisze na rynku. Zapewne duzo w tym bedzie zawdzieczal temu, ze jest od Google. Obecnie niezaleznie co Google wydaloby, cos naprawde wartosciowego, czy istotny bubel, chetni sie zanajda... bo przeciez to od naszego nowego wielkiego monopolisty i musi byc dobre ;p
}
2009-11-12 16:10:38 = anx
{
Jako początkujący w zabawach z C++ wydaje mi się że Go to całkiem fajnie uproszczone C. Ciekaw jestem jak z wydajnością, szybkością programu, rozmiarem w pamięci oraz rozmiarem po skompilowaniu w porównaniu do np. C++ czy pythona.

jednym słowem... MOAR!
}
2009-11-13 15:54:17 = Fanael
{
Bleh, zbyt paskudna składnia żeby coś w tym pisać. Powiedz szczerze, jak bardzo zaciskałeś zęby przy pisaniu tego raytracera? ;>
}
2009-11-15 09:10:51 = przemek1234
{
Proponuję się przyjrzeć też Microsoft Small Basic. .NET'owy język opracowany w tym roku, oparty składniowo o... BASIC'a. Chętnie poznałbym twoją opinię na jego temat.
}
2009-11-27 14:24:24 = Maciekx
{
Zauważyłem, że wszystkie produkty google są ściśle powiązane z ich wyszukiwarką, więc ten język na pewno też umożliwia cały szereg przydatnych funkcji powiązanych z wyszukiwaniem. Zauważyłem to przy ich przeglądarce a nawet systemie operacyjnym ( nawet instalka do przeglądarki jest podlinkowana w sieci). Ciekawe z nich zjawisko, pewnie zajdą ze swoim podejściem bardzo daleko.
}
2010-01-17 11:43:54 = lizard1982
{
No mi tam się ten język nie podoba i tyle ;d
Za dużo nowego wymyślania kół ;) Przypomina trochę Pascala i Pythona... Ja tam pozostaje przy języku C/C++ i języku D :)
Zapraszam na swoją stronkę!!
}
2010-01-18 13:26:58 = Gynvael Coldwind
{
@lizard1982
Kwestia gustu, jak zawsze przy wyborze języków ;>
}

Add a comment:

Nick:
URL (optional):
Math captcha: 2 ∗ 8 + 9 =