June 14, 2019
On Friday, 14 June 2019 at 01:22:35 UTC, Timon Gehr wrote:
> On 14.06.19 03:17, Exil wrote:
>> On Friday, 14 June 2019 at 01:12:21 UTC, Timon Gehr wrote:
>>> On 14.06.19 02:23, Exil wrote:
>>>> On Thursday, 13 June 2019 at 21:26:37 UTC, Tim wrote:
>>>>> On Thursday, 13 June 2019 at 20:55:34 UTC, Exil wrote:
>>>>>> This problem happens because you are used @trusted. If you used @safe you wouldn't be able to increment pointers and modify the values the way you did in @trusted.
>>>>>
>>>>> Here is a completly @safe version:
>>>>>
>>>>> import std.stdio;
>>>>>
>>>>> static int[2] data;
>>>>> static int[253] data2;
>>>>>
>>>>> void test(bool b) @safe
>>>>> {
>>>>>     data[b]++;
>>>>> }
>>>>>
>>>>> void main() @safe
>>>>> {
>>>>>     bool b = void;
>>>>>     writeln(data, data2);
>>>>>     test(b);
>>>>>     writeln(data, data2);
>>>>> }
>>>>>
>>>>> If b is valid only data can change. But for me data2 changes, even though it is never written to.
>>>>
>>>> This is a bug.
>>>
>>> Yes. And the bug is either
>>> - that `void` initialization of `bool` is `@safe`.
>>> - that `void` initialization of `bool` can produce a value that is both `true` and `false`.
>>> - that boolean values are assumed to be either `true` or `false` in @safe code.
>>>
>>> Which one seems most plausible to you?
>> 
>> None of them. Code generation is incorrect for boolean values.
>> ...
>
> That's the second option above... And I already explained why that answer is not satisfactory.

It's not limited to void initialization, so no... More accurately code generation is incorrect for bools.

>>>> It seems it doesn't do bounds checking for the index because it is a bool value and it is less than the static type. If you change the array to a ____dynamically allocated____ one, an assert is hit as expected.
>>>
>>> That's not expected, this is just the compiler not being as smart as it could be given the available information.
>> 
>> A value is used that is out of bounds of the array, yes that assert is expected.
>
> The compiler is able to derive that it is not out of bounds...

Not for dynamic arrays, which is what we are talking about.
June 13, 2019
On Thu, Jun 13, 2019 at 7:15 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/13/2019 5:35 PM, Timon Gehr wrote:
> > It is obvious that allocation has to be pure. However, accessing the address of your data is impure. The runtime systems of pure functional languages also allocate memory, but the addresses are not exposed to the pure user code.
>
> I know that technically you are correct, but I'm not so sure it matters for D's use of purity.

I mean, you've been arguing strict adherence to "@safe means memory safe and nothing else", and explicitly rejecting common-sense in favour of the definition...
June 13, 2019
On Thu, Jun 13, 2019 at 9:02 PM Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, June 13, 2019 9:22:48 PM MDT Walter Bright via Digitalmars-d wrote:
> > On 6/13/2019 6:05 PM, Timon Gehr wrote:
> > > If the result is mutable, there should be no common subexpression elimination because it affects aliasing, but for immutable results, the compiler should be allowed to pool identical values at its own leisure. (Note that this is not currently done.)
> >
> > I've suspected for a long time that the value of pure functions is not CSE, but the knowledge that there aren't side effects. Side effects are the bane of understanding code.
>
> Given how restricted the situations are when you can elide function calls with pure functions (especially without doing code flow analysis), I don't see how it's really any benefit at all aside from maybe math code. IIRC, duplicate pure function calls currently only get elided within the same expression, but even if it were within the same statement, that sort of thing is pretty rare outside of code that's doing math.
>
> On the other hand, knowing that a pure function doesn't access anything that it's not given is of value even if you have no strongly pure functions in your code anywhere.
>
> So, I've defintely come to the conclusion that functional purity really isn't one of the benefits (let alone the primary benefit) of D's pure in practice.

