Jump to page: 1 2 3
Thread overview
Reset all Members of a Aggregate Instance
Dec 03, 2015
Nordlöw
Dec 03, 2015
Sebastiaan Koppe
Dec 03, 2015
Nordlöw
Dec 03, 2015
Sebastiaan Koppe
Dec 03, 2015
Nordlöw
Dec 03, 2015
Adam D. Ruppe
Dec 03, 2015
Jakob Ovrum
Dec 03, 2015
Nordlöw
Dec 03, 2015
Chris Wright
Dec 03, 2015
Nordlöw
Dec 03, 2015
Chris Wright
Dec 08, 2015
Daniel Murphy
Dec 08, 2015
Chris Wright
Dec 08, 2015
Marc Schütz
Dec 04, 2015
Tofu Ninja
Dec 04, 2015
Tofu Ninja
Dec 04, 2015
Enamex
Dec 05, 2015
Observer
Dec 05, 2015
Ali Çehreli
Dec 05, 2015
Chris Wright
Dec 05, 2015
Jakob Ovrum
December 03, 2015
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
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
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
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
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
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
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
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
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
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?
« First   ‹ Prev
1 2 3