February 21, 2023

On Friday, 10 February 2023 at 14:37:35 UTC, ag0aep6g wrote:

>

On Friday, 10 February 2023 at 14:00:20 UTC, Steven Schveighoffer wrote:

>

It can be weakly pure. The docs are wrong.

i.e. this works:

pure int *foo(const int *p)
{
   return new int(5);
}

void main()
{
   int x;
   immutable int * bar = foo(&x);
}

That function "has no parameters with mutable indirections". So it's strongly pure, not weakly pure.

Uniqueness analysis depends on the return type as much as on parameter types.

In Steve’s example, foo does have parameters with mutable indirections (as I interpret that phrase – it’s honestly not precise wording) because const allows binding mutable values. The reason Steve’s example compiles is that by thorough investigation of parameter and return types, the compiler comes to the conclusion that there is no way p, which is a const(int)* makes it into the return value, and therefore the result must be uniquely created and thus may be cast to immutable. If you change the return type of foo to const(int)* (cf. goo in the example below), the parameter’s value could make it into the result and because p may be bound to mutable, the result cannot be cast to immutable implicitly:

pure @safe       int * foo(const(int)* p) { return new int(1); }
pure @safe const(int)* goo(const(int)* p) { return new int(1); }

void main() @safe
{
    auto p = new int;
    immutable a = foo(p); // ok
    immutable b = goo(p); // error
}
February 21, 2023
On 21.02.23 11:46, Quirin Schroll wrote:
> On Friday, 10 February 2023 at 14:37:35 UTC, ag0aep6g wrote:
[...]
>> That function "has no parameters with mutable indirections". So it's strongly pure, not weakly pure.
> 
> Uniqueness analysis depends on the return type as much as on parameter types.

I was only commenting on weakly/strongly pure. As you say, the return type matters for pure factory functions. But it doesn't matter for weakly/strongly pure.

All pure factory functions are strongly pure. Not all strongly pure functions are pure factory functions.
February 21, 2023

On Tuesday, 21 February 2023 at 13:13:27 UTC, ag0aep6g wrote:

>

On 21.02.23 11:46, Quirin Schroll wrote:

>

On Friday, 10 February 2023 at 14:37:35 UTC, ag0aep6g wrote:
[...]

>

That function "has no parameters with mutable indirections". So it's strongly pure, not weakly pure.

Uniqueness analysis depends on the return type as much as on parameter types.

I was only commenting on weakly/strongly pure. As you say, the return type matters for pure factory functions. But it doesn't matter for weakly/strongly pure.

All pure factory functions are strongly pure. Not all strongly pure functions are pure factory functions.

No, that is not true. The following foo is weakly pure, it mutates its input. But because the input cannot end up in the result (proven via their types, not the implementation), the result is unique, and can be converted to immutable.

@safe:

int* foo(double[] xs) pure
{
    if (xs.length >= 2)
        xs[0] = xs[$ - 1];
    return new int;
}

void main()
{
    double[] xs = [];
    immutable a = foo(xs);
}

The whole section of pure factory functions should be revised (it could moved to a textbook like Ali’s) because it wants to talk about unique results, but it talks about a special case of it.

February 21, 2023

On Tuesday, 21 February 2023 at 13:13:27 UTC, ag0aep6g wrote:

>

On 21.02.23 11:46, Quirin Schroll wrote:

>

On Friday, 10 February 2023 at 14:37:35 UTC, ag0aep6g wrote:
[...]

>

That function "has no parameters with mutable indirections". So it's strongly pure, not weakly pure.

Uniqueness analysis depends on the return type as much as on parameter types.

I was only commenting on weakly/strongly pure. As you say, the return type matters for pure factory functions. But it doesn't matter for weakly/strongly pure.

All pure factory functions are strongly pure. Not all strongly pure functions are pure factory functions.

No, that is not true. The following foo is weakly pure, it mutates its input. But because the input cannot end up in the result (proven via their types, not the implementation), the result is unique, and can be converted to immutable.

@safe:

int* foo(double[] xs) pure
{
    if (xs.length >= 2)
        xs[0] = xs[$ - 1];
    return new int;
}

void main()
{
    double[] xs = [];
    immutable a = foo(xs);
}

The whole section of pure factory functions should be revised (it could moved to a textbook like Ali’s) because it wants to talk about unique results, but it talks about a special case of it.

February 21, 2023
On 21.02.23 14:58, Quirin Schroll wrote:
> ```d
> @safe:
> 
> int* foo(double[] xs) pure
> {
>      if (xs.length >= 2)
>          xs[0] = xs[$ - 1];
>      return new int;
> }
> 
> void main()
> {
>      double[] xs = [];
>      immutable a = foo(xs);
> }
> ```

That right there is nothing but a safety hole. D allows casting from `double[]` to `int[]`, so the compiler cannot assume uniqueness in that case.

More explosive test case:

----
@safe:

int[] foo(ubyte[] bytes) @safe pure
{
    return cast(int[]) bytes; /* the language very much allows this */
}

void main()
{
    ubyte[] bytes = [42, 0, 0, 0];
    immutable ints = foo(bytes);
    assert(ints[0] == 42); /* passes */
    bytes[0] = 13;
    assert(ints[0] == 42); /* fails; immutable int changed value */
}
----
February 21, 2023
On 21.02.23 15:31, ag0aep6g wrote:
> On 21.02.23 14:58, Quirin Schroll wrote:
>> ```d
>> @safe:
>>
>> int* foo(double[] xs) pure
>> {
>>      if (xs.length >= 2)
>>          xs[0] = xs[$ - 1];
>>      return new int;
>> }
>>
>> void main()
>> {
>>      double[] xs = [];
>>      immutable a = foo(xs);
>> }
>> ```
> 
> That right there is nothing but a safety hole.

I did some digging and found `-preview=fixImmutableConv`. With that, the code fails compilation as it should. So this is a known issue and it's already in the process of getting fixed.
1 2
Next ›   Last »