Thread overview
Error: cannot implicitly convert expression this.aa of type inout(string[string]) to string[string]
Mar 15, 2018
Robert-D
Mar 15, 2018
Simen Kjærås
Mar 15, 2018
Robert-D
Mar 15, 2018
Simen Kjærås
Mar 15, 2018
Robert-D
Mar 15, 2018
Simen Kjærås
March 15, 2018
struct S {
string[string] aa;

    S dup() inout pure {
    	return S(aa);
    }
}

void main() {
	auto s = S(["": ""]);
    s.dup();
}

Result:
 Error: cannot implicitly convert expression this.aa of type inout(string[string]) to string[string]


I need help with the above program.
March 15, 2018
On Thursday, 15 March 2018 at 11:18:48 UTC, Robert-D wrote:
> struct S {
> string[string] aa;
>
>     S dup() inout pure {
>     	return S(aa);
>     }
> }
>
> void main() {
> 	auto s = S(["": ""]);
>     s.dup();
> }
>
> Result:
>  Error: cannot implicitly convert expression this.aa of type inout(string[string]) to string[string]
>
>
> I need help with the above program.


This is where things go wrong:
>     S dup() inout pure {

'inout' means that this function can keep the const, immutable or mutable status of the type on which the function is called. This means that an inout function has to treat the object as const, because otherwise the function would break the guarantees of immutable and const.

When using inout on a function, you always want to put inout on something else too - either a ref parameter or the return value. In your case, this works:

    inout(S) dup() inout pure {
    	return inout(S)(aa);
    }

--
  Simen
March 15, 2018
On Thursday, 15 March 2018 at 11:33:49 UTC, Simen Kjærås wrote:
> On Thursday, 15 March 2018 at 11:18:48 UTC, Robert-D wrote:
>> [...]
>
>
> This is where things go wrong:
>>     [...]
>
> 'inout' means that this function can keep the const, immutable or mutable status of the type on which the function is called. This means that an inout function has to treat the object as const, because otherwise the function would break the guarantees of immutable and const.
>
> When using inout on a function, you always want to put inout on something else too - either a ref parameter or the return value. In your case, this works:
>
>     inout(S) dup() inout pure {
>     	return inout(S)(aa);
>     }
>
> --
>   Simen

I want the function to create a mutable copy from a const or a imutable

Like this:

void main() {
    const S s = S(["": ""]);
    S b = s.dup();
}

How can i do that?
March 15, 2018
On Thursday, 15 March 2018 at 12:00:08 UTC, Robert-D wrote:
> I want the function to create a mutable copy from a const or a imutable
>
> Like this:
>
> void main() {
>     const S s = S(["": ""]);
>     S b = s.dup();
> }
>
> How can i do that?

In that case, the problem is that you also have to .dup the aa:

    S dup() const pure {
        return S(aa.dup);
    }

However, it seems aa.dup returns the wrong type - one would expect V[K] for inout(V[K]), but it returns inout(V)[K], or inout(string)[string], in your case. That's apparently a known bug: https://issues.dlang.org/show_bug.cgi?id=14148.

The solution for now, then, is this:

    S dup() const pure {
        return S(cast(string[string])aa.dup);
    }

--
  Simen
March 15, 2018
On Thursday, 15 March 2018 at 13:18:38 UTC, Simen Kjærås wrote:
> On Thursday, 15 March 2018 at 12:00:08 UTC, Robert-D wrote:
>> I want the function to create a mutable copy from a const or a imutable
>>
>> Like this:
>>
>> void main() {
>>     const S s = S(["": ""]);
>>     S b = s.dup();
>> }
>>
>> How can i do that?
>
> In that case, the problem is that you also have to .dup the aa:
>
>     S dup() const pure {
>         return S(aa.dup);
>     }
>
> However, it seems aa.dup returns the wrong type - one would expect V[K] for inout(V[K]), but it returns inout(V)[K], or inout(string)[string], in your case. That's apparently a known bug: https://issues.dlang.org/show_bug.cgi?id=14148.
>
> The solution for now, then, is this:
>
>     S dup() const pure {
>         return S(cast(string[string])aa.dup);
>     }
>
> --
>   Simen

Why something like this doesn't compile (with or without the cast on bb.dup)?

struct S {
    string[string] aa;

    S dup() inout pure {
        return S(cast(string[string]) aa.dup);
    }
}

struct SS {
    S[] bb;

    SS dup() inout pure {
        return SS(cast(S[]) bb.dup);
    }
}


Error: static assert: "Cannot implicitly convert type inout(S) to S in dup."

Or:

const(S)[] ss = [S(["": ""])];
S[] d = ss.dup;

Error: template object.dup cannot deduce function from argument types !()(const(S)[]), candidates are:
/dlang/dmd/linux/bin64/../../src/druntime/import/object.d(2086):        object.dup(T : V[K], K, V)(T aa)
/dlang/dmd/linux/bin64/../../src/druntime/import/object.d(2122):        object.dup(T : V[K], K, V)(T* aa)
/dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4191):        object.dup(T)(T[] a) if (!is(const(T) : T))
/dlang/dmd/linux/bin64/../../src/druntime/import/object.d(4207):        object.dup(T)(const(T)[] a) if (is(const(T) : T))


March 15, 2018
On Thursday, 15 March 2018 at 15:41:54 UTC, Robert-D wrote:
> Why something like this doesn't compile (with or without the cast on bb.dup)?
>
> struct S {
>     string[string] aa;
>
>     S dup() inout pure {
>         return S(cast(string[string]) aa.dup);
>     }
> }
>
> struct SS {
>     S[] bb;
>
>     SS dup() inout pure {
>         return SS(cast(S[]) bb.dup);
>     }
> }
>
> Or:
>
> const(S)[] ss = [S(["": ""])];
> S[] d = ss.dup;

For this to work, the standard .dup function would need to call .dup on each element of the array. Since this may or may not be what the programmer wants, the standard library doesn't do it for you. Generally, this is called deep-duping, or deep cloning. We can implement our own deepdup function:

struct S {
    string[string] aa;

    S dup() const {
        return S(aa.deepDup);
    }
}

struct SS {
    S[] bb;

    SS dup() const {
        return SS(cast(S[])bb.deepDup);
    }
}

import std.traits : Unqual, isArray, isAssociativeArray;

auto deepDup(T)(T obj)
if (!isArray!T && !isAssociativeArray!T)
{
    static if (is(typeof(obj.deepDup))) {
        return obj.deepDup;
    } else static if (is(typeof(obj.dup))) {
        return obj.dup;
    } else static if (is(typeof({ Unqual!T tmp = obj; }))) {
        return obj;
    } else {
        static assert(false, "Can't deepDup a "~T.stringof);
    }
}

auto deepDup(T)(T[] arr) {
    Unqual!T[] result;
    result.reserve(arr.length);

    foreach (e; arr) {
        result ~= e.deepDup;
    }

    return result;
}

auto deepDup(T : V[K], K, V)(T aa) {
    alias UV = Unqual!V;
    alias UK = Unqual!K;
    UV[UK] result;

    foreach (k, v; aa) {
        UK kdup = k.deepDup;
        UV vdup = v.deepDup;

        result[kdup] = vdup;
    }

    return result;
}

--
  Simen