Thread overview
tupleof of class instance... but enumerate _all_ the instance variables
2 days ago
Andy Valencia
2 days ago
monkyyy
2 days ago
Nick Treleaven
1 day ago
Andy Valencia
1 day ago
Ali Çehreli
5 hours ago
Andy Valencia
48 minutes ago
bauss
2 days ago

tupleof works for struct and class instances, but explicitly documents that it ignores instance variables from any superclass.

Is there any way to enumerate all the instance variables, not just the ones present in the specific instance's class?

Thanks,
Andy

2 days ago

On Friday, 27 June 2025 at 22:33:25 UTC, Andy Valencia wrote:

>

tupleof works for struct and class instances, but explicitly documents that it ignores instance variables from any superclass.

Is there any way to enumerate all the instance variables, not just the ones present in the specific instance's class?

Thanks,
Andy

__traits(allMembers but it wont be useful, and youll need to find some other filter, etc. etc.

2 days ago

On Friday, 27 June 2025 at 22:33:25 UTC, Andy Valencia wrote:

>

tupleof works for struct and class instances, but explicitly documents that it ignores instance variables from any superclass.

Is there any way to enumerate all the instance variables, not just the ones present in the specific instance's class?

Thanks,
Andy

This is one way:

import std;

class C
{
    int x, y;
}

class D : C
{
    int a, b;
}

void main()
{
    D d = new D;
    static if (is(D Bases == super))
    {
        static foreach (B; AliasSeq!(D, Bases))
        {
            pragma(msg, B);
            static foreach (field; B.tupleof)
            {{
                enum s = __traits(identifier, field);
                pragma(msg, s);
                // access runtime field
                __traits(getMember, d, s)++;
            }}
        }
    }
    assert([d.tupleof, (cast(C)d).tupleof] == [1,1,1,1]);
}

Pragma output:

D
a
b
C
x
y
1 day ago

On Saturday, 28 June 2025 at 10:41:47 UTC, Nick Treleaven wrote:

>
static if (is(D Bases == super))

Wow. I can't find that in any of my references on D... including the language spec itself. Nor in Phobos source... what is a "D Bases", please? Uncle!

Andy

1 day ago
On 6/28/25 8:50 PM, Andy Valencia wrote:
> On Saturday, 28 June 2025 at 10:41:47 UTC, Nick Treleaven wrote:
>
>>     static if (is(D Bases == super))
>
> Wow.  I can't find that in _any_ of my references on D...

Not this time. I have it here:

  https://ddili.org/ders/d.en/is_expr.html

Search for 'super' on that page.

> including the
> language spec itself.

It's the 'is expression' in the spec:

  https://dlang.org/spec/expression.html#is_expression

> Nor in Phobos source... what is a "D Bases",

It's not "D Bases" but the is expression is written in this form:

  is ( Type Identifier == TypeSpecialization )

So, 'D' is Type; 'Bases' is Identifier, and 'super' is TypeSpecialization.

> please?  Uncle!

All of that is described in not-very-human friendly language at the links above. :)

Ali

1 day ago

On Sunday, 29 June 2025 at 03:50:03 UTC, Andy Valencia wrote:

>

On Saturday, 28 June 2025 at 10:41:47 UTC, Nick Treleaven wrote:

>
static if (is(D Bases == super))

Wow. I can't find that in any of my references on D... including the language spec itself. Nor in Phobos source... what is a "D Bases", please? Uncle!

Ali's given a great answer, I'll just add that there's a Phobos trait I could've used which reads better and avoids the initial static if nesting (where the condition is always true):

alias Bases = BaseClassesTuple!D;

That also avoids listing any interfaces the class may implement.

https://dlang.org/phobos/std_traits.html#BaseTypeTuple

5 hours ago

On Saturday, 28 June 2025 at 10:41:47 UTC, Nick Treleaven wrote:

>
        static foreach (field; B.tupleof)
        {{
            enum s = __traits(identifier, field);
            pragma(msg, s);
            // access runtime field
            __traits(getMember, d, s)++;
        }}

One last question, if you would? Why the double open braces? I tried, and got:

tst57.d(26): Error: declaration tst57.main.s is already defined
tst57.d(26): variable s is defined here

if I changed to a single open brace?

Thanks again,
Andy

48 minutes ago

On Monday, 30 June 2025 at 16:37:01 UTC, Andy Valencia wrote:

>

On Saturday, 28 June 2025 at 10:41:47 UTC, Nick Treleaven wrote:

>
        static foreach (field; B.tupleof)
        {{
            enum s = __traits(identifier, field);
            pragma(msg, s);
            // access runtime field
            __traits(getMember, d, s)++;
        }}

One last question, if you would? Why the double open braces? I tried, and got:

tst57.d(26): Error: declaration tst57.main.s is already defined
tst57.d(26): variable s is defined here

if I changed to a single open brace?

Thanks again,
Andy

the static foreach will emit all code in scope, which means each iteration will emit the code in the scope, so you double brace it to create individual scopes that don't "overlap".