Found through Reddit, talk slides by Rob Pike, "The Expressiveness of Go": http://go.googlecode.com/hg/doc/ExpressivenessOfGo.pdf
http://www.reddit.com/r/programming/comments/dr6r4/talk_by_rob_pike_the_expressiveness_of_go_pdf/ This time I think I have understood most of the contents of the slides :-) Few interesting quotations: >From Page 18: There are pointers but no pointer arithmetic - pointers are important to performance, pointer arithmetic not. - although it's OK to point inside a struct. - important to control layout of memory, avoid allocation Increment/decrement (p++) are statements, not expressions. - no confusion about order of evaluation Addresses last as long as they are needed. - take the address of a local variable, the implementation guarantees the memory survives while it's referenced. No implicit numerical conversions (float to int, etc.). - C's "usual arithmetic conversions" are a minefield. >From page 19 and 20: Constants are "ideal numbers": no size or sign, hence no L or U or UL endings. Arithmetic with constants is high precision. Only when assigned to a variable are they rounded or truncated to fit. A typed element in the expression sets the true type of the constant. >From page 40: Goroutines have "segmented stacks": go f() starts f() executing concurrently on a new (small) stack. Stack grows and shrinks as needed. No programmer concern about stack size. No possibility for stack overflow. A couple of instructions of overhead on each function call, a huge improvement in simplicity and expressiveness. >From page 46: The surprises you discover will be pleasant ones. -------------------- Some comments: - In my D programs I sometimes use pointers, but pointer arithmetic is indeed uncommon. - Turning x++; into statements seems harsh, but indeed it solves some problems. In practice in my D programs the ++ is often used as a statement, to avoid bugs. - I think that "take the address of a local variable, the implementation guarantees the memory survives while it's referenced." means that it gets copied on the heap. - Constants management in Go: seems cute. - Segmented stack: allows to avoid some stack overflows at the price of a bit of delay at calling functions. - The comment from 46 refers to a language that is orthogonal, and I think it is probably very correct. It's one of the main advantages of an orthogonal design, you are free to create many combinations. -------------------- On the Go site there is a "playground", similar to what Ideone and Codepad sites offer for D2/D1. It contains some small programs, and you may modify them and compile almost arbitrary Go code. A little Go example in the playground shows closures and the comma/tuple syntax similar to Python one: package main // fib returns a function that returns // successive Fibonacci numbers. func fib() func() int { a, b := 0, 1 return func() int { a, b = b, a+b return b } } func main() { f := fib() // Function calls are evaluated left-to-right. println(f(), f(), f(), f(), f()) } Something similar in D2, D lacks a handy unpacking syntax, and I think currently it doesn't guarantee that functions get evaluated left-to-right: import std.stdio: writeln; int delegate() fib() { int a = 0; int b = 1; return { auto a_old = a; a = b; b = a_old + b; return b; }; } void main() { auto f = fib(); // function calls are not surely evaluated left-to-right writeln(f(), " ", f(), " ", f(), " ", f(), " ", f()); } Another example on the Go site, that shows the segmented stacks at work: // Peano integers are represented by a linked list // whose nodes contain no data (the nodes are the data). // See: http://en.wikipedia.org/wiki/Peano_axioms // This program demonstrates the power of Go's // segmented stacks when doing massively recursive // computations. package main // Number is a pointer to a Number type Number *Number // The arithmetic value of a Number is the count of // the nodes comprising the list. // (See the count function below.) // ------------------------------------- // Peano primitives func zero() *Number { return nil } func isZero(x *Number) bool { return x == nil } func add1(x *Number) *Number { e := new(Number) *e = x return e } func sub1(x *Number) *Number { return *x } func add(x, y *Number) *Number { if isZero(y) { return x } return add(add1(x), sub1(y)) } func mul(x, y *Number) *Number { if isZero(x) || isZero(y) { return zero() } return add(mul(x, sub1(y)), x) } func fact(n *Number) *Number { if isZero(n) { return add1(zero()) } return mul(fact(sub1(n)), n) } // ------------------------------------- // Helpers to generate/count Peano integers func gen(n int) *Number { if n > 0 { return add1(gen(n - 1)) } return zero() } func count(x *Number) int { if isZero(x) { return 0 } return count(sub1(x)) + 1 } // ------------------------------------- // Print i! for i in [0,9] func main() { for i := 0; i <= 9; i++ { f := count(fact(gen(i))) println(i, "! =", f) } } It's easy to translate it to D: import std.stdio: writeln; struct Number { Number* next; this(Number* ptr) { next = ptr; } } // ------------------------------------- // Peano primitives Number* zero() { return null; } bool isZero(Number* x) { return x == null; } Number* add1(Number* x) { return new Number(x); } Number* sub1(Number* x) { return x.next; } Number* add(Number* x, Number* y) { if (isZero(y)) return x; return add(add1(x), sub1(y)); } Number* mul(Number* x, Number* y) { if (isZero(x) || isZero(y)) return zero(); return add(mul(x, sub1(y)), x); } Number* fact(Number* n) { if (isZero(n)) return add1(zero()); return mul(fact(sub1(n)), n); } // ------------------------------------- // Helpers to generate/count Peano integers Number* gen(int n) { if (n <= 0) return zero(); return add1(gen(n - 1)); } int count(Number* x) { if (isZero(x)) { return 0; } return count(sub1(x)) + 1; } // ------------------------------------- void main() { foreach (i; 0 .. 11) { int f = count(fact(gen(i))); writeln(i, "! = ", f); } } But compiled normally on Windows leads to a stack overflow, you need to add a -L/STACK:10000000 Bye, bearophile