Thread overview
pragma msg field name?
Jun 27, 2023
Chris Katko
Jun 27, 2023
Ali Çehreli
Jun 27, 2023
Chris Katko
Jun 27, 2023
Chris Katko
Jun 27, 2023
Adam D Ruppe
Jun 27, 2023
Chris Katko
Jun 27, 2023
Jonathan M Davis
Jun 27, 2023
Dennis
Jun 27, 2023
Adam D Ruppe
June 27, 2023

inside a static foreach I can do

enum rep;

class myObject{
int field1, field2, field3;

static foreach(field; getSymbolsByUDA!(typeof(this), rep))
{
	pragma(msg, field);  // fails
	pragma(msg, fullyQualifiedName!field); // works
}
}

error for pragma(msg, field)

source/app.d(33,16): Error: value of `this` is not known at compile time
source/app.d(33,4):        while evaluating `pragma(msg, field)`

[repeating for every variable in the class]

How do I get just the field name? And why does it think this is a run-time value? I need to wrap it in some sort of template?

All I see in std.traits docs are: fullyQualifiedName mangledName moduleName packageName

June 26, 2023
On 6/26/23 21:25, Chris Katko wrote:

> How do I get just the field name?

I know .tupleof, which you can typeof() as well:

class myObject{
    int field1, field2, field3;

    static foreach(field; typeof(this).tupleof)
    {
        pragma(msg, field.stringof);
    }

    static foreach(MemberType; typeof(typeof(this).tupleof)) {
        pragma(msg, MemberType);
    }
}

The output:

field1
field2
field3
int
int
int

I had to consult what I wrote years ago:

  http://ddili.org/ders/d.en/tuples.html#ix_tuples..tupleof

Ali

June 26, 2023
On Monday, June 26, 2023 10:25:13 PM MDT Chris Katko via Digitalmars-d-learn wrote:
> inside a static foreach I can do
>
> ```
> enum rep;
>
> class myObject{
> int field1, field2, field3;
>
> static foreach(field; getSymbolsByUDA!(typeof(this), rep))
> {
>   pragma(msg, field);  // fails
>   pragma(msg, fullyQualifiedName!field); // works
> }
> }
> ```
>
> error for pragma(msg, field)
> ```
> source/app.d(33,16): Error: value of `this` is not known at
> compile time
> source/app.d(33,4):        while evaluating `pragma(msg, field)`
>
> [repeating for every variable in the class]
> ```
>
> How do I get just the field name? And why does it think this is a run-time value? I need to wrap it in some sort of template?
>
> All I see in std.traits docs are: fullyQualifiedName mangledName moduleName packageName

Well, on my machine, once the import for std.traits is added, that code compiles but prints nothing, so I suspect that you paired it down too much (likely related to the fact that none of the fields in question actually have UDAs on them).

However, I would point out that getSymbolsByUDA gives you symbols, not strings, whereas pragma(msg, ...) wants a string. fullyQualifiedName works, because it results in a string. You can see what field is by using typeof on it, but presumably, it's complaining about being a runtime value, because when you use it, it's trying to evaluate the symbol (e.g. get the value of field1). Using .stringof on field will give you a string, though I don't know if it'll give you what you're looking for. In general, FieldNameTuple would probably be what you would want for getting the names of the fields in a struct or class, though obviously, that wouldn't be just getting the ones with a specific UDA.

- Jonathan M Davis



June 27, 2023

On Tuesday, 27 June 2023 at 04:56:19 UTC, Ali Çehreli wrote:

>

On 6/26/23 21:25, Chris Katko wrote:

>

How do I get just the field name?

I know .tupleof, which you can typeof() as well:

class myObject{
int field1, field2, field3;

static foreach(field; typeof(this).tupleof)
{
    pragma(msg, field.stringof);
}

static foreach(MemberType; typeof(typeof(this).tupleof)) {
    pragma(msg, MemberType);
}

}

The output:

field1
field2
field3
int
int
int

I had to consult what I wrote years ago:

http://ddili.org/ders/d.en/tuples.html#ix_tuples..tupleof

Ali

That seems to do the trick, I was really not expecting so much text just to get something so simple!

At the moment I'm trying to take variables with an attribute (rep) and then make a duplicate of them inside the struct. It seems to work. If I had duplicate names, it fails. However, the new fields don't appear to be showing up on a second enumeration:

enum rep;
struct multiplayerObject2
	{
	@rep ushort type;
	@("rep2") ushort type2;
	float x, y;
	
	static foreach(t; typeof(this).tupleof)
		{
		// no if rep/rep2 here, i'm just testing:
		pragma(msg, t.stringof); // does not see any new fields!
		mixin("bool " ~ t.stringof ~ "25;"); // copy the fieldname with a suffix
		}

	pragma(msg, "-----separator-----");

	static foreach(t; typeof (this).tupleof) // again
		{
		pragma(msg, t.stringof); // does not see any new fields!
		}
	}

