Thread overview
Struct immutable data and dict
Oct 06, 2016
Patric Dexheimer
Oct 06, 2016
Adam D. Ruppe
Oct 06, 2016
Patric Dexheimer
Oct 06, 2016
Adam D. Ruppe
Oct 06, 2016
Mike Parker
Oct 06, 2016
Patric Dexheimer
Sep 04, 2018
Timoses
Sep 04, 2018
Alex
Sep 04, 2018
nkm1
Sep 04, 2018
Timoses
October 06, 2016
struct Test{
    immutable size_t id;
}

Test[string] dict;
Test[] array;

void main(){
    array~=Test(1);//work
    dict["teste"] = Test(1); //fail ??
}

"Error: cannot modify struct dict["teste"] Test with immutable members"
Why?
October 06, 2016
On Thursday, 6 October 2016 at 01:23:35 UTC, Patric Dexheimer wrote:
> Why?

Because you'd be overwriting that immutable member. Structs just put structure around their contents, but it doesn't change their nature. That struct is no different than if you wrote `immutable size_t` as the value - and of course, overwriting that; changing that violates that promise that you won't change it.

You could store pointers to those structs though, and overwrite the pointer.
October 06, 2016
On Thursday, 6 October 2016 at 02:09:44 UTC, Adam D. Ruppe wrote:
> On Thursday, 6 October 2016 at 01:23:35 UTC, Patric Dexheimer wrote:
>> Why?
>
> Because you'd be overwriting that immutable member. Structs just put structure around their contents, but it doesn't change their nature. That struct is no different than if you wrote `immutable size_t` as the value - and of course, overwriting that; changing that violates that promise that you won't change it.
>
> You could store pointers to those structs though, and overwrite the pointer.


But why i´m overwriting the struct if its the first time i´m putting it there? (like on the array).

October 06, 2016
On Thursday, 6 October 2016 at 03:05:18 UTC, Patric Dexheimer wrote:
> But why i´m overwriting the struct if its the first time i´m putting it there? (like on the array).

The compiler doesn't know it is the first time (it doesn't follow the data from creation, it just looks at that individual line, and first time write is no different than later writes with the associative array index, whereas array append is different so it can tell).
October 06, 2016
On Thursday, 6 October 2016 at 03:05:18 UTC, Patric Dexheimer wrote:

> But why i´m overwriting the struct if its the first time i´m putting it there? (like on the array).

There's a difference between initialization and assignment.

```
// Given this structure
struct MyStruct { int x; }

// Both of these lines are initializstion
auto mystruct1 = MyStruct(10);
MyStruct mystruct2;

assert(mystruct1.x == 10);
assert(mystruct2.x == 0);

// And both of these are assignments.
mystruct2 = MyStruct(11);
mystruct1 = mystruct2;

assert(mystruct2.x == 11);
assert(mystruct1.x == 11);
```

If x were immutable, both initializations would succeed, but both assignments would fail.


October 06, 2016
On Thursday, 6 October 2016 at 03:48:22 UTC, Mike Parker wrote:
> On Thursday, 6 October 2016 at 03:05:18 UTC, Patric Dexheimer wrote:
>
>> [...]
>
> There's a difference between initialization and assignment.
>
> [...]
On Thursday, 6 October 2016 at 03:48:22 UTC, Mike Parker wrote:
> On Thursday, 6 October 2016 at 03:05:18 UTC, Patric Dexheimer wrote:
>
> [...]

Hm, so in dict they are always assuming that i´m doing assignments..
Ok, more clear now. thanks.
September 04, 2018
On Thursday, 6 October 2016 at 02:09:44 UTC, Adam D. Ruppe wrote:
> On Thursday, 6 October 2016 at 01:23:35 UTC, Patric Dexheimer wrote:
>> Why?
>
> Because you'd be overwriting that immutable member. Structs just put structure around their contents, but it doesn't change their nature. That struct is no different than if you wrote `immutable size_t` as the value - and of course, overwriting that; changing that violates that promise that you won't change it.
>
> You could store pointers to those structs though, and overwrite the pointer.

Hm... so is there any way around this?

In my case I have a RandomAccessRange which caches it's results. Reduced example:

    struct Res
    {
        immutable int i;
    }

    struct Range
    {
        Res[size_t] c;

        Res fun(size_t i)
        {
            if (auto p = i in c)
                return *p;
            else
            {
                c[3] = Res(3);   /// ERROR line 26
                return c[3];
            }
        }
    }

    unittest
    {
        auto r = Range();
        r.fun(3);
    }

which errors at compilation with
onlineapp.d(26): Error: cannot modify struct this.c[3] Res with immutable members

