Immutable struct with AA init problem

Ali Çehreli acehreli at yahoo.com
Mon Nov 25 11:50:00 PST 2013


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



More information about the Digitalmars-d-learn mailing list