output

type
type2
x
y
-----separator-----
type
type2
x
y

However, if I do try to force the names to duplicate (say "type2") I get an error involving some sort of __anonymous subobject.

source/app.d-mixin-123(123,6): Error: variable `app.multiplayerObject2.__anonymous.type2` conflicts with variable `app.multiplayerObject2.type2` at source/app.d(116,19)

I also never realized you could put a static/static foreach inside the body of a struct (and not a function) so I'm still having trouble wrapping my head around that. Is it processing top-down?

Jonathan M Davis: Yeah, it does what I listed if you add the UDA to it.

June 27, 2023
On Tuesday, 27 June 2023 at 04:25:13 UTC, Chris Katko wrote:
> How do I get just the field name?

__traits(identifier, field)

> And why does it think this is a run-time value?

It is the same as if you wrote `Class.field`
June 27, 2023

On Tuesday, 27 June 2023 at 05:03:01 UTC, Jonathan M Davis wrote:

>

However, I would point out that getSymbolsByUDA gives you symbols, not strings, whereas pragma(msg, ...) wants a string.

For some time now, it accepts any number of objects, which will all be converted to strings and concatenated to form the message. The same applies to static assert().

June 27, 2023

Does anyone know why the new variables don't show up after the static foreach?

I have a struct, it has some marked fields. I want to note those fields at compile time and make some similarly named fields like myField becomes myField__replicated.

The code doesn't have to be inside the struct/class itself. It could be:

auto replicatedObject = makeReplicated!(myObject);

for example.

I'm not sure the high-level best way right now, as I'm currently having issues with the nitty-gritty implementation of templates.

snippetcode (drop right into run.dlang.io):

import std;

struct multiplayerObject2
	{
	ushort type;
	ushort type2;
	float x, y;
	
	static foreach(t; typeof(this).tupleof)
		{
		pragma(msg, t.stringof);
		mixin("bool " ~ t.stringof ~ "25;"); // copy the fieldname with a suffix
		}

	pragma(msg, "-----separator-----");

	static foreach(t; typeof (this).tupleof) // again
		{
		pragma(msg, t.stringof); // does not see any new fields!
		}
	}

void main()
{

}
// Output
type
type2
x
y
-----separator-----
type
type2
x
y
June 27, 2023
On Tuesday, 27 June 2023 at 22:20:22 UTC, Chris Katko wrote:
> 		pragma(msg, t.stringof); // does not see any new fields!

D's declarations are all order-independent, in theory those foreaches are done simultaneously, so it is kinda a race condition.

In practice, the compiler does them in two passes but both based on the same initial state.

Adding stuff and then reflecting over the stuff you add must be done as explicit steps on the outside, like you can make a `struct step1 {}` then `alias step2 = transform!step1;` then `alias step3 = transform_again!step2;` or something.
June 27, 2023
On Tuesday, 27 June 2023 at 22:34:17 UTC, Adam D Ruppe wrote:
> On Tuesday, 27 June 2023 at 22:20:22 UTC, Chris Katko wrote:
>> 		pragma(msg, t.stringof); // does not see any new fields!
>
> D's declarations are all order-independent, in theory those foreaches are done simultaneously, so it is kinda a race condition.

Thank you, that's what I thought, but then I started adding them and there was no warning and I was like "wait... is this top-down???"

>
> In practice, the compiler does them in two passes but both based on the same initial state.
>
> Adding stuff and then reflecting over the stuff you add must be done as explicit steps on the outside, like you can make a `struct step1 {}` then `alias step2 = transform!step1;` then `alias step3 = transform_again!step2;` or something.

Okay again makes more sense. The amount of stuff that was "kinda" working, plus learning through tiny 3 liner code snippets in docs, was making my brain explode a bit.

A constructor/factory pattern for this makes way more sense.

Sometimes it's hard to tell where things are symbolic / functional, verses procedural/linear.


June 27, 2023

On 6/27/23 6:34 PM, Adam D Ruppe wrote:

>

On Tuesday, 27 June 2023 at 22:20:22 UTC, Chris Katko wrote:

>

        pragma(msg, t.stringof); // does not see any new fields!

D's declarations are all order-independent, in theory those foreaches are done simultaneously, so it is kinda a race condition.

In particular the practice of adding new members based on introspecting other members is suspect. I've done it too, but I think it probably would be better if we didn't allow this kind of stuff, or came up with a sane way to do this.

This leads to all kinds of weird stuff. Like if you instantiate a template with the current type being compiled, that template is locked to that type at that point in compilation. Then you look at it outside the type, and the value is already cached.

-Steve