www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Reset class member variables

reply mandel <mandel foobar.com> writes:
Hi,

I have some big classes with lots of member variables
that need to be reset to theire initial value.
Therefore I thought about a more reliable way to
accomplish this, because it's hard to keep track
of variables I have added.
It also looks bloated to assign all values manually.

class Foo
{
	uint x;
	char[] name = "world";
//problematic:
	const uint y;
	char[1024] buffer;
	
	void reset()
	{
		scope tmp = new typeof(this);
		foreach(i, x;  tmp.tupleof)
		{
			this.tupleof[i] = x;
		}
	}
}

The problem is that I have to avoid
to try to set const values and static arrays.

How can this be done?
Sep 07 2007
next sibling parent Matti Niemenmaa <see_signature for.real.address> writes:
mandel wrote:
 Hi,
 
 I have some big classes with lots of member variables
 that need to be reset to theire initial value.
 Therefore I thought about a more reliable way to
 accomplish this, because it's hard to keep track
 of variables I have added.
 It also looks bloated to assign all values manually.
 
 class Foo
 {
 	uint x;
 	char[] name = "world";
 //problematic:
 	const uint y;
 	char[1024] buffer;
 	
 	void reset()
 	{
 		scope tmp = new typeof(this);
 		foreach(i, x;  tmp.tupleof)
 		{
 			this.tupleof[i] = x;
 		}
 	}
 }
 
 The problem is that I have to avoid
 to try to set const values and static arrays.
 
 How can this be done?

Does "this = new typeof(this);" work? -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 07 2007
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
mandel wrote:
 Hi,
 
 I have some big classes with lots of member variables
 that need to be reset to theire initial value.
 Therefore I thought about a more reliable way to
 accomplish this, because it's hard to keep track
 of variables I have added.
 It also looks bloated to assign all values manually.
 
 class Foo
 {
 	uint x;
 	char[] name = "world";
 //problematic:
 	const uint y;
 	char[1024] buffer;
 	
 	void reset()
 	{
 		scope tmp = new typeof(this);
 		foreach(i, x;  tmp.tupleof)
 		{
 			this.tupleof[i] = x;
 		}
 	}
 }
 
 The problem is that I have to avoid
 to try to set const values and static arrays.
 
 How can this be done?

It's a bit horrifying, but this should work: class Foo { uint x; char[] name = "world"; //problematic: const uint y; char[1024] buffer; void reset() { (cast(byte*) this)[0 .. this.classinfo.init.length] = this.classinfo.init[0 .. $]; } } Sean
Sep 07 2007
next sibling parent mandel <mandel foobar.com> writes:
Yes ,that works (and looks horrific, too). :P

Sean Kelly Wrote:

 mandel wrote:
 Hi,


 class Foo
 {
 	uint x;
 	char[] name = "world";
 //problematic:
 	const uint y;
 	char[1024] buffer;
 	
 	void reset()
 	{
 		scope tmp = new typeof(this);
 		foreach(i, x;  tmp.tupleof)
 		{
 			this.tupleof[i] = x;
 		}
 	}
 }
 
 The problem is that I have to avoid
 to try to set const values and static arrays.
 
 How can this be done?

It's a bit horrifying, but this should work: class Foo { uint x; char[] name = "world"; //problematic: const uint y; char[1024] buffer; void reset() { (cast(byte*) this)[0 .. this.classinfo.init.length] = this.classinfo.init[0 .. $]; } } Sean

Sep 07 2007
prev sibling parent reply mandel <mandel foobar.com> writes:
Ok, I jumped to early. :/
This method ignores const values that I have set in the ctor:
So, "this() { y = 123; }" would be reset to 0.

Sean Kelly Wrote:
 
 It's a bit horrifying, but this should work:
 
 class Foo
 {
      uint x;
      char[] name = "world";
 //problematic:
      const uint y;
      char[1024] buffer;
 
      void reset()
      {
          (cast(byte*) this)[0 .. this.classinfo.init.length] =
              this.classinfo.init[0 .. $];
      }
 }
 
 
 Sean

