www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Aggregates & associations

reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
Hi,
    A lot of the recent debate surrounding garbage collection and to a  
lesser extent const has got me wondering about
aggregation, association and attribution in (garbage collected) languages  
like D and Java.
In object oriented modelling there is a clear distinction between  
association and aggregation. An aggregate is
part of the object. If the object is destroyed it should be destroyed as  
well. An association is just a reference to
another object. How are these two concepts distinguished in D or Java?
Even in C++ you can't express them directly. I find myself labelling  
pointers as "owned" or "not-owned".

In java:

class Foo;

class Bar
{
    Foo aggregate;
    Foo association;
};

In C++:

class Foo;

class Bar
{
   Foo aggregate;
   Foo* association
};

or

class Bar2
{
   ~bar2()
   {
     delete aggregate;
   }

   // owned
   Foo* aggregate;

   // not owned
   Foo* association
};

It seems to me that in D the correct idiom is:

class Bar
{
    Foo aggregate;
    Foo* association;
}

and specifically that:

class Bar
{
    Foo association;
}

should be considered an error.
How do you label associations and aggregations? Is there any modern  
language that lets you represent these distinct concepts directly?

Also I have just realised I have a fundermental gap in my understanding of  
very basic D.
When I declare:

class Foo
{
    int x;
    int y;
}

class Bar
{
    Foo aggregate;
}

What is the memory layout of the object I am actually declaring?
Is it the C++ equivalent of:

class Bar
{
    Foo aggregate;    // i.e. { int x, int y }
};

or

class Bar
{
    Foo* aggregate;
};

If I was being more low-level than I need to be most of time these days  
the memory layout matters. How do you choose
which kind of aggregation (has-a versus part-of) is implemented?
I'm amazed I never noticed this before but semantically its not a problem  
because an aggregate is an aggregate.
Could someone please enlighten me - my brain isn't screwed in today?
Dec 18 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
You seem to be getting confused as to how D classes work.  In D, classes
work like they do in Java: they are *always* references.  That is,

  class Foo {}
  Foo a;

Here, a is *effectively* a pointer; it is a reference to an instance of
Foo, just like in Java.

If you want to control the layout of memory, you can use a struct.

  struct Foo
  {
      int a, b;
  }

  struct Bar
  {
      Foo foo;
      float x;
  }

  Bar b;

Here, b is exactly 12 bytes long.  &b.foo.a == &b.foo == &b.  If b is
declared as a function local, it takes up 12 bytes on the stack; if it's
declared as part of an aggregate type (like a struct, class or union,)
then it takes up 12 bytes within an instance of that type.

So, to get back to your original question, you could probably represent
aggregates as structs and associations with classes.  Note that the only
one that can represent *both* would be a struct:

  struct Baz
  {
      Foo aggregate;
      Foo* association;
  }

Currently, this is all a bit of a mess.  However, I believe that Walter
intends to (eventually) introduce scoped class members like so:

  class Foo {}

  class Bar
  {
      scope Foo aggregate;
      Foo association;
  }

So that when an instance of Bar is destroyed, its 'aggregate' member is
also destroyed (currently, this is impossible to guarantee if
'aggregate' is GC-allocated.)

But that's not really useful at this point.

Hope that helps.

	-- Daniel
Dec 18 2007
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Wed, 19 Dec 2007 00:53:43 -0000, Daniel Keep  =

<daniel.keep.lists gmail.com> wrote:

 You seem to be getting confused as to how D classes work.  In D, class=
es
 work like they do in Java: they are *always* references.  That is,

   class Foo {}
   Foo a;

 Here, a is *effectively* a pointer; it is a reference to an instance o=
f
 Foo, just like in Java.
Right. I got that.
 If you want to control the layout of memory, you can use a struct.

   struct Foo
   {
       int a, b;
   }

   struct Bar
   {
       Foo foo;
       float x;
   }

   Bar b;

 Here, b is exactly 12 bytes long.  &b.foo.a =3D=3D &b.foo =3D=3D &b.  =
If b is
 declared as a function local, it takes up 12 bytes on the stack; if it=
's
 declared as part of an aggregate type (like a struct, class or union,)=
 then it takes up 12 bytes within an instance of that type.

 So, to get back to your original question, you could probably represen=
t
 aggregates as structs and associations with classes.  Note that the on=
ly
 one that can represent *both* would be a struct:

   struct Baz
   {
       Foo aggregate;
       Foo* association;
   }

 Currently, this is all a bit of a mess.
