www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Immutable struct with AA init problem

reply "Uranuz" <neuranuz gmail.com> writes:
In my programme I want to make set of immutable struct objects, 
that will be initialazed at startup in shared static this() 
constructor. But using the folowing code I have compilation 
error. I think there is a problem with associative array.

For usual array we have .idup property that returns immutable 
copy of dynamic array, but for AA we have no such option. And 
there are some difficulties to create immutable AA.

But question is how to make following source compile. Do you have 
any advices?

//--------------
import std.stdio, std.conv;

struct EnumFormat
{	
protected:
	string[int] _names;
	int[] _keys;

public:
	this(string[int] names, bool isAscendingOrder = true) immutable
	{	_names = names;
		import std.algorithm;
		int[] keys = names.keys;
		
		if( isAscendingOrder )
			sort!("a < b")(keys);
		else
			sort!("a > b")(keys);
		_keys = keys;
	}
	
	string opIndex(int key)
	{	if( key in _names )
			return _names[key];
		else
			throw new Exception("Value " ~ key.to!string ~ " is not valid 
enum value!!!");
	}
	
	
	int opApply(int delegate(ref string name, ref int i) dg)
	{	foreach( key; _keys )
		{	auto result = dg(names[key], key);
			if(result)
				return result;
		}
		return 0;
	}
	
	int opApply(int delegate(ref int i) dg)
	{	foreach( key; _keys )
		{	auto result = dg(key);
			if(result)
				return result;
		}
		return 0;
	}
}

immutable(EnumFormat) magicCreatures;

//Intializing it at programme startup to make it once initialized
//and shared between all threads
shared static this()
{	
	magicCreatures = EnumFormat([1:"goblin", 2:"ork", 3:"elf", 
7:"dwarf"], false);
}


void main()
{
	foreach(name, i; magicCreatures)
	{ //Doing something
		
	}
}

//-----------------
Compilation output:
enum_test2.d(16): Error: cannot implicitly convert expression 
(names) of type string[int] to immutable(char[][int])
enum_test2.d(24): Error: cannot implicitly convert expression 
(keys) of type int[] to immutable(int[])
enum_test2.d(31): Error: cannot implicitly convert expression 
(names.dup()) of type string[int] to immutable(char[][int])
enum_test2.d(90): Error: immutable method 
enum_test2.EnumFormat.this is not callable using a mutable object
Failed: 'dmd' '-v' '-o-' 'enum_test2.d' '-I.'

How can I make this struct working with immutable constructor?
Nov 25 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 11/25/2013 10:52 AM, Uranuz wrote:

 In my programme I want to make set of immutable struct objects, that
 will be initialazed at startup in shared static this() constructor. But
 using the folowing code I have compilation error. I think there is a
 problem with associative array.

 For usual array we have .idup property that returns immutable copy of
 dynamic array, but for AA we have no such option. And there are some
 difficulties to create immutable AA.

 But question is how to make following source compile. Do you have any
 advices?

 //--------------
 import std.stdio, std.conv;

 struct EnumFormat
 {
 protected:
      string[int] _names;
      int[] _keys;

 public:
      this(string[int] names, bool isAscendingOrder = true) immutable
      {    _names = names;
Because the type of _names is immutable(string[int]), it must refer to matching type: this(immutable(string[int]) names, bool isAscendingOrder = true) immutable
          import std.algorithm;
          int[] keys = names.keys;

          if( isAscendingOrder )
              sort!("a < b")(keys);
          else
              sort!("a > b")(keys);
          _keys = keys;
_key is immutable, so it cannot refer to int[]. assumeUnique() seems to be a good fit: import std.exception; // ... _keys = assumeUnique(keys);
      }

      string opIndex(int key)
      {    if( key in _names )
              return _names[key];
          else
              throw new Exception("Value " ~ key.to!string ~ " is not
 valid enum value!!!");
      }


      int opApply(int delegate(ref string name, ref int i) dg)
Since you are iterating over an immutable object, this function must promise not to modify, so it must be marked as const. Additionally, non-const reference to members cannot be granted, so the simplest thing is to drop the refs: int opApply(int delegate(string name, int i) dg) const
      {    foreach( key; _keys )
          {    auto result = dg(names[key], key);
Typo: names -> _names
              if(result)
                  return result;
          }
          return 0;
      }

      int opApply(int delegate(ref int i) dg)
      {    foreach( key; _keys )
          {    auto result = dg(key);
              if(result)
                  return result;
          }
          return 0;
      }
 }