FWIW, I have a codebase where `pure` has immense value, because it's
so highly multi-threaded, that any impure operation can not be trusted
not to crash spectacularly.
We need confidence that work functions absolutely do not back-door
access any data. So it's a confidence and correct-ness thing for us,
not an optimisation thing.
June 14, 2019
On Friday, 14 June 2019 at 01:46:40 UTC, Timon Gehr wrote:
> On 14.06.19 02:15, Jonathan M Davis wrote:
>> Well, I fail to see how allowing access to private data is not @safe, since
>> it does not inherently mean that there are going to be problems with memory
>> safety.
>
> int[N] array;
> static assert(0<N);
>
> struct VerifiedIndex{
>     private int index_=0;
>     @disable this(int); // shouldn't be necessary, but it is
>     @property int index()@safe{ return index_; }
>     @property void index(int i)@trusted{ // no, this can't be @safe
>         enforce(0<=x&&x<N, "index out of bounds");
>         index_=i;
>     }
>     int read()@trusted{ return array.ptr[index]; }
>     void write(int x)@trusted{ array.ptr[index]=x; }
> }
>
> This kind of thing is necessary. You need to give @trusted a chance to provide a @safe interface. This is very hard if all @safe code can randomly assign to your private members.

X.tupleof in context C should be @system where X has members not otherwise visible from C (e.g. private from a different module, package from the wrong package). In other cases, it's @safe.
June 14, 2019
On 14.06.19 07:20, ag0aep6g wrote:
> On 14.06.19 02:23, Timon Gehr wrote:
>> On 14.06.19 00:27, Manu wrote:
> [...]
>>> Breaking private access is not in any way shape or form a memory
>>> safety violation.
>>>
>>
>> It can very well be if the private data is managed by a @trusted interface that assumes @safe code cannot meddle with that data because it is private.
> 
> Strictly speaking, @trusted can't assume that. One can always write @safe code in the same module and (accidentally) mess with the private data that way.
> ...

Yes, it's a problem. @safe functions in a module with @trusted functions operating on private data should be a red flag. The value of @trusted is suspect if you can introduce memory corruption by only adding/editing @safe code.

> An @trusted function that relies on `private` for safety does not present an @safe interface to its own module.
> 
> In practice, that's often overlooked or ignored, though. With a restricted tupleof, at least the damage is contained in one module.

There's also the issue that sometimes you want to call a @safe function from a @trusted function, and this is currently allowed. However, technically, the @trusted function is not able to assume that the @safe function has no bugs, because they could be later introduced when the @safe code is edited.
June 14, 2019
On 14.06.19 05:22, Walter Bright wrote:
> On 6/13/2019 6:05 PM, Timon Gehr wrote:
>> If the result is mutable, there should be no common subexpression elimination because it affects aliasing, but for immutable results, the compiler should be allowed to pool identical values at its own leisure. (Note that this is not currently done.)
> 
> I've suspected for a long time that the value of pure functions is not CSE, but the knowledge that there aren't side effects. Side effects are the bane of understanding code.
> 

So you would argue that `pure` functions should be able to read global mutable state?
June 14, 2019
On 14.06.19 04:10, Walter Bright wrote:
> On 6/13/2019 5:35 PM, Timon Gehr wrote:
>> It is obvious that allocation has to be pure. However, accessing the address of your data is impure. The runtime systems of pure functional languages also allocate memory, but the addresses are not exposed to the pure user code.
> 
> I know that technically you are correct, but I'm not so sure it matters for D's use of purity.

`pure` in D already provides value. It would provide more value if it also restricted access to addresses.

In any case, the spec currently states:

`For cases where the compiler can guarantee that a pure function cannot alter its arguments, it can enable full, functional purity (i.e. the guarantee that the function will always return the same result for the same arguments).`

This is blatantly wrong if `pure` functions and your notion of "the same result" are able to access memory addresses. If your notion of "the same arguments" is able to access memory addresses, the guarantee is basically meaningless (and still does not exist).


If I see:
int foo(immutable(int)[] a)pure;

