www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Accessing members through pointers to structs (also, CTFE associative

reply Ali <something something.com> writes:
Hi, Long time watcher and recently started playing with D a bit 
more. Ran in to a couple of snags that I'll combine in one post. 
It involves a data set that contains a list of strings. Each 
string represents a Room name. What I'm trying to do is pluck out 
the room names and also calculate the frequency each letter 
occurs in a name, per room.

First problem is to do with pointers to structs. Here's the code:

static immutable rooms = 
import("data.txt").split("\n").map!parse.array;

static Tuple!(const(Room*), "room", int[char], 
"frequencies")[rooms.length] data;
static this() {
     foreach (i, room; rooms) {
         data[i].room = &room;
         // Also calculate frequencies, but that's not important 
yet.
     }
}

void main() {
     foreach (d; data) {
         d.room.name.writeln; // <-- How do I access name here??
     }
}

I've tried d.(*room).name but that didn't work. There's no arrow 
operator. I've tried making my tuple a ref Room instead, but 
that's a no go as well. I can copy the Room object directly in to 
the tuple, but since it's already there in static immutable data 
I'd rather just have a pointer to it.

Is there a way to do that?

Second problem is to do with associative arrays. At first the 
Room object had a frequencies object in it (ie: int[char] <- 
number of times a character appears in the name).

In my parse function, if I add a foreach loop that loops through 
the letters in the room's name, and adds populates an associative 
array like so:

Room parse(string line) {
     immutable name = // blah
     int[char] frequencies;
     foreach (letter; name) {
         frequencies[letter] += 1
     }
     return Room(name, frequencies);
}

pragma(msg, rooms); // <- this works!

In the above case the pragma actually prints out all the Room 
objects, with their respective frequencies calculated correctly. 
But *after* it has printed it out, then a whole list of 
compilation errors that all look like this:

Error: non-constant expression ['d':1, 'r':3, 'x':1, 'e':1, 
'v':2, 'k':2, 'z':1, 't':1, 'u':1, 'p':2, 'c':1, 's':1, 'f':2, 
'i':2]

But it seems that it was calculated correctly, it just can't be 
assigned to the actual variable.

My current workaround includes taking frequencies out of the Room 
struct and calculating them inside a module constructor (hence 
the first question on the Tuple and Room *)

Are there other workarounds?

Cheers, and thanks for any help!
- Ali
Dec 13 2016
next sibling parent reply drug007 <drug2004 bk.ru> writes:
On 13.12.2016 23:30, Ali wrote:
 Hi, Long time watcher and recently started playing with D a bit more.
 Ran in to a couple of snags that I'll combine in one post. It involves a
 data set that contains a list of strings. Each string represents a Room
 name. What I'm trying to do is pluck out the room names and also
 calculate the frequency each letter occurs in a name, per room.

 First problem is to do with pointers to structs. Here's the code:

 static immutable rooms = import("data.txt").split("\n").map!parse.array;

 static Tuple!(const(Room*), "room", int[char],
 "frequencies")[rooms.length] data;
 static this() {
      foreach (i, room; rooms) {
          data[i].room = &room;
          // Also calculate frequencies, but that's not important yet.
      }
 }

 void main() {
      foreach (d; data) {
          d.room.name.writeln; // <-- How do I access name here??
      }
 }

 I've tried d.(*room).name but that didn't work. There's no arrow
I'm sleepy, sorry for quick and probable wrong answer - try (*d.room).name
Dec 13 2016
parent reply Ali <something something.com> writes:
On Tuesday, 13 December 2016 at 21:08:31 UTC, drug007 wrote:
 (*d.room).name
Oh yeah, tried that too. That at least compiles but gives a runtime exception (bad address).
Dec 13 2016
parent bauss (wtf happend to my name took some old cached title LOL??) writes:
On Tuesday, 13 December 2016 at 21:21:34 UTC, Ali wrote:
 On Tuesday, 13 December 2016 at 21:08:31 UTC, drug007 wrote:
 (*d.room).name
Oh yeah, tried that too. That at least compiles but gives a runtime exception (bad address).
Try (*cast(Room*)(d.room)).name
Dec 13 2016
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/13/2016 12:30 PM, Ali wrote:

     foreach (i, room; rooms) {
         data[i].room = &room;
That is the address of the local variable room. You need to use 'ref' there: foreach (i, ref room; rooms) {
 - Ali
Ali "the real one :o)"
Dec 13 2016
parent reply Ali <something something.com> writes:
On Tuesday, 13 December 2016 at 21:33:11 UTC, Ali Çehreli wrote:
 On 12/13/2016 12:30 PM, Ali wrote:

     foreach (i, room; rooms) {
         data[i].room = &room;
That is the address of the local variable room. You need to use 'ref' there: foreach (i, ref room; rooms) {
 - Ali
Ahh true!! Cheers. Now about that second part of my problem ....
 Ali
 "the real one :o)"
Haha :)
Dec 13 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/13/2016 01:36 PM, Ali wrote:

 Now about that second part of my problem ....
I'm not entirely sure whether this should work but I think the problem is with mutating the 'frequencies' member of an immutable element of 'rooms'. The error message means that those non-const expressions cannot be shared by a member of an immutable AA. I moved the frequencies to 'data' and hte following worked. Used 'shared static this' so that the data is populated per application instead of per thread. Additionally, the 'd.room.name.writeln' expression works just fine with DMD64 D Compiler v2.072.1. import std.algorithm: splitter, map; import std.array: array; import std.typecons: Tuple; import std.stdio: writeln; static immutable Room[] rooms = import("data.txt").splitter.map!parse.array; struct Room { string name; } static Tuple!(const(Room*), "room", int[char], "frequencies")[rooms.length] data; shared static this() { foreach (i, ref room; rooms) { data[i].room = &room; foreach (letter; room.name) { data[i].frequencies[letter]++; } } } Room parse(string line) pure { immutable name = line; return Room(name); } void main() { foreach (d; data) { d.room.name.writeln; d.frequencies.writeln; } } Ali
Dec 13 2016
parent reply Ali <something something.com> writes:
On Tuesday, 13 December 2016 at 23:29:31 UTC, Ali Çehreli wrote:
 On 12/13/2016 01:36 PM, Ali wrote:

 Now about that second part of my problem ....
I'm not entirely sure whether this should work but I think the problem is with mutating the 'frequencies' member of an immutable element of 'rooms'. The error message means that those non-const expressions cannot be shared by a member of an immutable AA.
I'm not sure I fully follow here. Because the variable in the parse function is not immutable and the frequencies member is not "created" yet, so to say. So after I create the frequencies object, I assign it to the member of a Room object. The following illustrates this more clearly I think: struct A { int x; } struct B { int[char] x; } auto f1() { int x; x = 3; return A(x); } auto f2() { int[char] x; x['A'] = 2; return B(x); } static immutable a = f1(); static immutable b = f2(); pragma(msg, a); pragma(msg, b); This fails to compile with "Error: non-constant expression ['A':2]". But, the pragma(msg) prints out the correct information for both a and b. What's the deal with static immutable associative arrays and D anyway? Is there some kind of roadmap somewhere or bugs that need to be fixed before they work properly in D? I'm confused because it seems like the data actually gets inside the struct object that has an AA as a member, but then the compiler just decides "nah, just kidding, this ain't actually ok. bye".
 I moved the frequencies to 'data' and hte following worked.
Yeah that is indeed the workaround I mentioned and hence the need for the pointer to room problem I was having :p This does work. But I guess I'm just looking for a more ideal solution. Thanks for all the help so far! :)
Dec 14 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/14/2016 04:02 AM, Ali wrote:
 On Tuesday, 13 December 2016 at 23:29:31 UTC, Ali Çehreli wrote:
 On 12/13/2016 01:36 PM, Ali wrote:

 Now about that second part of my problem ....
I'm not entirely sure whether this should work but I think the problem is with mutating the 'frequencies' member of an immutable element of 'rooms'. The error message means that those non-const expressions cannot be shared by a member of an immutable AA.
I'm not sure I fully follow here. Because the variable in the parse function is not immutable and the frequencies member is not "created" yet, so to say. So after I create the frequencies object, I assign it to the member of a Room object. The following illustrates this more clearly I think: struct A { int x; } struct B { int[char] x; } auto f1() { int x; x = 3; return A(x); } auto f2() { int[char] x; x['A'] = 2; return B(x); } static immutable a = f1(); static immutable b = f2(); pragma(msg, a); pragma(msg, b); This fails to compile with "Error: non-constant expression ['A':2]". But, the pragma(msg) prints out the correct information for both a and b.
Yeah, I think the compiler is confused because the function is called in a non-const context during the initialization of an immutable object. I would open an issue: https://issues.dlang.org/enter_bug.cgi?product=D Ali
Dec 15 2016
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Thursday, 15 December 2016 at 19:30:08 UTC, Ali Çehreli wrote:

 Yeah, I think the compiler is confused because the function is 
 called in a non-const context during the initialization of an 
 immutable object.

 I would open an issue:

   https://issues.dlang.org/enter_bug.cgi?product=D

 Ali
You cannot Assign Associative Arrays at compile-time. Because those are defined by druntime have no stable ABI.
Dec 15 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/15/2016 05:30 PM, Stefan Koch wrote:
 On Thursday, 15 December 2016 at 19:30:08 UTC, Ali Çehreli wrote:

 Yeah, I think the compiler is confused because the function is called
 in a non-const context during the initialization of an immutable object.

 I would open an issue:

   https://issues.dlang.org/enter_bug.cgi?product=D

 Ali
You cannot Assign Associative Arrays at compile-time. Because those are defined by druntime have no stable ABI.
Thanks Stefan but at least there should be a better diagnostic instead of the confusing current situation that Ali experienced. Ali
Dec 15 2016
parent Ali <something something.com> writes:
On Friday, 16 December 2016 at 01:48:59 UTC, Ali Çehreli wrote:
 On 12/15/2016 05:30 PM, Stefan Koch wrote:
 On Thursday, 15 December 2016 at 19:30:08 UTC, Ali Çehreli 
 wrote:

 Yeah, I think the compiler is confused because the function 
 is called
 in a non-const context during the initialization of an 
 immutable object.

 I would open an issue:

   https://issues.dlang.org/enter_bug.cgi?product=D

 Ali
You cannot Assign Associative Arrays at compile-time. Because those are defined by druntime have no stable ABI.
Thanks Stefan but at least there should be a better diagnostic instead of the confusing current situation that Ali experienced. Ali
Ah kay. Confusing :) Thanks again!
Dec 17 2016