Jump to page: 1 27  
Page
Thread overview
New slides about Go
Oct 14, 2010
bearophile
Oct 14, 2010
Walter Bright
Oct 14, 2010
Nick Sabalausky
Oct 14, 2010
bearophile
Oct 14, 2010
Vladimir Panteleev
Oct 14, 2010
Walter Bright
Oct 14, 2010
Denis Koroskin
Oct 14, 2010
bearophile
Oct 15, 2010
Vladimir Panteleev
Oct 15, 2010
Walter Bright
Oct 14, 2010
Nick Sabalausky
Oct 14, 2010
Walter Bright
Oct 14, 2010
Walter Bright
Oct 15, 2010
Paulo Pinto
Oct 15, 2010
Walter Bright
Oct 15, 2010
Paulo Pinto
Oct 15, 2010
so
Oct 15, 2010
bearophile
Oct 15, 2010
Paulo Pinto
Oct 15, 2010
Walter Bright
Oct 16, 2010
Paulo Pinto
Oct 16, 2010
Walter Bright
Oct 14, 2010
bearophile
Oct 15, 2010
Jonathan M Davis
Oct 15, 2010
Walter Bright
Oct 15, 2010
Nick Sabalausky
Oct 15, 2010
Walter Bright
Oct 15, 2010
JimBob
Oct 15, 2010
Max Samukha
Oct 15, 2010
Max Samukha
Oct 15, 2010
Max Samukha
Oct 15, 2010
Walter Bright
Oct 15, 2010
Max Samukha
Oct 15, 2010
Max Samukha
Oct 15, 2010
Walter Bright
Oct 15, 2010
Walter Bright
Oct 15, 2010
Denis Koroskin
Oct 15, 2010
dsimcha
Oct 16, 2010
Max Samukha
Oct 15, 2010
Michel Fortin
Oct 15, 2010
Max Samukha
Oct 14, 2010
Denis Koroskin
Oct 15, 2010
Walter Bright
Oct 16, 2010
Jérôme M. Berger
Oct 16, 2010
Walter Bright
Oct 15, 2010
Nick Sabalausky
Oct 15, 2010
Walter Bright
Nov 11, 2010
Bruno Medeiros
Nov 11, 2010
Justin Johansson
Nov 11, 2010
Justin Johansson
Nov 12, 2010
Bruno Medeiros
Nov 24, 2010
Nick Sabalausky
Nov 24, 2010
Bruno Medeiros
Oct 16, 2010
Justin Johansson
Oct 16, 2010
Nick Sabalausky
October 14, 2010
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
October 14, 2010
bearophile wrote:
> 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.

There's a huge cost to it, however. You can't call C code directly anymore.

Anyhow, this problem simply goes away with 64 bits. You can allocate each thread gigabytes of address space, faulting it in as required, and still be able to have billions of threads.

Segmented stacks would have been a great idea 10 years ago.
October 14, 2010
"Walter Bright" <newshound2@digitalmars.com> wrote in message news:i97v5c$d1u$1@digitalmars.com...
> bearophile wrote:
>> 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.
>
> There's a huge cost to it, however. You can't call C code directly anymore.
>
> Anyhow, this problem simply goes away with 64 bits.

Which is incredibly helpful on 32-bit systems.


October 14, 2010
Walter:

> You can't call C code directly anymore.

I don't know/understand why. Probably I just don't know how a segmented stack is implemented/structured.

If the stack is growable, I presume there's some free space anyway at the end of it. So you are not forced to test for the stack length, so you may call a C function and hope it will not blow the free stack left. Probably I am wrong, but I don't know why :-)

Bye,
bearophile
October 14, 2010
On Fri, 15 Oct 2010 02:04:59 +0300, bearophile <bearophileHUGS@lycos.com> wrote:

> Walter:
>
>> You can't call C code directly anymore.
>
> I don't know/understand why. Probably I just don't know how a segmented stack is implemented/structured.
>
> If the stack is growable, I presume there's some free space anyway at the end of it. So you are not forced to test for the stack length, so you may call a C function and hope it will not blow the free stack left. Probably I am wrong, but I don't know why :-)

