Thread overview | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 03, 2015 Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Given class C { // lots of members } and a function f(C c) { } is there a generic way, perhaps through reflection, to reset (inside f) all members of `c` to their default values? Something along foreach(ref member; __traits(allMembers, c)) { member = typeof(member).init; } |
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | Haven't compiled but it should look something like this: foreach(member; __traits(allMembers, typeof(c))) __traits(getMember, c, member) = typeof(__traits(getMember, c, member)).init; |
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On Thursday, 3 December 2015 at 21:04:00 UTC, Nordlöw wrote: > Given > > class C > { > // lots of members > } > > and a function > > f(C c) > { > } > > is there a generic way, perhaps through reflection, to reset (inside f) all members of `c` to their default values? Something along > > foreach(ref member; __traits(allMembers, c)) > { > member = typeof(member).init; > } Back in 2007 it didn't seem to exist a standard way of doing this: http://forum.dlang.org/post/fbs9eg$721$1@digitalmars.com Is tupleof the best contender? |
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sebastiaan Koppe | On Thursday, 3 December 2015 at 21:08:30 UTC, Sebastiaan Koppe wrote:
> Haven't compiled but it should look something like this:
>
> foreach(member; __traits(allMembers, typeof(c)))
> __traits(getMember, c, member) = typeof(__traits(getMember, c, member)).init;
Need to assert that not a function and mutability (std.traits.isMutable)
|
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On Thursday, 3 December 2015 at 21:04:00 UTC, Nordlöw wrote:
> is there a generic way, perhaps through reflection, to reset (inside f) all members of `c` to their default values?
You could always copy the init back over it. For a struct:
s = Struct.init;
for a class... well, the code is a lot uglier and liable to break if you don't have the static type right. Maybe better off wrapping the class members in a struct and doing it that way.
|
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On Thursday, 3 December 2015 at 21:04:00 UTC, Nordlöw wrote:
> Given
>
> class C
> {
> // lots of members
> }
>
> and a function
>
> f(C c)
> {
> }
>
> is there a generic way, perhaps through reflection, to reset (inside f) all members of `c` to their default values? Something along
>
> foreach(ref member; __traits(allMembers, c))
> {
> member = typeof(member).init;
> }
import std.traits;
foreach(i, member; FieldNameTuple!C)
{
alias FieldType = Fields!C[i];
static if(isMutable!FieldType)
__traits(getMember, c, member) = FieldType.init;
}
However, it doesn't work in the presence of private fields. A better alternative is probably to `destroy` the instance then `emplace` to default-construct a new instance over it.
|
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On Thursday, 3 December 2015 at 21:13:59 UTC, Nordlöw wrote:
> Need to assert that not a function and mutability (std.traits.isMutable)
Yeah you need to do that.
|
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | On Thursday, 3 December 2015 at 21:04:00 UTC, Nordlöw wrote:
> Something along
>
> foreach(ref member; __traits(allMembers, c))
> {
> member = typeof(member).init;
> }
This works for me:
void resetAllMembers(T)(T c)
if (is(T == class))
{
foreach (ref m; c.tupleof)
{
import std.traits : isMutable;
alias M = typeof(m);
static if (isMutable!M)
{
m = M.init;
}
}
}
|
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nordlöw | 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"); } } An object reference is just a pointer, but we can't directly cast it. So we make a pointer to it and cast that; the type system allows it. Now we can access the data that the object reference refers to directly. `o.classinfo` gets the runtime type information object for the actual class that `o` belongs to. The `init` property gives you a single blob of bytes representing the default field values of that class. So we copy that over into the object. To finish up, if the type has a default constructor, we invoke it. We don't have a way to identify any other constructors that we could invoke. This is usually not a good thing to do, but if you really need to, you can. |
December 03, 2015 Re: Reset all Members of a Aggregate Instance | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Wright | 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?
|
Copyright © 1999-2021 by the D Language Foundation