I want to be able to assume the result of `foo` is a function of the length and elements of `a`. This is currently not the case and it bothers me.
June 14, 2019
On 14.06.19 07:43, Exil wrote:
> On Friday, 14 June 2019 at 01:22:35 UTC, Timon Gehr wrote:
>> On 14.06.19 03:17, Exil wrote:
>>> On Friday, 14 June 2019 at 01:12:21 UTC, Timon Gehr wrote:
>>>> On 14.06.19 02:23, Exil wrote:
>>>>> On Thursday, 13 June 2019 at 21:26:37 UTC, Tim wrote:
>>>>>> On Thursday, 13 June 2019 at 20:55:34 UTC, Exil wrote:
>>>>>>> This problem happens because you are used @trusted. If you used @safe you wouldn't be able to increment pointers and modify the values the way you did in @trusted.
>>>>>>
>>>>>> Here is a completly @safe version:
>>>>>>
>>>>>> import std.stdio;
>>>>>>
>>>>>> static int[2] data;
>>>>>> static int[253] data2;
>>>>>>
>>>>>> void test(bool b) @safe
>>>>>> {
>>>>>>     data[b]++;
>>>>>> }
>>>>>>
>>>>>> void main() @safe
>>>>>> {
>>>>>>     bool b = void;
>>>>>>     writeln(data, data2);
>>>>>>     test(b);
>>>>>>     writeln(data, data2);
>>>>>> }
>>>>>>
>>>>>> If b is valid only data can change. But for me data2 changes, even though it is never written to.
>>>>>
>>>>> This is a bug.
>>>>
>>>> Yes. And the bug is either
>>>> - that `void` initialization of `bool` is `@safe`.
>>>> - that `void` initialization of `bool` can produce a value that is both `true` and `false`.
>>>> - that boolean values are assumed to be either `true` or `false` in @safe code.
>>>>
>>>> Which one seems most plausible to you?
>>>
>>> None of them. Code generation is incorrect for boolean values.
>>> ...
>>
>> That's the second option above... And I already explained why that answer is not satisfactory.
> 
> It's not limited to void initialization, so no...

That complaint makes no sense. `void` initialization is a most general way to mess with `bool` memory.

> More accurately code generation is incorrect for bools.
> ...

You can't blame a data type for having invariants.

>>>>> It seems it doesn't do bounds checking for the index because it is a bool value and it is less than the static type. If you change the array to a ____dynamically allocated____ one, an assert is hit as expected.
>>>>
>>>> That's not expected, this is just the compiler not being as smart as it could be given the available information.
>>>
>>> A value is used that is out of bounds of the array, yes that assert is expected.
>>
>> The compiler is able to derive that it is not out of bounds...
> 
> Not for dynamic arrays, which is what we are talking about.

You have never shown your code but I assume it is something like:

data=new int[](2);
bool b=void;
data[b]++;

