diff options
Diffstat (limited to '_content/blog/first-go-program/index.adoc')
| -rw-r--r-- | _content/blog/first-go-program/index.adoc | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/_content/blog/first-go-program/index.adoc b/_content/blog/first-go-program/index.adoc new file mode 100644 index 0000000..699c922 --- /dev/null +++ b/_content/blog/first-go-program/index.adoc @@ -0,0 +1,467 @@ += Program Go yang pertama +Andrew Gerrand +18 Juli 2013 + +Brad Fitzpatrick dan saya (Andrew Gerrand) baru-baru ini mulai menata +ulang +https://go.dev/cmd/godoc/[godoc^], +dan saya baru sadar, godoc adalah salah satu program Go yang paling +lama. +Robert Griesemer menulis program tersebut di awal 2009, dan kita masih +menggunakannya sampai sekarang. + +Saat saya +https://twitter.com/enneff/status/357403054632484865[men-tweet^] +tentang hal ini, Dave Cheney membalas dengan +https://twitter.com/davecheney/status/357406479415914497[pertanyaan +menarik^]: program Go apa yang paling tua? +Rob Pike mencari-cari di dalam surel-nya dan menemukan sebuah pesan +lama dari Ken Thomposon ke Robert (Griesemer). + +Yang kita lihat selanjutnya adalah program Go yang pertama. +Yang ditulis oleh Rob di bulan Februari 2008, saat tim Go saat itu +hanya Rob, Robert, dan Ken. +Mereka memiliki sejumlah fitur yang solid (yang ditulis dalam +https://commandcenter.blogspot.com.au/2012/06/less-is-exponentially-more.html[blog +ini^] +dan spesifikasi bahasa yang agak kasar. +Ken baru saja menyelesaikan versi pertama dari kompilator Go (yang belum +menghasilkan kode natif, tapi transliterasi kode Go ke C untuk prototipe +pertama) dan saatnya mencoba membuat program dengan kompilator tersebut. + +Rob mengirim surel ke "Tim Go": + +---- +From: Rob 'Commander' Pike +Date: Wed, Feb 6, 2008 at 3:42 PM +To: Ken Thompson, Robert Griesemer +Subject: slist + +it works now. + +roro=% a.out +(defn foo (add 12 34)) +return: icounter = 4440 +roro=% + +here's the code. +some ugly hackery to get around the lack of strings. +---- + +(Baris `icounter` pada keluaran program adalah jumlah perintah yang +dieksekusi, ditulis untuk pemeriksaan.) + +---- +package main + +// fake stuff +type char uint8; + +// const char TESTSTRING[] = "(defn foo (add 'a 'b))\n"; + +type Atom struct { + string *[100]char; + integer int; + next *Slist; /* in hash bucket */ +} + +type List struct { + car *Slist; + cdr *Slist; +} + +type Slist struct { + isatom bool; + isstring bool; + //union { + atom Atom; + list List; + //} u; + + Free method(); + Print method(); + PrintOne method(doparen bool); + String method(*char <-); + Integer method(int <-); + Car method(*Slist <-); + Cdr method(*Slist <-); +} + +method (this *Slist) Car(*Slist <-) { + return this.list.car; +} + +method (this *Slist) Cdr(*Slist <-) { + return this.list.cdr; +} + +method (this *Slist) String(*[100]char <-) { + return this.atom.string; +} + +method (this *Slist) Integer(int <-) { + return this.atom.integer; +} + +function OpenFile(); +function Parse(*Slist <-); + +//Slist* atom(char *s, int i); + +var token int; +var peekc int = -1; +var lineno int32 = 1; + +var input [100*1000]char; +var inputindex int = 0; +var tokenbuf [100]char; + +var EOF int = -1; // BUG should be const + +function main(int32 <-) { + var list *Slist; + + OpenFile(); + for ;; { + list = Parse(); + if list == nil { + break; + } + list.Print(); + list.Free(); + break; + } + + return 0; +} + +method (slist *Slist) Free(<-) { + if slist == nil { + return; + } + if slist.isatom { +// free(slist.String()); + } else { + slist.Car().Free(); + slist.Cdr().Free(); + } +// free(slist); +} + +method (slist *Slist) PrintOne(<- doparen bool) { + if slist == nil { + return; + } + if slist.isatom { + if slist.isstring { + print(slist.String()); + } else { + print(slist.Integer()); + } + } else { + if doparen { + print("("); + } + slist.Car().PrintOne(true); + if slist.Cdr() != nil { + print(" "); + slist.Cdr().PrintOne(false); + } + if doparen { + print(")"); + } + } +} + +method (slist *Slist) Print() { + slist.PrintOne(true); + print "\n"; +} + +function Get(int <-) { + var c int; + + if peekc >= 0 { + c = peekc; + peekc = -1; + } else { + c = convert(int, input[inputindex]); + inputindex = inputindex + 1; // BUG should be incr one expr + if c == '\n' { + lineno = lineno + 1; + } + if c == '\0' { + inputindex = inputindex - 1; + c = EOF; + } + } + return c; +} + +function WhiteSpace(bool <- c int) { + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +function NextToken() { + var i, c int; + var backslash bool; + + tokenbuf[0] = '\0'; // clear previous token + c = Get(); + while WhiteSpace(c) { + c = Get(); + } + switch c { + case EOF: + token = EOF; + case '(': + case ')': + token = c; + break; + case: + for i = 0; i < 100 - 1; { // sizeof tokenbuf - 1 + tokenbuf[i] = convert(char, c); + i = i + 1; + c = Get(); + if c == EOF { + break; + } + if WhiteSpace(c) || c == ')' { + peekc = c; + break; + } + } + if i >= 100 - 1 { // sizeof tokenbuf - 1 + panic "atom too long\n"; + } + tokenbuf[i] = '\0'; + if '0' <= tokenbuf[0] && tokenbuf[0] <= '9' { + token = '0'; + } else { + token = 'A'; + } + } +} + +function Expect(<- c int) { + if token != c { + print "parse error: expected ", c, "\n"; + panic "parse"; + } + NextToken(); +} + +// Parse a non-parenthesized list up to a closing paren or EOF +function ParseList(*Slist <-) { + var slist, retval *Slist; + + slist = new(Slist); + slist.list.car = nil; + slist.list.cdr = nil; + slist.isatom = false; + slist.isstring = false; + + retval = slist; + for ;; { + slist.list.car = Parse(); + if token == ')' { // empty cdr + break; + } + if token == EOF { // empty cdr BUG SHOULD USE || + break; + } + slist.list.cdr = new(Slist); + slist = slist.list.cdr; + } + return retval; +} + +function atom(*Slist <- i int) { // BUG: uses tokenbuf; should take +argument + var h, length int; + var slist, tail *Slist; + + slist = new(Slist); + if token == '0' { + slist.atom.integer = i; + slist.isstring = false; + } else { + slist.atom.string = new([100]char); + var i int; + for i = 0; ; i = i + 1 { + (*slist.atom.string)[i] = tokenbuf[i]; + if tokenbuf[i] == '\0' { + break; + } + } + //slist.atom.string = "hello"; // BUG! s; //= strdup(s); + slist.isstring = true; + } + slist.isatom = true; + return slist; +} + +function atoi(int <-) { // BUG: uses tokenbuf; should take argument + var v int = 0; + for i := 0; '0' <= tokenbuf[i] && tokenbuf[i] <= '9'; i = i + 1 { + v = 10 * v + convert(int, tokenbuf[i] - '0'); + } + return v; +} + +function Parse(*Slist <-) { + var slist *Slist; + + if token == EOF || token == ')' { + return nil; + } + if token == '(' { + NextToken(); + slist = ParseList(); + Expect(')'); + return slist; + } else { + // Atom + switch token { + case EOF: + return nil; + case '0': + slist = atom(atoi()); + case '"': + case 'A': + slist = atom(0); + case: + slist = nil; + print "unknown token"; //, token, tokenbuf; + } + NextToken(); + return slist; + } + return nil; +} + +function OpenFile() { + //strcpy(input, TESTSTRING); + //inputindex = 0; + // (defn foo (add 12 34))\n + inputindex = 0; + peekc = -1; // BUG + EOF = -1; // BUG + i := 0; + input[i] = '('; i = i + 1; + input[i] = 'd'; i = i + 1; + input[i] = 'e'; i = i + 1; + input[i] = 'f'; i = i + 1; + input[i] = 'n'; i = i + 1; + input[i] = ' '; i = i + 1; + input[i] = 'f'; i = i + 1; + input[i] = 'o'; i = i + 1; + input[i] = 'o'; i = i + 1; + input[i] = ' '; i = i + 1; + input[i] = '('; i = i + 1; + input[i] = 'a'; i = i + 1; + input[i] = 'd'; i = i + 1; + input[i] = 'd'; i = i + 1; + input[i] = ' '; i = i + 1; + input[i] = '1'; i = i + 1; + input[i] = '2'; i = i + 1; + input[i] = ' '; i = i + 1; + input[i] = '3'; i = i + 1; + input[i] = '4'; i = i + 1; + input[i] = ')'; i = i + 1; + input[i] = ')'; i = i + 1; + input[i] = '\n'; i = i + 1; + NextToken(); +} +---- + +Program tersebut memindai dan mencetak +https://en.wikipedia.org/wiki/S-expression[S-expression^]. +Ia tidak membaca input dari user dan tidak memiliki impor, bergantung kepada +fasilitas `print` untuk pencetakan. +Ia ditulis benar-benar di hari pertama sejak +https://go.dev/change/8b8615138da3[kompilator bekerja walau belum komplit^]. +Kebanyakan fitur bahasa belum diimplementasikan dan beberapa darinya bahkan +belum ada spesifikasi-nya. + +Namun, bentuk awal dari bahasa yang kita pakai sekarang sudah tampak pada +program tersebut. +Deklarasi tipe dan variabel, alur kontrol, dan perintah paket tidak banyak +berubah. + +Tapi banyak perbedaan dan kekurangan. +Yang paling mencolok yaitu tidak adanya konkurensi dan _interface_--keduanya +dianggap fitur esensial sejak hari pertama namun belum dirancang. + +Kata `func` adalah sebuah fungsi, dan bentuknya menspesifikasikan nilai +kembalian _sebelum_ argumen, dipisahkan oleh `\<-`, yang sekarang kita +gunakan sebagai operator pengiriman/penerimaan dari dan ke _channel_. +Misalnya, fungsi `WhiteSpace` menerima integer `c` dan mengembalikan sebuah +`boolean`. +---- +function WhiteSpace(bool <- c int) +---- + +Tanda panah tersebut adalah pemisah sebelum sintaksis yang lebih bagus +dirancang untuk mendeklarasikan banyak nilai kembalian. + +Method ditulis berbeda dari fungsi dan punya sintaksis-nya sendiri. +---- +method (this *Slist) Car(*Slist <-) { + return this.list.car; +} +---- + +Dan method dideklarasikan di dalam definisi `struct`, walaupun hal ini +nantinya berubah. +---- +type Slist struct { + ... + Car method(*Slist <-); +} +---- + +Belum ada tipe string, walaupun spesifikasi-nya sudah ada. +Untuk bekerja dengan string, Rob harus membuat string sebagai array bertipe +`uint8` dengan konstruksi yang aneh. +(Tipe array tidak berubah dan slice belum ada rancangannya, walaupun ada +konsep "open array" yang belum diimplementasikan.) +---- +input[i] = '('; i = i + 1; +input[i] = 'd'; i = i + 1; +input[i] = 'e'; i = i + 1; +input[i] = 'f'; i = i + 1; +input[i] = 'n'; i = i + 1; +input[i] = ' '; i = i + 1; +... +---- + +Fungsi `panic` dan `print` adalah bawaan, bukan fungsi yang dideklarasikan. +---- +print "parse error: expected ", c, "\n"; +panic "parse"; +---- + +Dan masih ada banyak beberapa perbedaan kecil lainnya; lihat apakah Anda +bisa mengidentifikasi diantaranya. + +Kurang dari dua tahun setelah program tersebut ditulis, Go dirilis sebagai +proyek sumber terbuka. +Melihat ke belakang, sangatlah jelas betapa bahasa Go telah berkembang dan +dewasa. +(Hal terakhir yang berubah antara proto-Go dan Go yang kita kenal sekarang +yaitu dihapusnya titik-koma.) + +Namun yang paling mencolok adalah betapa banyak yang telah kita pelajari +tentang _menulis_ kode Go. +Misalnya, Rob menulis penerima method dengan `this`, namun sekarang kita +menggunakan nama yang singkat dengan konteks yang spesifik. +Ada ratusan lebih contoh-contoh penting lainnya dan sampai sekarang kita +masih mencari cara terbaik menulis kode Go. +(Perhatikan trik cerdik dari +https://github.com/golang/glog[paket glog^] +untuk +https://github.com/golang/glog/blob/c6f9652c7179652e2fd8ed7002330db089f4c9db/glog.go#L893[menangani +tingkat verbositas^].) + +Saya ingin tahu apa yang akan kita pelajari di masa depan. |
