www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Initializing "two-dimensional" compile-time enum

reply "Uranuz" <neuranuz gmail.com> writes:
Greetings! I have a problem in my code and I need an advice. I 
need possibility of creating "two-dimensional" AA in module scope 
that I can access at compile-time. I considered that it should be 
marked as enum to do this but I get strange error. There is a 
piece of code to test.

//---------------
import std.stdio;


enum string[int][string] pohodEnumValues = [
	"vid": [ 3: "skiing", 5: "rafting", 7: "jumping" ],
	"ks": [ 1: "first", 2: "second", 3: "third" ],
	"prepare": [ 1:"planning", 3:"preparing", 5:"complete" ]
];


void main()
{
	writeln(pohodEnumValues);
	
}
//--------END OF CODE -----

In dmd 2.064.2 I get following output:

Compilation output:
/d521/f517.d(4): Error: not an associative array initializer

Elements of AA are used as template arguments so I need them at 
compile-time. I need help, please))
Nov 24 2013
next sibling parent "Uranuz" <neuranuz gmail.com> writes:
Compiling following code makes another strange error message.

import std.stdio;

enum string[int][string] pohodEnumValues = [
	"vid": [ 3: "skiing", 5: "rafting", 7: "jumping" ].dup,
	"ks": [ 1: "first", 2: "second", 3: "third" ].dup,
	"prepare": [ 1:"planning", 3:"preparing", 5:"complete" ].dup
];


void main()
{
	writeln(pohodEnumValues);
	
}

//-------
Compilation output:
/opt/compilers/dmd2/include/object.di(435): Error: _aaApply2 
cannot be interpreted at compile time, because it has no 
available source code
/opt/compilers/dmd2/include/object.di(458):        called from 
here: this.opApply(delegate int(ref int __applyArg0, ref string 
__applyArg1) => 0)
/d895/f161.d(5):        called from here: [3:"skiing", 
5:"rafting", 7:"jumping"].dup()
Nov 24 2013
prev sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
Geez, I just spent 15' trying to make this work! AA + Compile-time are
like oil and water.

You can use CTFE and an initializing function. It's a bit cumbersome,
but it works.

module main;

import std.stdio;

string[int][string] initializePohod()
{
    string[int][string] result;
    result["vid"] = [ 3: "skiing", 5: "rafting", 7: "jumping" ];
    result["ks"] = [ 1: "first", 2: "second", 3: "third" ];
    result["prepare"] = [ 1:"planning", 3:"preparing", 5:"complete" ];
    return result;
}

enum string[int][string] pohodEnumValues = initializePohod();

void main()
{
        writeln(pohodEnumValues);
        pragma(msg, pohodEnumValues); // there, accessible during compilation.
}

On Sun, Nov 24, 2013 at 1:01 PM, Uranuz <neuranuz gmail.com> wrote:
 Greetings! I have a problem in my code and I need an advice. I need
 possibility of creating "two-dimensional" AA in module scope that I can
 access at compile-time. I considered that it should be marked as enum to do
 this but I get strange error. There is a piece of code to test.

 //---------------
 import std.stdio;


 enum string[int][string] pohodEnumValues = [
         "vid": [ 3: "skiing", 5: "rafting", 7: "jumping" ],
         "ks": [ 1: "first", 2: "second", 3: "third" ],
         "prepare": [ 1:"planning", 3:"preparing", 5:"complete" ]
 ];


 void main()
 {
         writeln(pohodEnumValues);

 }
 //--------END OF CODE -----

 In dmd 2.064.2 I get following output:

 Compilation output:
 /d521/f517.d(4): Error: not an associative array initializer

 Elements of AA are used as template arguments so I need them at
 compile-time. I need help, please))
Nov 24 2013
next sibling parent reply "Uranuz" <neuranuz gmail.com> writes:
Thanks! I'll try it. Another question is can I use immutable 
variables in compile time or they are just runtime variables that 
are once initialized and can't be modified? Is it only way to use 
manifest constants (enum). And what is semantics of enum 
constants? In D we have a lot of modifiers: static, enum, const, 
immutable. So sometimes I get stuck with question what to use? 
Could someone briefly explain the purpose of each one of these?
Nov 24 2013
parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Nov 24, 2013 at 5:14 PM, Uranuz <neuranuz gmail.com> wrote:
 Thanks! I'll try it. Another question is can I use immutable variables in
 compile time or they are just runtime variables that are once initialized
 and can't be modified? Is it only way to use manifest constants (enum). And
 what is semantics of enum constants? In D we have a lot of modifiers:
 static, enum, const, immutable. So sometimes I get stuck with question what
 to use? Could someone briefly explain the purpose of each one of these?
