Thread overview
non-constant error for module AA"s
Jan 24, 2011
Andrej Mitrovic
Jan 24, 2011
spir
Jan 24, 2011
BlazingWhitester
Jan 25, 2011
Andrej Mitrovic
Jan 25, 2011
bearophile
Jan 25, 2011
spir
Jan 25, 2011
spir
January 24, 2011
Is this a bug?

import std.stdio;

string[string] values = ["abc":"abc", "def":"def"];

void main()
{
    string[string] values2 = ["abc":"abc", "def":"def"];
}


test.d(3): Error: non-constant expression ["abc":"abc","def":"def"]

What's non-constant about that expression?
January 24, 2011
On 01/24/2011 04:45 PM, Andrej Mitrovic wrote:
> Is this a bug?
>
> import std.stdio;
>
> string[string] values = ["abc":"abc", "def":"def"];
>
> void main()
> {
>      string[string] values2 = ["abc":"abc", "def":"def"];
> }
>
>
> test.d(3): Error: non-constant expression ["abc":"abc","def":"def"]
>
> What's non-constant about that expression?

Had the same issue, and yop, it's a bug, and filed: search the issue tracker.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

January 24, 2011
On 2011-01-24 17:45:03 +0200, Andrej Mitrovic said:

> Is this a bug?
> 
> import std.stdio;
> 
> string[string] values = ["abc":"abc", "def":"def"];
> 
> void main()
> {
>     string[string] values2 = ["abc":"abc", "def":"def"];
> }
> 
> 
> test.d(3): Error: non-constant expression ["abc":"abc","def":"def"]
> 
> What's non-constant about that expression?

It's because of D's implementation of AA, but you can make it work with enum, e.g. enum string[string] values = ["abc":"abc", "def":"def"]; // works just fine at compile time

January 25, 2011
On 1/24/11, BlazingWhitester <max.klyga@gmail.com> wrote:
> On 2011-01-24 17:45:03 +0200, Andrej Mitrovic said:
>
>> Is this a bug?
>>
>> import std.stdio;
>>
>> string[string] values = ["abc":"abc", "def":"def"];
>>
>> void main()
>> {
>>     string[string] values2 = ["abc":"abc", "def":"def"];
>> }
>>
>>
>> test.d(3): Error: non-constant expression ["abc":"abc","def":"def"]
>>
>> What's non-constant about that expression?
>
> It's because of D's implementation of AA, but you can make it work with enum, e.g. enum string[string] values = ["abc":"abc", "def":"def"]; // works just fine at compile time
>
>

It's interesting that enum works but immutable doesn't. enum will do, Thanks.
January 25, 2011
Andrej Mitrovic:

> It's interesting that enum works but immutable doesn't. enum will do, Thanks.

But there are some problems with enum AAs. Take a look at this little program:

enum int[int] aa = [1:2, 3:4];
int foo(int x) {
    return aa[x];
}
void main() {}


And the asm of foo():

_D4test3fooFiZi comdat
        push    EAX
        mov ECX,offset FLAT:_D10TypeInfo_i6__initZ
        mov EDX,offset FLAT:_D12TypeInfo_Hii6__initZ
        push    EAX
        push    4
        push    ECX
        push    4
        push    3
        push    2
        push    1
        push    2
        push    EDX
        call    near ptr __d_assocarrayliteralT
        add ESP,018h
        push    EAX
        call    near ptr __aaGetRvalue
        mov EAX,[EAX]
        add ESP,010h
        pop ECX
        ret

Bye,
bearophile
January 25, 2011
On Mon, 24 Jan 2011 10:45:03 -0500, Andrej Mitrovic wrote:

> Is this a bug?
> 
> import std.stdio;
> 
> string[string] values = ["abc":"abc", "def":"def"];
> 
> void main()
> {
>     string[string] values2 = ["abc":"abc", "def":"def"];
> }
> 
> 
> test.d(3): Error: non-constant expression ["abc":"abc","def":"def"]
> 
> What's non-constant about that expression?


My guess would be that using an AA literal is just syntax sugar for calling an AA construction function, and that said function isn't CTFEable.

When you specify an initial value for a global, that value must be a compile-time constant.  If it's not, as in this case, the correct thing to do is to use a module constructor:

  string[string] values;
  static this()
  {
      values = [ "abc":"abc", "def":"def" ];
  }

It is ONLY a good idea to use an enum array if you know you will be doing all lookups at compile time.  If the key you're looking for is just known at run time, the AA will be constructed anew for each lookup (I think), which is hideously expensive.

  enum string[string] values = [ "abc":"def", "ghi":"jkl" ];

  // This is fine, because it is done at compile time.
  // It's essentially the same as:  auto s = "def";
  auto s = values["abc"];

  // This is a no-no, because it evaluates to something
  // like:  auto aa = values; auto s = aa[key];
  auto key = "abc";
  auto s = values[key];

Here's an example program that demonstrates the difference.  On my machine, the enum AA version takes 22x longer than the "normal" AA version.


