new principle of division between structures and classes

Bill Baxter wbaxter at gmail.com
Sat Jan 10 15:26:49 PST 2009


2009/1/11 Christopher Wright <dhasenan at gmail.com>:
>> Instead of such division as now: POD && value type (struct) and POD &&
>> reference type (class).
>
> The reference versus value type difference is just a matter of defaults.

No it's not.  scope MyClass does not make a MyClass that works like a
value type.  It merely makes a MyClass instance that's allocated on
the stack.  The semantics of it otherwise is identical to a regular
class.

Another difference is that class instances can only be 'scope' in functions.
A use case that's missing is:
class MyClass {
     scope OtherClass foo;
}
This would embed the memory for 'foo' right inside MyClass, so that

   scope x = new MyClass;

Would not involve any heap allocations.  Currently if you have a class
inside a class, there's no way to use 'scope' to avoid the heap
allocation on the contained class.

Also you could imagine scope arrays.
MyClass foo = new scope MyClass[10];

Where this would do one heap allocation, not 10.
There is a problem with this though, mentioned below, precisely
because scope MyClass does *not* have value semantics.

> Returning a class instance on the stack from a function is possible with
> inout parameters, though you can't use a constructor in that case:
> void main ()
> {
>        scope MyClass obj = new MyClass;
>        foo (obj);
> }
>
> void foo (inout MyClass obj)
> {
>        // initialize obj somehow
> }

To further follow up on this, what you are showing is *not* returning
a class instance on the stack via inout.  You are just modifying a
pre-existing instance.   Returning a scope instance via inout would
look like this:

void main() {
    MyClass obj;
    foo(obj);
}
void foo(inout MyClass obj) {
    scope tmp = new MyClass;
    obj = tmp;
}

And that will crash because it refers to memory allocated on the stack.
What is impossible with D right now is to make a value copy of a class
(short of getting hackish with memcpy).

But since classes can be polymorphic, value copying gets you into
slicing problems.  That's why value copying is disabled to begin with.
 So disabling value copies is a good thing.

And that's also the problem with putting scope'd things inside another
class or an array.  Since they don't have value semantics, there's no
way to overwrite the memory that's there with a new version of the
object.  If you try to overwrite it you will instead just change the
pointer.  (This is what happens with scope objects in functions now).


Assuming this worked:

class MyClass {
     scope OtherClass foo;
}
scope x = new MyClass;
x.foo = new OtherClass;

You haven't reused the memory that foo originally occupied.  You've
instead made foo point to the heap.  And now you have a chunk of your
class that stored the original foo that's dead, useless and
uncollectable.

So the conclusion is that scope without value semantics is of somewhat
limited use.   Or at least in the case of embedded scope objects, they
should best be considered kind of like 'final', only for cases where
you're never going to rebind the reference to something else.

--bb



More information about the Digitalmars-d mailing list