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.

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: 4 ∗ 5 + 1 =