summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_content/blog/first-go-program/index.adoc467
-rw-r--r--_content/blog/index.adoc4
2 files changed, 470 insertions, 1 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.
diff --git a/_content/blog/index.adoc b/_content/blog/index.adoc
index 1175be9..312487b 100644
--- a/_content/blog/index.adoc
+++ b/_content/blog/index.adoc
@@ -109,6 +109,9 @@
* link:/blog/slices/["Array, slice (dan string): Mekanisme 'append'"^],
26 September 2013. Rob Pike.
+* link:/blog/first-go-program/[Program Go yang pertama^],
+ 18 Juli 2013. Andrew Gerrand.
+
* link:/blog/race-detector/[Memperkenalkan pendeteksi _data race_^],
26 Juni 2013. Dmitry Vyukov dan Andrew Gerrand.
@@ -124,7 +127,6 @@
* link:/blog/waza-talk/[Konkurensi bukanlah paralelisme^].
16 Januari 2013. Andrew Gerrand.
-
=== 2012
* link:/blog/organizing-go-code/[Mengorganisasi kode Go^],