You can plainly see that the length of `data` is 2. So can a compiler (possibly after inlining, if data is a global dynamic array and your data[b]++ is in a static function). And anyway, if the compiler assumes that a value is either 0 or 1 and this fails to be the case, you have UB on your hands and you can't expect anything in particular to happen.
June 14, 2019
On Friday, 14 June 2019 at 12:47:12 UTC, Timon Gehr wrote:
> On 14.06.19 07:43, Exil wrote:
>> On Friday, 14 June 2019 at 01:22:35 UTC, Timon Gehr wrote:
>>> On 14.06.19 03:17, Exil wrote:
>>>> On Friday, 14 June 2019 at 01:12:21 UTC, Timon Gehr wrote:
>>>>> On 14.06.19 02:23, Exil wrote:
>>>>>> On Thursday, 13 June 2019 at 21:26:37 UTC, Tim wrote:
>>>>>>> On Thursday, 13 June 2019 at 20:55:34 UTC, Exil wrote:
>>>>>>>> This problem happens because you are used @trusted. If you used @safe you wouldn't be able to increment pointers and modify the values the way you did in @trusted.
>>>>>>>
>>>>>>> Here is a completly @safe version:
>>>>>>>
>>>>>>> import std.stdio;
>>>>>>>
>>>>>>> static int[2] data;
>>>>>>> static int[253] data2;
>>>>>>>
>>>>>>> void test(bool b) @safe
>>>>>>> {
>>>>>>>     data[b]++;
>>>>>>> }
>>>>>>>
>>>>>>> void main() @safe
>>>>>>> {
>>>>>>>     bool b = void;
>>>>>>>     writeln(data, data2);
>>>>>>>     test(b);
>>>>>>>     writeln(data, data2);
>>>>>>> }
>>>>>>>
>>>>>>> If b is valid only data can change. But for me data2 changes, even though it is never written to.
>>>>>>
>>>>>> This is a bug.
>>>>>
>>>>> Yes. And the bug is either
>>>>> - that `void` initialization of `bool` is `@safe`.
>>>>> - that `void` initialization of `bool` can produce a value that is both `true` and `false`.
>>>>> - that boolean values are assumed to be either `true` or `false` in @safe code.
>>>>>
>>>>> Which one seems most plausible to you?
>>>>
>>>> None of them. Code generation is incorrect for boolean values.
>>>> ...
>>>
>>> That's the second option above... And I already explained why that answer is not satisfactory.
>> 
>> It's not limited to void initialization, so no...
>
> That complaint makes no sense. `void` initialization is a most general way to mess with `bool` memory.

It is not a complaint, it is a fact. You can set bool to be a different value. Disabling void initialization in @safe is just a bandaid for the larger problem. If you fix code generation, then you won't have instances where it appears as though the value is both true and false.

>> More accurately code generation is incorrect for bools.
>> ...
>
> You can't blame a data type for having invariants.
>
>>>>>> It seems it doesn't do bounds checking for the index because it is a bool value and it is less than the static type. If you change the array to a ____dynamically allocated____ one, an assert is hit as expected.
>>>>>
>>>>> That's not expected, this is just the compiler not being as smart as it could be given the available information.
>>>>
>>>> A value is used that is out of bounds of the array, yes that assert is expected.
>>>
>>> The compiler is able to derive that it is not out of bounds...
>> 
>> Not for dynamic arrays, which is what we are talking about.
>
> You have never shown your code but I assume it is something like:

Why are you assuming anything? You are just assuming how it was implemented to fit your argument, which is obviously biased. The code he posted used a static global, it would only make sense to also use a static global.

> data=new int[](2);
> bool b=void;
> data[b]++;
>
> You can plainly see that the length of `data` is 2. So can a compiler (possibly after inlining, if data is a global dynamic array and your data[b]++ is in a static function). And anyway, if the compiler assumes that a value is either 0 or 1 and this fails to be the case, you have UB on your hands and you can't expect anything in particular to happen.

At the very least an assert should be thrown. If the compiler doesn't generates assembly that uses the full byte contents of the bool, it should be checking that it is within bounds. In regards to an array being accessed, that is defined behavior.