Sep 07 2007
parent Sean Kelly <sean f4.ca> writes:
mandel wrote:
 Ok, I jumped to early. :/
 This method ignores const values that I have set in the ctor:
 So, "this() { y = 123; }" would be reset to 0.

Hrm... to deal with that I think you'd have to use foreach and tupleof, but I don't think D 1.0 provides a means for detecting the storage type of a declaration. Ideally, you'd want to do something like this: foreach( pos, inout val; this.tupleof ) { static if( !is( typeof( val ) : const ) ) val = this.classinfo.init.tupleof[pos]; }
Sep 07 2007
prev sibling next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
mandel schrieb:
 Hi,
 
 I have some big classes with lots of member variables
 that need to be reset to theire initial value.
 Therefore I thought about a more reliable way to
 accomplish this, because it's hard to keep track
 of variables I have added.
 It also looks bloated to assign all values manually.

what about creating a new object everytime you need a fresh one? i think that new is faster than reinitalise all members - and you get rid of your track problems (btw: the need of reseting an object could be a design problem) ciao dennis
Sep 07 2007
next sibling parent dennis luehring <dl.soluz gmx.net> writes:
 (btw: the need of reseting an object could be a design problem)

1# bad example: int result[]; auto obj = new TheObject(); for( ... ) { result ~= obj.do_some_thing( some_data ); obj.reset(); } possible errors: you forgot the .reset() or the reset isn't correct implemented .... 2# better, cleaner way: int result[]; for( ... ) { auto obj = new TheObject(); result ~= obj.do_some_thing( some_data ); } in this case you don't have to safe/repair your object state possible errors: none --- design blabla the obj.reset is (maybe) an hard optimizing step (if the newing IS expensive) or your obj is doing the wrong stuff (in the wrong context?)
Sep 07 2007
prev sibling parent reply mandel <mandel foobar.com> writes:
I agree, in many cases it is a design problem
to reset an Object because the problems
introduced by it often outweights the 
speed/memory overhead.

But it's nice when the initializing problem
can be done in a foolproof way.
It's nice not to have to sacrifice speed for reliability.


dennis luehring Wrote:

 mandel schrieb:
 Hi,
 
 I have some big classes with lots of member variables
 that need to be reset to theire initial value.
 Therefore I thought about a more reliable way to
 accomplish this, because it's hard to keep track
 of variables I have added.
 It also looks bloated to assign all values manually.

what about creating a new object everytime you need a fresh one? i think that new is faster than reinitalise all members - and you get rid of your track problems (btw: the need of reseting an object could be a design problem) ciao dennis

Sep 07 2007
parent reply Nathan Reed <nathaniel.reed gmail.com> writes:
mandel wrote:
 It's nice not to have to sacrifice speed for reliability.

In a garbage collected language like D, allocations are extremely fast, potentially several times faster than heap based languages like C/C++. Using a new instance of the object for each iteration of the loop is really what you're doing /conceptually/, anyway...so, I wouldn't worry about the allocation performance too much unless you've profiled the app and established that it is a bottleneck. And if that's the case you might want to think about making the object a struct (so a value-type, allocated on the stack) anyway. Thanks, Nathan Reed
Sep 07 2007
parent reply Sean Kelly <sean f4.ca> writes:
Nathan Reed wrote:
 mandel wrote:
 It's nice not to have to sacrifice speed for reliability.

In a garbage collected language like D, allocations are extremely fast, potentially several times faster than heap based languages like C/C++. Using a new instance of the object for each iteration of the loop is really what you're doing /conceptually/, anyway...so, I wouldn't worry about the allocation performance too much unless you've profiled the app and established that it is a bottleneck.