import std.datetime, std.stdio;


enum string[string] enumAA = [ "abc" : "abc", "def" : "def" ];

string[string] normalAA;
static this()
{
    normalAA = [ "abc" : "abc", "def" : "def" ];
}


void main()
{
    enum max = 10_000_000;
    StopWatch sw;
    string lookup1 = "abc";
    string lookup2 = "def";

    sw.start();
    foreach (i; 0 .. max)
    {
        auto a = enumAA[lookup1];
        auto b = enumAA[lookup2];
    }
    sw.stop();
    writeln(sw.peek().seconds);

    sw.reset();

    sw.start();
    foreach (i; 0 .. max)
    {
        auto a = normalAA[lookup1];
        auto b = normalAA[lookup2];
    }
    sw.stop();
    writeln(sw.peek().seconds);
}
January 25, 2011
On 01/25/2011 08:54 AM, bearophile wrote:
> Andrej Mitrovic:
>
>> It's interesting that enum works but immutable doesn't. enum will do, Thanks.
>
> But there are some problems with enum AAs. Take a look at this little program:
>
> enum int[int] aa = [1:2, 3:4];
> int foo(int x) {
>      return aa[x];
> }
> void main() {}
>
>
> And the asm of foo():
>
> _D4test3fooFiZi comdat
>          push    EAX
>          mov ECX,offset FLAT:_D10TypeInfo_i6__initZ
>          mov EDX,offset FLAT:_D12TypeInfo_Hii6__initZ
>          push    EAX
>          push    4
>          push    ECX
>          push    4
>          push    3
>          push    2
>          push    1
>          push    2
>          push    EDX
>          call    near ptr __d_assocarrayliteralT
>          add ESP,018h
>          push    EAX
>          call    near ptr __aaGetRvalue
>          mov EAX,[EAX]
>          add ESP,010h
>          pop ECX
>          ret
>
> Bye,
> bearophile

IIUC, the compiler re-defines the constant (enum) AA at use point. Why?

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

January 25, 2011
On 01/25/2011 09:13 AM, Lars T. Kyllingstad wrote:
> On Mon, 24 Jan 2011 10:45:03 -0500, Andrej Mitrovic wrote:
>
>> Is this a bug?
>>
>> import std.stdio;
>>
>> string[string] values = ["abc":"abc", "def":"def"];
>>
>> void main()
>> {
>>      string[string] values2 = ["abc":"abc", "def":"def"];
>> }
>>
>>
>> test.d(3): Error: non-constant expression ["abc":"abc","def":"def"]
>>
>> What's non-constant about that expression?
>
>
> My guess would be that using an AA literal is just syntax sugar for
> calling an AA construction function, and that said function isn't
> CTFEable.
>
> When you specify an initial value for a global, that value must be a
> compile-time constant.  If it's not, as in this case, the correct thing
> to do is to use a module constructor:
>
>    string[string] values;
>    static this()
>    {
>        values = [ "abc":"abc", "def":"def" ];
>    }
>
> It is ONLY a good idea to use an enum array if you know you will be doing
> all lookups at compile time.  If the key you're looking for is just known
> at run time, the AA will be constructed anew for each lookup (I think),
> which is hideously expensive.
>
>    enum string[string] values = [ "abc":"def", "ghi":"jkl" ];
>
>    // This is fine, because it is done at compile time.
>    // It's essentially the same as:  auto s = "def";
>    auto s = values["abc"];
>
>    // This is a no-no, because it evaluates to something
>    // like:  auto aa = values; auto s = aa[key];
>    auto key = "abc";
>    auto s = values[key];
>
> Here's an example program that demonstrates the difference.  On my
> machine, the enum AA version takes 22x longer than the "normal" AA
> version.
>
>
> import std.datetime, std.stdio;
>
>
> enum string[string] enumAA = [ "abc" : "abc", "def" : "def" ];
>
> string[string] normalAA;
> static this()
> {
>      normalAA = [ "abc" : "abc", "def" : "def" ];
> }
>
>
> void main()
> {
>      enum max = 10_000_000;
>      StopWatch sw;
>      string lookup1 = "abc";
>      string lookup2 = "def";
>
>      sw.start();
>      foreach (i; 0 .. max)
>      {
>          auto a = enumAA[lookup1];
>          auto b = enumAA[lookup2];
>      }
>      sw.stop();
>      writeln(sw.peek().seconds);
>
>      sw.reset();
>
>      sw.start();
>      foreach (i; 0 .. max)
>      {
>          auto a = normalAA[lookup1];
>          auto b = normalAA[lookup2];
>      }
>      sw.stop();
>      writeln(sw.peek().seconds);
> }

Waow, thank you, Lars, /this/ is an explanation.
Now, why doesn't D make an enum aa a normal variable like your "normal aa" (but evaluated at compile-time instead of import time)?

Normal
-- 
_________________
vita es estrany
spir.wikidot.com