June 15, 2019
On 14.06.19 23:16, Exil wrote:
> On Friday, 14 June 2019 at 12:47:12 UTC, Timon Gehr wrote:
>> On 14.06.19 07:43, Exil wrote:
>>> On Friday, 14 June 2019 at 01:22:35 UTC, Timon Gehr wrote:
>>>> On 14.06.19 03:17, Exil wrote:
>>>>> On Friday, 14 June 2019 at 01:12:21 UTC, Timon Gehr wrote:
>>>>>> On 14.06.19 02:23, Exil wrote:
>>>>>>> On Thursday, 13 June 2019 at 21:26:37 UTC, Tim wrote:
>>>>>>>> On Thursday, 13 June 2019 at 20:55:34 UTC, Exil wrote:
>>>>>>>>> This problem happens because you are used @trusted. If you used @safe you wouldn't be able to increment pointers and modify the values the way you did in @trusted.
>>>>>>>>
>>>>>>>> Here is a completly @safe version:
>>>>>>>>
>>>>>>>> import std.stdio;
>>>>>>>>
>>>>>>>> static int[2] data;
>>>>>>>> static int[253] data2;
>>>>>>>>
>>>>>>>> void test(bool b) @safe
>>>>>>>> {
>>>>>>>>     data[b]++;
>>>>>>>> }
>>>>>>>>
>>>>>>>> void main() @safe
>>>>>>>> {
>>>>>>>>     bool b = void;
>>>>>>>>     writeln(data, data2);
>>>>>>>>     test(b);
>>>>>>>>     writeln(data, data2);
>>>>>>>> }
>>>>>>>>
>>>>>>>> If b is valid only data can change. But for me data2 changes, even though it is never written to.
>>>>>>>
>>>>>>> This is a bug.
>>>>>>
>>>>>> Yes. And the bug is either
>>>>>> - that `void` initialization of `bool` is `@safe`.
>>>>>> - that `void` initialization of `bool` can produce a value that is both `true` and `false`.
>>>>>> - that boolean values are assumed to be either `true` or `false` in @safe code.
>>>>>>
>>>>>> Which one seems most plausible to you?
>>>>>
>>>>> None of them. Code generation is incorrect for boolean values.
>>>>> ...
>>>>
>>>> That's the second option above... And I already explained why that answer is not satisfactory.
>>>
>>> It's not limited to void initialization, so no...
>>
>> That complaint makes no sense. `void` initialization is a most general way to mess with `bool` memory.
> 
> It is not a complaint, it is a fact.

You disagreed with my assessment, so it is a complaint. Look it up. There is really no basis for attacking my statement for not being general enough, as it referred to the compiler's behavior on a specific code sample.

> You can set bool to be a different value.

Not in a @safe way.

> Disabling void initialization in @safe is just a bandaid for the larger problem.

No. The "larger problem" is that assigning random data to memory occupied by a data type with an invariant can lead to UB. @safe prevents UB, while in @system/@trusted code it is your own responsibility, so this actually solves the problem.

> If you fix code generation, then you won't have instances where it appears as though the value is both true and false.
> 
>>> More accurately code generation is incorrect for bools.
>>> ...
>>
>> You can't blame a data type for having invariants.
>> ...

...?

>>>>>>> It seems it doesn't do bounds checking for the index because it is a bool value and it is less than the static type. If you change the array to a ____dynamically allocated____ one, an assert is hit as expected.
>>>>>>
>>>>>> That's not expected, this is just the compiler not being as smart as it could be given the available information.
>>>>>
>>>>> A value is used that is out of bounds of the array, yes that assert is expected.
>>>>
>>>> The compiler is able to derive that it is not out of bounds...
>>>
>>> Not for dynamic arrays, which is what we are talking about.
>>
>> You have never shown your code but I assume it is something like:
> 
> Why are you assuming anything?

Because you didn't provide it.

> You are just assuming how it was implemented to fit your argument, which is obviously biased. The code he posted used a static global, it would only make sense to also use a static global.
> ...

Which I have considered, so your biased "obviously biased" accusation is obviously wrong. I will try to stop replying to your posts as they are anonymous, of poor quality and may actually be written in bad faith. (How likely is it that you would get essentially _every single thing_ horribly wrong?)

>> data=new int[](2);
>> bool b=void;
>> data[b]++;
>>
>> You can plainly see that the length of `data` is 2. So can a compiler (possibly after inlining, if data is a global dynamic array and your data[b]++ is in a static function). And anyway, if the compiler assumes that a value is either 0 or 1 and this fails to be the case, you have UB on your hands and you can't expect anything in particular to happen.
> 
> At the very least an assert should be thrown.

Of course not. You have an array of length 2 and are indexing it with a `bool`! Throwing a bounds error is never the right thing to do here. If you say `bool` has no invariant and everything except '\0' represents true, then conversion of `bool` to `size_t` needs to be implemented as `(b?1:0)`.

> If the compiler doesn't generates assembly that uses the full byte contents of the bool, it should be checking that it is within bounds. In regards to an array being accessed, that is defined behavior.
> 

If the `bool` has an invariant that says it is always either `0` or `1`, then using a `void`-initialized `bool` is UB.