A named enum has no 'real' existence: you cannot take its address (it has none), for example. It's a glorified literal, which is just replaced by its value every time it's used. Which means using enum` in conjunction with dynamic arrays and associative arrays is prone to drastically limit your code speed, because there will be an allocation for each instance. An immutable value is much more standard: it's allocated once, you can take its address and so on. It can be allocated at runtime and once it's allocated, no one can change it. It A const value cannot be modified in the current scope, but someone else, elsewhere, might. See: http://ddili.org/ders/d.en/const_and_immutable.html And also: http://ddili.org/ders/d.en/const_member_functions.html
Nov 24 2013
parent reply "Uranuz" <neuranuz gmail.com> writes:
As far as I understand I can't use immutable values as template 
arguments. It's what I need in my code. I'll give an example.

//---------------
import std.stdio;

immutable(string[int][string]) pohodEnumValues;

shared static this()
{
     pohodEnumValues = [
	"vid": [ 3: "skiing", 5: "rafting", 7: "jumping" ],
	"ks": [ 1: "first", 2: "second", 3: "third" ],
	"prepare": [ 1:"planning", 3:"preparing", 5:"complete" ]
	];
}

//Some template method
void foo(string arg)()
{ //Some actions here
	
}

void main()
{
	foreach( name, item; pohodEnumValues )
	{	foo!(name)(); //I need name at compile time here
	}
}
//-----------------

Because we have only compile time foreach over tuple this is not 
working. Can someone give an advice, please?
Nov 24 2013
next sibling parent reply "Uranuz" <neuranuz gmail.com> writes:
This example above will not compile because name is not a compile 
time expression. But I can't undersatnd how to make some kind of 
compile-time variable. If we have advanced metaprogramming 
features I think possibility of defining compile-time variables 
is needed. Am I right or not?

I think defining compile-time array as Tuple!("first", "second", 
"third") looking sophisticated.
Nov 24 2013
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
 But I can't undersatnd how to make some kind of compile-time
 variable. If we have advanced metaprogramming features I think possibility
 of defining compile-time variables is needed. Am I right or not?
That's what we all want, but it's more or less impossible. If your variable do not change type, then you can at least build an array and store its successive values in the array. Then you use the last value for the rest of your computation. Or, as I said in another post, use Compile-Time Function Evaluation: using standard functions, you can be as iterative/imperative as you want.
Nov 24 2013
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Nov 24, 2013 at 8:09 PM, Uranuz <neuranuz gmail.com> wrote:
 As far as I understand I can't use immutable values as template arguments.
Indeed not. They are not defined at compile-time.
 //Some template method
 void foo(string arg)()
 { //Some actions here

 }

 void main()
 {
         foreach( name, item; pohodEnumValues )
         {       foo!(name)(); //I need name at compile time here
         }
 }
 //-----------------

 Because we have only compile time foreach over tuple this is not working.
 Can someone give an advice, please?
I see some possibilities, but they might be a bit overkill. In increasing order of coding effort: 1) use a tuple (as you suggest in another post) 2) use functions to build the code you want (as a string) and then mix it in. Using functions, you can use iterative code as much as you wish. 3) Another, more far-fetched, option is to use a struct. Since your AA is defined at compile-time, I would not create an AA, but a struct, crafting it to mimic your AA.
Nov 24 2013
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 24 November 2013 at 13:58:11 UTC, Philippe Sigaud
wrote:
 You can use CTFE and an initializing function. It's a bit 
 cumbersome,
 but it works.
Lambda's to the rescue! //---- enum string[int][string] pohodEnumValues = (){ string[int][string] result; result["vid"] = [ 3: "skiing", 5: "rafting", 7: "jumping" ]; result["ks"] = [ 1: "first", 2: "second", 3: "third" ]; result["prepare"] = [ 1:"planning", 3:"preparing", 5:"complete" ]; return result; }(); //---- This is cleaner, IMO.
Nov 24 2013
next sibling parent "Uranuz" <neuranuz gmail.com> writes:
While looking at this example JavaScript syntax calling to mind))
Nov 24 2013
prev sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Nov 24, 2013 at 5:19 PM, monarch_dodra <monarchdodra gmail.com> wrote:

 This is cleaner, IMO.
Well, in an ideal world, we wouldn't have to fall back to these contortions.
Nov 24 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 24 November 2013 at 17:16:21 UTC, Philippe Sigaud
wrote:
 On Sun, Nov 24, 2013 at 5:19 PM, monarch_dodra 
 <monarchdodra gmail.com> wrote:

 This is cleaner, IMO.
Well, in an ideal world, we wouldn't have to fall back to these contortions.
Even without bugs, it's still convenient way to declare a variable as enum or const, when 1-liner initialization is simply not possible. enum bar = () { T t; initialize(t); return t; }();
Nov 25 2013
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
Good idea, it's something I tend to forget. I always create associated
functions when an anony...
Nov 25 2013
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Mon, Nov 25, 2013 at 7:10 PM, Philippe Sigaud
<philippe.sigaud gmail.com> wrote:
 Good idea, it's something I tend to forget. I always create associated
 functions when an anony...
Arg, damn gmail. ... when an anonymous one would be enough (and would not clutter the namespace)
Nov 25 2013