Reset all Members of a Aggregate Instance

Chris Wright via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Dec 3 14:32:32 PST 2015


On Thu, 03 Dec 2015 21:55:04 +0000, Nordlöw wrote:

> On Thursday, 3 December 2015 at 21:38:48 UTC, Chris Wright wrote:
>> The terrible way is something like:
>>
>> void reset(Object o)
>> in {
>>   assert(!(o is null));
>> }
>> body {
>>   auto p = cast(ubyte*)*cast(void**)&o;
>>   auto ci = o.classinfo;
>>   auto init = cast(ubyte)ci.init; p[0..init.length] = init[];
>>   if (ci.defaultConstructor) {
>>     ci.defaultConstructor(o);
>>   } else {
>>     throw new Exception("no default constructor; object is in
>> invalid state");
>>   }
>> }
> 
> In what way is this better than my solution?

I called my solution "terrible", which doesn't suggest that I think well 
of it compared to alternatives. I did this mainly to provide another 
implementation that someone else had alluded to. But since you asked...

You're ignoring the distinction between runtime and compiletime types, 
and you are resetting fields to the default values of their types, not 
the default values of the fields.

To wit:

class Foo {
  int i = 5;
}
class Bar : Foo {
  int j = 6;
  this() {}
  this(int a, int b) { i = a; j = b; }
}
Foo foo = new Bar(10, 10);
nordlow.resetAllFields(foo);

We expect foo to look like a default-initialized instance of whatever it 
began life as. Like if we implemented the equality operations, we'd 
expect to see this work: `assert(foo == new Bar);` But we don't. Your 
solution doesn't know what the default field value of Foo.i is, so it 
erroneously resets it to 0. We wanted 5.

Similarly, your solution ignores the fact that we've got an instance of 
Bar here, not an instance of Foo, and there are additional fields that 
need to be reset. You're using compile time reflection, so there's no way 
around that -- unless you create a virtual method with a mixin and 
require the user to mix it into each class in the hierarchy.

My solution still gets a ton wrong. I forgot to call the destructor, for 
instance. I can't call the constructor if it has parameters, and that 
means the object might well be in an invalid state. It's not safe in the 
face of potential runtime changes.

Assuming I encountered a case that both our solutions could handle 
correctly, I'd prefer yours. It's safer.


More information about the Digitalmars-d-learn mailing list