On 9 November 2012 21:39, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
On Friday, November 09, 2012 15:55:12 Manu wrote:
> Does that actually make sense? Surely a function that receives a scope
> argument can return that argument, since it's only passing it back to the
> same function that already owns it... it knows it can trust that function,
> since it was received from that function.

It can't. That would mean that the reference escaped. That would be
particularly deadly for delegates. Think about what happens if the scoped
delegate is put into a struct which is returned.

struct Result
{
 delegate........ del;
 ...........
}

Result foo(scope delegate....... bar)
{
 ..........
 return Result(bar);
}

auto baz()
{
 Result r;
 {
 int n = 5;
 r = foo((){writeln(n);});
 }
 r.del();
}

baz has no idea where the delegate in r came from. It has no idea that it
wasn't allocated as a closure. So, it's not going to allocate one, which means
that the delegate refers to a part of the stack which won't exist anymore when
the delegate actually gets called. If scope wasn't used, that wouldn't have
been a problem, because a closure would have been allocated as soon as the
delegate had been passed to foo, but because scope was used, it knows that the
delegate won't escape, so it doesn't allocate the closure (since it's not
necessary). But that only works because scope prevents escaping - including by
the return value. So, the above code _must_ be invalid.

Okay, makes sense.

>> Any struct holding any reference types would be
> > in the same boat, as would any class or AA.
>
> I don't follow the problem with reference args. surely they can be
> evaluated just fine? Just that nothing can escape the function...

It's the fact that they can't escape the function which is the problem. If
scope is working correctly, than any and all reference types which are passed
to the function via a scope parameter (be it directly or within another
object) cannot escape the function in any way shape or form. So, you can't
assign any of them to any static or module-level variables (not generally a
big deal) and you can't use any of them in the return value (often a big
deal). Sometimes, that's exactly what you want, but in the general case, you
don't want to prevent anything you pass into a function from being returned
from it, so scope quickly becames overly restrictive.

I'm still not buying this. Here's a common struct I will pass by ref (perhaps the most common struct in my industry):

struct Vector { float, x,y,z,w; }
struct Matrix { Vector xRow, yRow, zRow, wRow; }

Vector mul( scope const ref Matrix m, scope const Vector v)
{
  Vector v;
  // perform a matrix multiply against the vector...
  // this work uses every single field of the inputs given, but the result it produces has to references to the sources.
  // everything is operated on and copied to the output struct, which is returned.
  return result;
}

Why should this be a problem?
The majority of my work-horse structs apply to this pattern. This is what I imagine 'scope' to be for...
The main advantage I expect is that I can have confidence that passing rvalues (temporaries) is safe, and that external code won't take references to memory that I may not own/control. Is that not the point?

Surely the problem that scope should be protecting against is a pointer to any part of the argument escaping. *Copies* of values contained in the argument/s are fine.