Yes it is isn't it. Why on Earth would any sensible refactoring of C++ include making the sa= me declaration "Foo aggregate" context dependent on whether its inside a = struct or a class. Why did Walter do this when his other refactorings were so sane? (Lose two guru points and make a sanity roll) This is not want I would want as classes and structs are different thing= s. = An instance of a class ISA object. A instance of a struct is not an object. This is also no good because structs have value semantics and classes ha= ve = reference semantics. Is this why we I see a "ref" keyword popping up occasionally?= = Is it the main way of making a struct behave like a class? Is this all for the sake of eliminating -> and &? I'm not sure it was = worth it. I can see there is a trade off between: Foo foo =3D new foo; versus Foo& foo =3D new Foo; //this is not D but it could have been The reference form is the most common usage so you don't want to type th= e = extra &. This makes sense with: scope Foo foo; being on (e.g.) the stack. Though it doesn't obviously mean "I am a value type".
 However, I believe that Walter
 intends to (eventually) introduce scoped class members like so:

   class Foo {}

   class Bar
   {
       scope Foo aggregate;
       Foo association;
   }

 So that when an instance of Bar is destroyed, its 'aggregate' member i=
s
 also destroyed (currently, this is impossible to guarantee if
 'aggregate' is GC-allocated.)

 But that's not really useful at this point.
This is useful for defining ownership though it a stretch for the = definition of scope. I suppose its better than introducing a new keyword like 'owned' though.=
 Hope that helps.

 	-- Daniel
It does but it makes me want to run away from D. What is really needed is a sensible way of saying "this is a value" vers= us "this is a reference" as a qualifier on the type. In c++ value was the norm and reference was &. So if reference is the no= rm = we need a qualifier that says I am a value. Its not obvious what the best choice would be. Perhaps * because it is = conventionally understood to C/C++ emigrees to mean dereference. So. class Bar { *Foo aggregateValue; Foo association; } I think the above syntax is particularly vile and would go for something= = like "val" as the antinym of "ref". i.e. class Bar { val Foo aggregateValue; Foo association; } The same keyword could solve the pass by value problem on functions too.= I like this it means that for every type there is always either a ref or= = val qualifier. The ref qualifier is just hidden because its the default. Have I missed anything? -- = Using Opera's revolutionary [NOT!] e-mail client: = http://www.opera.com/mail/
Dec 18 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bruce Adams" <tortoise_74 yeah.who.co.uk> wrote in message 
news:op.t3j6ntq1xikks4 lionheart.cybernetics...
On Wed, 19 Dec 2007 00:53:43 -0000, Daniel Keep
<daniel.keep.lists gmail.com> wrote:

------------------
What is really needed is a sensible way of saying "this is a value" versus
"this is a reference" as a qualifier on the type.
------------------

I'm just going to tell you what Walter would (and has, several times): in 
C++, 95% of the time you design a class to be _either_ a value type _or_ a 
reference type, not both, but of course there's no way to restrict the use 
thereof to one kind or the other.

Don't shoot the messenger.

