Thread overview
pure factory function vs immutable(Foo)**
Jul 10, 2017
ag0aep6g
Jul 10, 2017
drug
Jul 10, 2017
ag0aep6g
Jul 11, 2017
ag0aep6g
July 10, 2017
I feel like I must be missing something here.

This works:

----
alias T = int;

T** f(const T** input) pure
{
    T** output;
    return output;
}

void main()
{
    T i;
    T* p = &i;
    immutable T** r = f(&p);
}
----

`f` is `pure`, its parameter is const, and its return type has mutable indirections. That makes it a "pure factory function" [1].

Since `f` is a pure factory function, the compiler can assume that the result is not referenced from anywhere else. So I can declare it `immutable`.

So far, so good.

Now change `T` to `alias T = immutable int;`. The program gets rejected. The error message is: "cannot implicitly convert expression (f(& p)) of type immutable(int)** to immutable(int**)".

What changed? `f` can now return a reference to `i`. But that's not a problem, because that part of the return type is already `immutable`. What would be a problem is if `f` could return a reference to `p`. But it can't, as far as I can tell.

Am I missing something or could/should the program be accepted with `T = immutable int`? What could `f` do that would break `r`'s immutability?


[1] https://dlang.org/spec/function.html#pure-functions
July 10, 2017
10.07.2017 17:57, ag0aep6g пишет:
> I feel like I must be missing something here.
>
> This works:
>
> ----
> alias T = int;
>
> T** f(const T** input) pure
> {
>     T** output;
>     return output;
> }
>
> void main()
> {
>     T i;
>     T* p = &i;
>     immutable T** r = f(&p);
> }
> ----
>
> `f` is `pure`, its parameter is const, and its return type has mutable
> indirections. That makes it a "pure factory function" [1].
>
> Since `f` is a pure factory function, the compiler can assume that the
> result is not referenced from anywhere else. So I can declare it
> `immutable`.
>
> So far, so good.
>
> Now change `T` to `alias T = immutable int;`. The program gets rejected.
> The error message is: "cannot implicitly convert expression (f(& p)) of
> type immutable(int)** to immutable(int**)".
>
> What changed? `f` can now return a reference to `i`. But that's not a
> problem, because that part of the return type is already `immutable`.
> What would be a problem is if `f` could return a reference to `p`. But
> it can't, as far as I can tell.
>
> Am I missing something or could/should the program be accepted with `T =
> immutable int`? What could `f` do that would break `r`'s immutability?
>
>
> [1] https://dlang.org/spec/function.html#pure-functions
I'm not sure I understand, but
```
immutable (T)** r = f(&p);
```
compiles. So compiler complains that indirections are mutable, but immutable ones are expected according to type of `r`

July 10, 2017
On 07/10/2017 05:42 PM, drug wrote:
> 10.07.2017 17:57, ag0aep6g пишет:
[...]
>> The error message is: "cannot implicitly convert expression (f(& p)) of
>> type immutable(int)** to immutable(int**)".
[...]
> I'm not sure I understand, but
> ```
> immutable (T)** r = f(&p);
> ```
> compiles. So compiler complains that indirections are mutable, but immutable ones are expected according to type of `r`

In itself, the error message makes sense. We can't usually convert from `immutable(int)**` to `immutable(int**)`.

We also can't usually convert from `int**` to `immutable(int**)`. But we can when the `int**` comes from a "pure factory function". And as far as I can see, it could/should also work when the pure factory function returns `immutable(int)**`.

For some context, I originally tried something like this:

----
struct S
{
    string str;
    int other_stuff;
}

void main()
{
    import std.algorithm: map;
    import std.array: array;
    S[] structs;
    immutable strs = structs.map!(s => s.str).array;
}
----
July 11, 2017
On 07/10/2017 04:57 PM, ag0aep6g wrote:
> ----
> alias T = int;
> 
> T** f(const T** input) pure
> {
>      T** output;
>      return output;
> }
> 
> void main()
> {
>      T i;
>      T* p = &i;
>      immutable T** r = f(&p);
> }
> ----
[...]
> Now change `T` to `alias T = immutable int;`. The program gets rejected. The error message is: "cannot implicitly convert expression (f(& p)) of type immutable(int)** to immutable(int**)".

Filed an issue:
https://issues.dlang.org/show_bug.cgi?id=17635
July 11, 2017
On 7/11/17 2:12 PM, ag0aep6g wrote:
> On 07/10/2017 04:57 PM, ag0aep6g wrote:
>> ----
>> alias T = int;
>>
>> T** f(const T** input) pure
>> {
>>      T** output;
>>      return output;
>> }
>>
>> void main()
>> {
>>      T i;
>>      T* p = &i;
>>      immutable T** r = f(&p);
>> }
>> ----
> [...]
>> Now change `T` to `alias T = immutable int;`. The program gets rejected. The error message is: "cannot implicitly convert expression (f(& p)) of type immutable(int)** to immutable(int**)".
> 
> Filed an issue:
> https://issues.dlang.org/show_bug.cgi?id=17635

I think this is a legitimate bug.

to make sure this is correct, I added:

pragma(msg, typeof(input).stringof);

And it prints const(immutable(int)**) (as I would have expected, but wasn't 100% sure).

So there is no way the input can be returned, as immutable(int)** cannot be implicitly converted from const(immutable(int)**).

I think this is just a missed case in the compiler.

-Steve