A workaround I thought could be to use an array

    struct Range
    {
        //Res[size_t] c;
        struct Con { Res c; bool valid; }
        Con[] c;

        Res fun(size_t i)
        {
            if (c.length > i && c[i].valid)
                return c[i].c;
            else
            {
                if (c.length <= i) c.length = i + 1;
                auto r = Con(Res(3), true);
                c[i] = r;   /// same ERROR!
                return c[i].c;
            }
        }
    }

However, of course this also fails because randomly assigning the array elements will overwrite it. So the associative array seems like the better idea. However, not being able to INITIALIZE an assoc array element disallows its usage.

Is there any solution, trick or workaround??
September 04, 2018
On Tuesday, 4 September 2018 at 10:30:24 UTC, Timoses wrote:
>
> However, of course this also fails because randomly assigning the array elements will overwrite it. So the associative array seems like the better idea. However, not being able to INITIALIZE an assoc array element disallows its usage.
>
> Is there any solution, trick or workaround??

If the initialization of assoc array is not the matter, but the initialization of an element of it, then, the question is rather:
"Is the absence of an immutable value in an assoc array worth to be garanteed, because the values are immutable?" Isn't it?

No idea about this :p

´´´
void main()
{
	import std.stdio;
	auto r = Range("dummy");
	r.fun(3).writeln;
}

struct Res
{
	immutable int i;
}

struct Range
{
	this(string)
	{
		c = [0 : Res(42), 5: Res(73), /*3: Res(4)*/];
	}

	Res[size_t] c;

	Res fun(size_t i)
	{
		if (auto p = i in c)
			return *p;
		else
		{
			//c[3] = Res(3);   /// ERROR line 26
			return Res(int.max);
		}
	}
}
´´´

I tried two workarounds:
1) let the immutable away.
2) preallocate a full array of immutables. Then, misuse the assoc array by using the keys only. If the key is there, then, yield the appropriate element from the preallocated array. If not, yield the "elephant in Cairo".
September 04, 2018
On Tuesday, 4 September 2018 at 11:25:15 UTC, Alex wrote:
> On Tuesday, 4 September 2018 at 10:30:24 UTC, Timoses wrote:
>>
>> However, of course this also fails because randomly assigning the array elements will overwrite it. So the associative array seems like the better idea. However, not being able to INITIALIZE an assoc array element disallows its usage.
>>
>> Is there any solution, trick or workaround??
> I tried two workarounds:
> 1) let the immutable away.
> 2) preallocate a full array of immutables. Then, misuse the assoc array by using the keys only. If the key is there, then, yield the appropriate element from the preallocated array. If not, yield the "elephant in Cairo".

I also had this problem recently. I think aa.require() should allow to add immutables (feature request). Anyway, my workaround was along the lines of:

final class AA(Key, Value)
{
    Value[] _storage;
    size_t[Key] _aa;

    void opIndexAssign(Value value, Key key)
    {
        if (key !in _aa)
        {
            _storage ~= value;
            _aa[key] = _storage.length - 1;
        }
    }

    Value opIndex(Key key)
    {
        if (auto index = key in _aa)
            return _storage[*index];

        throw new Exception("no key");
    }
}

immutable struct S
{
    int num;
}

void main()
{
    import std.stdio : writeln;

    auto aa = new AA!(string, S);

    aa["one"] = S(1);
    aa["two"] = S(2);

    writeln(aa["one"]);
    writeln(aa["two"]);
}

September 04, 2018
On Tuesday, 4 September 2018 at 12:27:47 UTC, nkm1 wrote:
> I also had this problem recently. I think aa.require() should allow to add immutables (feature request). Anyway, my workaround was along the lines of:
>
> final class AA(Key, Value)
> {
>     Value[] _storage;
>     size_t[Key] _aa;
>
>     void opIndexAssign(Value value, Key key)
>     {
>         if (key !in _aa)
>         {
>             _storage ~= value;
>             _aa[key] = _storage.length - 1;
>         }
>     }
>
>     Value opIndex(Key key)
>     {
>         if (auto index = key in _aa)
>             return _storage[*index];
>
>         throw new Exception("no key");
>     }
> }
>
> immutable struct S
> {
>     int num;
> }
>
> void main()
> {
>     import std.stdio : writeln;
>
>     auto aa = new AA!(string, S);
>
>     aa["one"] = S(1);
>     aa["two"] = S(2);
>
>     writeln(aa["one"]);
>     writeln(aa["two"]);
> }

Thanks for the replies. It seems quite annoying.

I just use classes for now.