 immutable(EnumFormat) magicCreatures;

 //Intializing it at programme startup to make it once initialized
 //and shared between all threads
 shared static this()
 {
      magicCreatures = EnumFormat([1:"goblin", 2:"ork", 3:"elf",
 7:"dwarf"], false);
The right-hand side had to be immutable as well. I think it is because this is not taken to be immutable-construction, rather post-blit. (I think.): magicCreatures = immutable(EnumFormat)([1:"goblin", 2:"ork", 3:"elf", 7:"dwarf"], false);
 }


 void main()
 {
      foreach(name, i; magicCreatures)
      { //Doing something

      }
 }

 //-----------------
 Compilation output:
 enum_test2.d(16): Error: cannot implicitly convert expression (names) of
 type string[int] to immutable(char[][int])
 enum_test2.d(24): Error: cannot implicitly convert expression (keys) of
 type int[] to immutable(int[])
 enum_test2.d(31): Error: cannot implicitly convert expression
 (names.dup()) of type string[int] to immutable(char[][int])
 enum_test2.d(90): Error: immutable method enum_test2.EnumFormat.this is
 not callable using a mutable object
 Failed: 'dmd' '-v' '-o-' 'enum_test2.d' '-I.'

 How can I make this struct working with immutable constructor?
It compiles with the above changes. The entire program: //-------------- import std.stdio, std.conv; import std.exception; struct EnumFormat { protected: string[int] _names; int[] _keys; public: this(immutable(string[int]) names, bool isAscendingOrder = true) immutable { _names = names; import std.algorithm; int[] keys = names.keys; if( isAscendingOrder ) sort!("a < b")(keys); else sort!("a > b")(keys); _keys = assumeUnique(keys); } string opIndex(int key) { if( key in _names ) return _names[key]; else throw new Exception("Value " ~ key.to!string ~ " is not valid enum value!!!"); } int opApply(int delegate(string name, int i) dg) const { foreach( key; _keys ) { auto result = dg(_names[key], key); if(result) return result; } return 0; } int opApply(int delegate(ref int i) dg) { foreach( key; _keys ) { auto result = dg(key); if(result) return result; } return 0; } } immutable(EnumFormat) magicCreatures; //Intializing it at programme startup to make it once initialized //and shared between all threads shared static this() { magicCreatures = immutable(EnumFormat)([1:"goblin", 2:"ork", 3:"elf", 7:"dwarf"], false); } void main() { foreach(name, i; magicCreatures) { //Doing something } } Ali
Nov 25 2013
parent reply "Uranuz" <neuranuz gmail.com> writes:
As far as I understand in current implementation of Dlang it's 
not possible to write:

immutable(EnumFormat) magicCreatures = 
immutable(EnumFormat)([1:"goblin", 2:"ork", 3:"elf", 7:"dwarf"], 
false);

It's because AA literal isn't immutable. But is there some method 
similar to assumeUnique() for AA? Using static this() to define 
some constants looks awkward as I believe.
Nov 26 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 11/26/2013 02:12 AM, Uranuz wrote:> As far as I understand in current 
implementation of Dlang it's not
 possible to write:

 immutable(EnumFormat) magicCreatures =
 immutable(EnumFormat)([1:"goblin", 2:"ork", 3:"elf", 7:"dwarf"], false);
It is a shame that either the design and implementation of const, immutable, construction, associative arrays, etc. or our understanding of such complexities are still incomplete but at least what you show works as long as there is an immutable constructor. The following main constructs one mutable and one immutable object: struct S { string[int] aa; bool b; this(string[int] aa, bool b) { this.aa = aa; this.b = b; } this(immutable(string[int]) aa, bool b) immutable { this.aa = aa; this.b = b; } } void main() { auto sm = S([1:"mut"], false); auto si = immutable(S)([2:"imm"], true); }
 It's because AA literal isn't immutable.
Actually, AA literals can be used to initialize an immutable AA as well: immutable(string[int]) aaimm = [ 1 : "aa imm" ];
 But is there some method similar to assumeUnique() for AA? Using static
 this() to define some constants looks awkward as I believe.
assumeUnique works with AAs as well: import std.exception; void main() { auto aa = [ 1 : "one" ]; static assert(is (typeof(aa) == string[int])); auto aaimm = assumeUnique(aa); static assert(is (typeof(aaimm) == immutable(string[int]))); } Ali
Nov 26 2013