(side note: absolutely _everyone_ who uses Opera as their newsreader, their 
posts don't quote correctly in OE...) 
Dec 18 2007
next sibling parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Wed, 19 Dec 2007 01:54:56 -0000, Jarrett Billingsley  
<kb3ctd2 yahoo.com> wrote:

 "Bruce Adams" <tortoise_74 yeah.who.co.uk> wrote in message
 news:op.t3j6ntq1xikks4 lionheart.cybernetics...
 On Wed, 19 Dec 2007 00:53:43 -0000, Daniel Keep
 <daniel.keep.lists gmail.com> wrote:

 ------------------
 What is really needed is a sensible way of saying "this is a value"  
 versus
 "this is a reference" as a qualifier on the type.
 ------------------

 I'm just going to tell you what Walter would (and has, several times): in
 C++, 95% of the time you design a class to be _either_ a value type _or_  
 a
 reference type, not both, but of course there's no way to restrict the  
 use
 thereof to one kind or the other.
That's an explanation for struct versus class but not the more general case including memory layout and calling conventions.
 Don't shoot the messenger.
[bang!] Whether you use values or references 95% of the time isn't an issue if you focus on semantics (of program behaviour). Most of the time is going to be about optimisation in terms of both speed and memory layout. However, I dislike the idea of having that 5% inaccessible to the language. I mean 95% of the time I don't need floating point numbers would it be okay to not support them?
 (side note: absolutely _everyone_ who uses Opera as their newsreader,  
 their
 posts don't quote correctly in OE...)
Presumably because outlook doesn't follow RFCs properly. Your voting buttons don't show up too well on my linux box either, :). (or your wacky decision to have reply to all reply to yourself as well)
Dec 18 2007
prev sibling parent =?ISO-8859-1?Q?Jari-Matti_M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
On Tue, 18 Dec 2007, Jarrett Billingsley wrote:

 (side note: absolutely _everyone_ who uses Opera as their newsreader, their
 posts don't quote correctly in OE...)
And OE doesn't specify the message encoding. Well luckily there's rarely non-ASCII discussion here.
Dec 23 2007
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
A long time ago Walter mentioned that the "scope" attribute may be 
extended to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

With the above, the size of Foo would be expanded to contain an instance 
of Baz and val2 would be initialized to reference this memory, very much 
like "scope" works in functions now.  But I didn't see any mention of 
this in the D 2.0 writeup so the idea may have been either discarded or 
forgotten.


Sean
Dec 18 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Sean Kelly" wrote
A long time ago Walter mentioned that the "scope" attribute may be extended 
to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an instance 
 of Baz and val2 would be initialized to reference this memory, very much 
 like "scope" works in functions now.  But I didn't see any mention of this 
 in the D 2.0 writeup so the idea may have been either discarded or 
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it. -Steve
Dec 19 2007
next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Steven Schveighoffer Wrote:

 "Sean Kelly" wrote
A long time ago Walter mentioned that the "scope" attribute may be extended 
to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an instance 
 of Baz and val2 would be initialized to reference this memory, very much 
 like "scope" works in functions now.  But I didn't see any mention of this 
 in the D 2.0 writeup so the idea may have been either discarded or 
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it.
It has more value that that. It's easy for me to imagine a scope class that includes one or more scope classes (such as a wrapper around an RAII object)
Dec 19 2007
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Wed, 19 Dec 2007 15:11:46 -0000, Jason House  
<jason.james.house gmail.com> wrote:

 Steven Schveighoffer Wrote:

 "Sean Kelly" wrote
A long time ago Walter mentioned that the "scope" attribute may be  
extended
to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an  
instance
 of Baz and val2 would be initialized to reference this memory, very  
much
 like "scope" works in functions now.  But I didn't see any mention of  
this
 in the D 2.0 writeup so the idea may have been either discarded or
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it.
It has more value that that. It's easy for me to imagine a scope class that includes one or more scope classes (such as a wrapper around an RAII object)
Also failing early can be a good thing. Attempting to use an associated object that is not valid is an error. Just because you have not released the memory for it does not make it valid. You program could give the illusion of working for a bit and then die mysteriously. The ability to delete deterministically as an optimisation could make programs more efficient too. You might even be able to simplify collection sweeps or switch them off temporarily without compromising performance.
Dec 19 2007
parent reply Sean Kelly <sean f4.ca> writes:
Bruce Adams wrote:
 On Wed, 19 Dec 2007 15:11:46 -0000, Jason House 
 <jason.james.house gmail.com> wrote:
 
 Steven Schveighoffer Wrote:

 "Sean Kelly" wrote
A long time ago Walter mentioned that the "scope" attribute may be 
extended
to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an 
instance
 of Baz and val2 would be initialized to reference this memory, very 
much
 like "scope" works in functions now.  But I didn't see any mention 
of this
 in the D 2.0 writeup so the idea may have been either discarded or
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it.
It has more value that that. It's easy for me to imagine a scope class that includes one or more scope classes (such as a wrapper around an RAII object)
Also failing early can be a good thing. Attempting to use an associated object that is not valid is an error. Just because you have not released the memory for it does not make it valid. You program could give the illusion of working for a bit and then die mysteriously. The ability to delete deterministically as an optimisation could make programs more efficient too. You might even be able to simplify collection sweeps or switch them off temporarily without compromising performance.
Interestingly, if objects are constructed inside the memory reserved for other objects, then if one is collected by the GC it must be true that all other objects in the same block are free as well. Also, since they share memory, all the objects can safely refer to one another in their dtors so long as they are careful to avoid using member data that may already have been released. As you say, this promises to offer some interesting possibilities for composite objects. Sean
Dec 19 2007
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Wed, 19 Dec 2007 20:41:58 -0000, Sean Kelly <sean f4.ca> wrote:

 Bruce Adams wrote:
 On Wed, 19 Dec 2007 15:11:46 -0000, Jason House  
 <jason.james.house gmail.com> wrote:

 Steven Schveighoffer Wrote:

 "Sean Kelly" wrote
A long time ago Walter mentioned that the "scope" attribute may be  
extended
to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an  
instance
 of Baz and val2 would be initialized to reference this memory, very  
much
 like "scope" works in functions now.  But I didn't see any mention  
of this
 in the D 2.0 writeup so the idea may have been either discarded or
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it.
It has more value that that. It's easy for me to imagine a scope class that includes one or more scope classes (such as a wrapper around an RAII object)
Also failing early can be a good thing. Attempting to use an associated object that is not valid is an error. Just because you have not released the memory for it does not make it valid. You program could give the illusion of working for a bit and then die mysteriously. The ability to delete deterministically as an optimisation could make programs more efficient too. You might even be able to simplify collection sweeps or switch them off temporarily without compromising performance.
Interestingly, if objects are constructed inside the memory reserved for other objects, then if one is collected by the GC it must be true that all other objects in the same block are free as well. Also, since they share memory, all the objects can safely refer to one another in their dtors so long as they are careful to avoid using member data that may already have been released. As you say, this promises to offer some interesting possibilities for composite objects. Sean
Except that at present there's no way to declare that an object is contained in another object except as a struct and a struct is not an object. I don't think scope would do this and if it did it would be ahem beyond its scope to do so.
Dec 19 2007
parent reply Sean Kelly <sean f4.ca> writes:
Bruce Adams wrote:
 On Wed, 19 Dec 2007 20:41:58 -0000, Sean Kelly <sean f4.ca> wrote:
 Interestingly, if objects are constructed inside the memory reserved 
 for other objects, then if one is collected by the GC it must be true 
 that all other objects in the same block are free as well.  Also, 
 since they share memory, all the objects can safely refer to one 
 another in their dtors so long as they are careful to avoid using 
 member data that may already have been released.  As you say, this 
 promises to offer some interesting possibilities for composite objects.
Except that at present there's no way to declare that an object is contained in another object except as a struct and a struct is not an object. I don't think scope would do this and if it did it would be ahem beyond its scope to do so.
Why? It works this way for class variables declared elsewhere. As a QOI feature, but still... Sean
Dec 19 2007
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Thu, 20 Dec 2007 00:49:05 -0000, Sean Kelly <sean f4.ca> wrote:

 Bruce Adams wrote:
 On Wed, 19 Dec 2007 20:41:58 -0000, Sean Kelly <sean f4.ca> wrote:
 Interestingly, if objects are constructed inside the memory reserved  
 for other objects, then if one is collected by the GC it must be true  
 that all other objects in the same block are free as well.  Also,  
 since they share memory, all the objects can safely refer to one  
 another in their dtors so long as they are careful to avoid using  
 member data that may already have been released.  As you say, this  
 promises to offer some interesting possibilities for composite objects.
Except that at present there's no way to declare that an object is contained in another object except as a struct and a struct is not an object. I don't think scope would do this and if it did it would be ahem beyond its scope to do so.
Why? It works this way for class variables declared elsewhere. As a QOI feature, but still... Sean
Sorry I should have qualified that. Scope as I understand it, declares whether a variable should be deleted or it. i.e. whether it is owned by the current scope, which in the proposed extension would mean class scope. It does not say anything about the memory layout. Whether the object is a value or reference is still up for grabs. It doesn't usually matter in functions but in a class it does, at least as an optimisation. I think something like the "val" syntax would make this kind of optimisation possible as well as solving the pass by value, pass by reference optimisation problem. Bruce.
Dec 20 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bruce Adams" <tortoise_74 yeah.who.co.uk> wrote in message 
news:op.t3mssesyxikks4 lionheart.cybernetics...

 Sorry I should have qualified that. Scope as I understand it, declares 
 whether
 a variable should be deleted or it. i.e. whether it is owned by the 
 current scope,
 which in the proposed extension would mean class scope. It does not say 
 anything
 about the memory layout. Whether the object is a value or reference is 
 still up
 for grabs. It doesn't usually matter in functions but in a class it does, 
 at least
 as an optimisation.
See, it's an optimization. Guess who should be doing optimizations? Hint: it's not the programmer. I'd place manual specification of whether a scope class is allocated inline the body of its owning class or function in the same category as "inline" and "register" -- ultimately meaningless hints to the compiler to do something that it can figure out better than you can. Chances are if we got scope class references in classes they _would_ be inlined into the owning class's body, if for no other reason than the principle of least surprise -- it already happens in functions -- and also because, well, it's a good optimization. This is why C++ is complex. It gives you all these possibilities and features, but leaves it up to you to make something useful out of them. D tries to give you useful _semantic_ features whose semantics leave room for optimization, freeing you from dealing with the low-level crap that C++ makes you deal with. I don't want D to go to the way C++ does it.
Dec 20 2007
parent "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Thu, 20 Dec 2007 14:38:40 -0000, Jarrett Billingsley  
<kb3ctd2 yahoo.com> wrote:

 "Bruce Adams" <tortoise_74 yeah.who.co.uk> wrote in message
 news:op.t3mssesyxikks4 lionheart.cybernetics...

 Sorry I should have qualified that. Scope as I understand it, declares
 whether
 a variable should be deleted or it. i.e. whether it is owned by the
 current scope,
 which in the proposed extension would mean class scope. It does not say
 anything
 about the memory layout. Whether the object is a value or reference is
 still up
 for grabs. It doesn't usually matter in functions but in a class it  
 does,
 at least
 as an optimisation.
See, it's an optimization. Guess who should be doing optimizations? Hint: it's not the programmer. I'd place manual specification of whether a scope class is allocated inline the body of its owning class or function in the same category as "inline" and "register" -- ultimately meaningless hints to the compiler to do something that it can figure out better than you can. Chances are if we got scope class references in classes they _would_ be inlined into the owning class's body, if for no other reason than the principle of least surprise -- it already happens in functions -- and also because, well, it's a good optimization. This is why C++ is complex. It gives you all these possibilities and features, but leaves it up to you to make something useful out of them. D tries to give you useful _semantic_ features whose semantics leave room for optimization, freeing you from dealing with the low-level crap that C++ makes you deal with. I don't want D to go to the way C++ does it.
Its not quite as simple as that. What needs to be optimised depends on how the program is used. The compiler cannot know that unless you add some pretty strong AI (or at least a way to feedback profiling results to your compiler). This is why inlining is still occasionally useful in C++, not because of bad language design.
Dec 20 2007
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Steven Schveighoffer wrote:
 "Sean Kelly" wrote
 A long time ago Walter mentioned that the "scope" attribute may be extended 
 to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an instance 
 of Baz and val2 would be initialized to reference this memory, very much 
 like "scope" works in functions now.  But I didn't see any mention of this 
 in the D 2.0 writeup so the idea may have been either discarded or 
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it.
You're right that it's not necessary. The GC is supposed to take care of this for you. But constructing complex aggregates can be quite expensive in terms of GC use, as a separate allocation must be made for every object. This can also reduce locality of the objects are of different sizes, which may affect performance by incurring cache misses. Now, it is possible in D 2.0 to get the size of an object and reserve space for it using a static array, but this requires the use of placement new, which requires yet more fancy template code to bolt onto existing classes, etc. So this is certainly possible, but far messier than in C++. And it's really a fairly common design requirement. Sean
Dec 19 2007
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Sean Kelly" wrote
 Steven Schveighoffer wrote:
 "Sean Kelly" wrote
 A long time ago Walter mentioned that the "scope" attribute may be 
 extended to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an instance 
 of Baz and val2 would be initialized to reference this memory, very much 
 like "scope" works in functions now.  But I didn't see any mention of 
 this in the D 2.0 writeup so the idea may have been either discarded or 
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it.
You're right that it's not necessary. The GC is supposed to take care of this for you. But constructing complex aggregates can be quite expensive in terms of GC use, as a separate allocation must be made for every object. This can also reduce locality of the objects are of different sizes, which may affect performance by incurring cache misses. Now, it is possible in D 2.0 to get the size of an object and reserve space for it using a static array, but this requires the use of placement new, which requires yet more fancy template code to bolt onto existing classes, etc. So this is certainly possible, but far messier than in C++. And it's really a fairly common design requirement.
I didn't quite understand your original post, thanks for explaining it further. -Steve
Dec 20 2007
prev sibling parent Christopher Wright <dhasenan gmail.com> writes:
Steven Schveighoffer wrote:
 "Sean Kelly" wrote
 A long time ago Walter mentioned that the "scope" attribute may be extended 
 to indicate aggregation:

     class Foo
     {
         Bar valA;
         scope Baz val2;
     }

 With the above, the size of Foo would be expanded to contain an instance 
 of Baz and val2 would be initialized to reference this memory, very much 
 like "scope" works in functions now.  But I didn't see any mention of this 
 in the D 2.0 writeup so the idea may have been either discarded or 
 forgotten.
I believe this type of behavior is not necessary. Whether a member is an aggregate or an association, it will be deleted when nothing references it anymore, which is when it should be deleted. The only thing this proposed behavior can do is cause segfaults when something that still has a reference to a scoped member tries to use it. -Steve
I think the desired behavior is this: 1. Any object can have zero or one owners. 2. Any object that has an owner is collected and has its destructor called after its owner is collected and has its destructor called. 3. As an exception to (2), if an object's owner has no reference to it, the object can be collected.
Dec 19 2007