Or if there's some reason that the object must be re-initialized in place--say, to preserve its address. One could argue that this necessity indicates a poor program design, but I imagine there are cases where it may apply. For what it's worth, this would be quite easy to accomplish if D supported placement new as a default construction method (rather than requiring the user to override operator new to do so). Then, re-initializing an object would be as simple as: this = new(this) typeof(this); (assuming the runtime doesn't do anything too weird in _d_new)
 And if that's the case you might want to think about making the object a 
 struct (so a value-type, allocated on the stack) anyway.

Good point. Sean
Sep 08 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Sean Kelly wrote:
 [snip]

 Or if there's some reason that the object must be re-initialized in
 place--say, to preserve its address.  One could argue that this
 necessity indicates a poor program design, but I imagine there are cases
 where it may apply.

Or you might just be dealing with thousands of frequently created and destroyed tiny, tiny objects and yes the overhead of allocating/deallocating *is* an issue. Like pretty sparkly particles -- free lists are your friend! :)
 For what it's worth, this would be quite easy to accomplish if D
 supported placement new as a default construction method (rather than
 requiring the user to override operator new to do so).  Then,
 re-initializing an object would be as simple as:
 
 this = new(this) typeof(this);
 
 (assuming the runtime doesn't do anything too weird in _d_new)

That makes me uneasy because then you can't overload new(void*) for anything. Maybe... void* inplace(TypeInfo ti, size_t size, void* custom_arg) { return custom_arg; } this = new.inplace(this) typeof(this); So make a special case of the unified function call syntax such that if you have a function whose first two arguments are (TypeInfo,size_t), then it can be called as a "member" of new. This allows classes to override new as necessary, whilst still providing a way to do more general overloads.
 And if that's the case you might want to think about making the object
 a struct (so a value-type, allocated on the stack) anyway.


Sorry, pretty sparkly particles must persist across stack frames :( -- Daniel
Sep 08 2007
parent Sean Kelly <sean f4.ca> writes:
Daniel Keep wrote:
 
 And if that's the case you might want to think about making the object
 a struct (so a value-type, allocated on the stack) anyway.


Sorry, pretty sparkly particles must persist across stack frames :(

It's possible to use 'new' for structs too :-p Sean
Sep 09 2007
prev sibling parent Ingo Oeser <ioe-news rameria.de> writes:
Sean Kelly wrote:

 Nathan Reed wrote:
 Using a new instance of the object for each iteration of the loop is
 really what you're doing /conceptually/, anyway...so, I wouldn't worry
 about the allocation performance too much unless you've profiled the app
 and established that it is a bottleneck.

Or if there's some reason that the object must be re-initialized in place--say, to preserve its address. One could argue that this necessity indicates a poor program design, but I imagine there are cases where it may apply.

Just to support Seans argument here... One example from driver development: Some on-card descriptor, you get mapped via IO memory. The class would be your driver instance for this card and your descriptor a struct or array member in that class. You have to re-initialize that descriptor or at least part of after receive. One usually does that in some cleanup run for many at once. Network Interface Cards (NICs) often work that way. Best Regards Ingo Oeser
Sep 09 2007
prev sibling parent Regan Heath <regan netmail.co.nz> writes:
mandel wrote:
 Hi,
 
 I have some big classes with lots of member variables
 that need to be reset to theire initial value.
 Therefore I thought about a more reliable way to
 accomplish this, because it's hard to keep track
 of variables I have added.
 It also looks bloated to assign all values manually.
 
 class Foo
 {
 	uint x;
 	char[] name = "world";
 //problematic:
 	const uint y;
 	char[1024] buffer;
 	
 	void reset()
 	{
 		scope tmp = new typeof(this);
 		foreach(i, x;  tmp.tupleof)
 		{
 			this.tupleof[i] = x;
 		}
 	}
 }
 
 The problem is that I have to avoid
 to try to set const values and static arrays.
 
 How can this be done?

How about putting the member variables you want to reset inside a struct inside the class, eg. import std.stdio; class Foo { struct FooData { int a = 6; } FooData data; int a() { return data.a; } void reset() { data = FooData.init; } } void main() { auto f = new Foo(); writefln(f.a); f.data.a = 5; writefln(f.a); f.reset(); writefln(f.a); } The proposed "alias data this" could later be used to bring the members of FooData into the scope of Foo allowing you to access them as "f.a" without property methods. Regan
Sep 10 2007