www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - pure factory function vs immutable(Foo)**

reply ag0aep6g <anonymous example.com> writes:
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
Jul 10 2017
next sibling parent reply drug <drug2004 bk.ru> writes:
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`
Jul 10 2017
parent ag0aep6g <anonymous example.com> writes:
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; } ----
Jul 10 2017
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
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
Jul 11 2017
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
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
Jul 11 2017