Calling C code should still be possible, but it will involve checking for free space on the stack and preallocating as required. A possible optimization is to use one "C stack" per thread (with the assumption that there's no re-entry into our code from C code).

-- 
Best regards,
 Vladimir                            mailto:vladimir@thecybershadow.net
October 14, 2010
"bearophile" <bearophileHUGS@lycos.com> wrote in message news:i97utq$d7e$1@digitalmars.com...
>
> - In my D programs I sometimes use pointers, but pointer arithmetic is indeed uncommon.

If you're actually doing systems-level or high-performance work, it can be essential in certain cases depending on how good the optimizer is.

Loops like this are fairly typical (using 'for' instead of 'foreach'/'map'/etc for clarity):

T[] myArray = ...;
for(int i=0; i<max; i++)
{
    myArray[i] // <- do something with that
}

If the compiler isn't smart enough to turn that into this:

T[] myArray = ...;
auto ptr = myArray.ptr;
auto end = myArray.ptr + max;
for(auto ptr = myArray.ptr; ptr<end; ptr++)
{
    *myArray // <- do something with that
}

Then you're wasting cycles every iteration (by doing an extra addition and maybe an extra shift or even multiplication depending on T: Ie, (cast(ubyte*)myArray.ptr) + i * T.sizeof). That was a pretty common inner-loop optimization back in my C days.

And keep in mind, of course, real-world examples can be much more complex than that, so even if the compiler can handle trivial cases like this (I have no idea if it can, although using 'foreach' would probably make it easier - in some cases), it might not work for other cases. So unless the optimizer was known to be that good even in complex cases, I wouldn't want to be without pointer arithmetic. It's not needed often, but when it is needed it's indispensable (and still results in much more readable/portable code then delving down to asm).

Plus, I've never once done pointer arithmetic accidentally in D, so I don't see any safety to be gained from not allowing it.

> - 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've long been of the opinion that should just be a statement. All it ever does as an expression, if anything, is obfuscate code. I've never once seen a case where it clarified anything.

> - Segmented stack: allows to avoid some stack overflows at the price of a bit of delay at calling functions.

Seems a bad idea to force the overhead of that, but it should definitely be available as an option. Contrary to what Walter and Andrei seem to think, 32-bit systems are still very much alive and will be for quite awhile longer. Especially when you remember that there are more computers out there than just desktops and servers. (Ex: When is a phone ever going to need 64-bit? Eventually maybe, but certainly not anytime soon.)


October 14, 2010
bearophile wrote:
> Walter:
> 
>> You can't call C code directly anymore.
> 
> I don't know/understand why. Probably I just don't know how a segmented stack
> is implemented/structured.
> 
> If the stack is growable, I presume there's some free space anyway at the end
> of it. So you are not forced to test for the stack length, so you may call a
> C function and hope it will not blow the free stack left. Probably I am
> wrong, but I don't know why :-)

Segmented stacks add a test in *every* function's prolog to test and see if the stack is exhausted, and if so, switch to a new stack.

Exactly zero of C code does this.

So if you're near the end of your stack segment, and you call a C function, boom.
October 14, 2010
Nick Sabalausky wrote:
> "bearophile" <bearophileHUGS@lycos.com> wrote in message news:i97utq$d7e$1@digitalmars.com...
>> - In my D programs I sometimes use pointers, but pointer arithmetic is indeed uncommon.
> 
> If you're actually doing systems-level or high-performance work, it can be essential in certain cases depending on how good the optimizer is.

It's hard to see how to implement, say, a storage allocator with no pointer arithmetic.
October 14, 2010
Walter Bright wrote:
> It's hard to see how to implement, say, a storage allocator with no pointer arithmetic.

Here's another one. Try implementing va_arg without pointer arithmetic.
October 14, 2010
On Fri, 15 Oct 2010 03:41:50 +0400, Walter Bright <newshound2@digitalmars.com> wrote:

> So if you're near the end of your stack segment, and you call a C function, boom.

I've heard that happens in D, too. You can still call C functions at your peril, and no people complained so far.
« First   ‹ Prev
1 2 3 4 5 6 7