View mode: basic / threaded / horizontal-split · Log in · Help
March 14, 2011
Iterating over an enum associative array
Hey,

I'm having some problems iterating over an enumerated associative array.
It comes up with this error at compile time:
> Internal error: e2ir.c 4835
I cut the code down to this:

> import std.stdio;
>
> enum int[string] assoc = [";": 0, "=": 1, "+": 2, "-": 2, "*": 3, 
"/": 3];
>
> void main()
> {
> 	foreach(op; assoc.byKey())
> 		writefln("op: %s", op);
> }

What does this mean/how can I get this to work?

Thanks,
Nebster
March 14, 2011
Re: Iterating over an enum associative array
On 03/14/2011 12:21 PM, Nebster wrote:
> Hey,
>
> I'm having some problems iterating over an enumerated associative array.
> It comes up with this error at compile time:
>>  Internal error: e2ir.c 4835
> I cut the code down to this:
>
>>  import std.stdio;
>>
>>  enum int[string] assoc = [";": 0, "=": 1, "+": 2, "-": 2, "*": 3, "/": 3];
>>
>>  void main()
>>  {
>>  foreach(op; assoc.byKey())
>>  writefln("op: %s", op);
>>  }
>
> What does this mean/how can I get this to work?

There are problems with associative array constants. I'm not 100% sure this is 
the source of your error, though. Anyway, the following works fine, using the 
module's "static this" constructor:

static int[string] assoc;
static this () {
    assoc = [";": 0, "=": 1, "+": 2, "-": 2, "*": 3, "/": 3];
}
static enum seq = [1,2,3];

unittest {
    foreach(op ; assoc.byKey())
        writefln("op: %s", op);
    foreach(n ; seq)
        writefln("n: %s", n);
}
==>
op: *
op: +
op: -
op: /
op: ;
op: =
n: 1
n: 2
n: 3

You can use this trick each time you need a D module to hold predefined and/or 
precomputed data (meaning, you need D to play the role of a data description 
language).
This is not needed if said data is plain simple literal values. As you see, dmd 
does not consider an associative array to be plain simple literal, even when it 
obviously is; but a sequential array, yes.


A side note: constant struct data can be directly defined at the module 
top-level, at least in simple cases. But (for any reason), dmd in fact does not 
create a single constant value that will be used everywhere you write its name. 
Instead, it re-creates the constant value at each place you write it. Aside the 
possible cost (?), this can create bugs if you count on it be unique:

struct S { int i; }
enum S* ps0 = &(S(0)), ps1 = &(S(1));

unittest {
    S* ps;
    if (true) ps = ps0; else ps= ps1;
    assert (*ps == *ps0);           // indeed
//~     assert (ps == ps0);         // fail !!!
    writefln("%s != %s", ps,ps0);   // BFC95FE4 != BFC95FF0
}

The trick of using the module's static this clause also solves this issue.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com
March 14, 2011
Re: Iterating over an enum associative array
== Quote from Nebster (Evil.Nebster@gmail.com)'s article
> Hey,
> I'm having some problems iterating over an enumerated associative array.
> It comes up with this error at compile time:
>  > Internal error: e2ir.c 4835
> I cut the code down to this:
>  > import std.stdio;
>  >
>  > enum int[string] assoc = [";": 0, "=": 1, "+": 2, "-": 2, "*": 3,
> "/": 3];
>  >
>  > void main()
>  > {
>  > 	foreach(op; assoc.byKey())
>  > 		writefln("op: %s", op);
>  > }
> What does this mean/how can I get this to work?
> Thanks,
> Nebster


That's a rather cryptic error message. Hopefully someone smarter than I can trace
down why this doesn't have better error reporting. I suspect the problem has
something to do with CTFE. Because you're using an enum, D assumes you want its
value to be computed at compile time. However, currently, associative arrays can
not be evaluated at compile time. Using a static this to initialize the value at
runtime, as already suggested, should solve your issue.
March 14, 2011
Re: Iterating over an enum associative array
On 14/03/2011 14:38, Peter Lundgren wrote:
> == Quote from Nebster (Evil.Nebster@gmail.com)'s article
>> Hey,
>> I'm having some problems iterating over an enumerated associative array.
>> It comes up with this error at compile time:
>>   >  Internal error: e2ir.c 4835
>> I cut the code down to this:
>>   >  import std.stdio;
>>   >
>>   >  enum int[string] assoc = [";": 0, "=": 1, "+": 2, "-": 2, "*": 3,
>> "/": 3];
>>   >
>>   >  void main()
>>   >  {
>>   >  	foreach(op; assoc.byKey())
>>   >  		writefln("op: %s", op);
>>   >  }
>> What does this mean/how can I get this to work?
>> Thanks,
>> Nebster
>
>
> That's a rather cryptic error message. Hopefully someone smarter than I can trace
> down why this doesn't have better error reporting. I suspect the problem has
> something to do with CTFE. Because you're using an enum, D assumes you want its
> value to be computed at compile time. However, currently, associative arrays can
> not be evaluated at compile time. Using a static this to initialize the value at
> runtime, as already suggested, should solve your issue.

That's not the cryptic part, its the name of the source file and line 
number, its tripping up here:

AssocArrayLiteralExp::toElem
//...
Type *t = type->toBasetype()->mutableOf();
assert(t->ty == Taarray);			//line 4835

Though to me that whole function looks like a pile of random abbreviations.
March 14, 2011
Re: Iterating over an enum associative array
I am back.

Nebster:

> I'm having some problems iterating over an enumerated associative array.
> It comes up with this error at compile time:
>  > Internal error: e2ir.c 4835

Added:
http://d.puremagic.com/issues/show_bug.cgi?id=5734

Bye,
bearophile
Top | Discussion index | About this forum | D home