September 04, 2017
On Monday, 4 September 2017 at 09:15:30 UTC, ag0aep6g wrote:
> On 09/04/2017 06:10 AM, Moritz Maxeiner wrote:
>> Indeed, but it also means that - other than null dereferencing - pointer issues can by made into reference issues my dereferencing a pointer and passing that into a function that takes that parameter by reference.
>
> Why "other than null dereferencing"? You can dereference a null pointer and pass it in a ref parameter. That doesn't crash at the call site, but only when the callee accesses the parameter:
>
> [...]

Because I was ignorant and apparently wrong, thanks for the correction.
Still, though, this is surprising to me, because this means taking the address of a parameter passed by reference (which is in your case is typed as an existing int) can be null. Is this documented somewhere (couldn't find it in the spec and it seems like a bug to me)?
September 04, 2017
On 09/04/2017 11:47 AM, Moritz Maxeiner wrote:
> Still, though, this is surprising to me, because this means taking the address of a parameter passed by reference (which is in your case is typed as an existing int) can be null. Is this documented somewhere (couldn't find it in the spec and it seems like a bug to me)?

I'm only aware of this part of the spec, which doesn't say much about ref parameters:

https://dlang.org/spec/function.html#parameters

g++ accepts the equivalent C++ code and shows the same behavior. But, as far as I can tell, it's undefined behavior there, because dereferencing null has undefined behavior.

In D, dereferencing a null pointer is expected to crash the program. It's allowed in @safe code with that expectation. So it seems to have defined behavior that way.

But if a dereferencing null must crash the program, shouldn't my code crash at the call site? Or is there an exception for ref parameters? Any way, the spec seems to be missing some paragraphs that clear all this up.
September 04, 2017
On Monday, 4 September 2017 at 10:24:48 UTC, ag0aep6g wrote:
> On 09/04/2017 11:47 AM, Moritz Maxeiner wrote:
>> Still, though, this is surprising to me, because this means taking the address of a parameter passed by reference (which is in your case is typed as an existing int) can be null. Is this documented somewhere (couldn't find it in the spec and it seems like a bug to me)?
>
> I'm only aware of this part of the spec, which doesn't say much about ref parameters:
>
> https://dlang.org/spec/function.html#parameters
>
> g++ accepts the equivalent C++ code and shows the same behavior. But, as far as I can tell, it's undefined behavior there, because dereferencing null has undefined behavior.
>
> In D, dereferencing a null pointer is expected to crash the program. It's allowed in @safe code with that expectation. So it seems to have defined behavior that way.

Yes, which is why I wrongly assumed that turning a null pointer into a reference would crash the program (as such references can't be tested for being null, you'd have to turn them back into a pointer to test).

>
> But if a dereferencing null must crash the program, shouldn't my code crash at the call site? Or is there an exception for ref parameters? Any way, the spec seems to be missing some paragraphs that clear all this up.

Yes, that is what I meant by saying it looks like a bug to me. It really ought to crash at the call site imho; this would require injecting null checks at the call site when the argument is a pointer dereference.
September 04, 2017
On Sunday, 3 September 2017 at 03:04:58 UTC, Uknown wrote:
> In C, the `restrict` keyword implies that 2 or more pointer arguments in a function call do not point to the same data.

I really don't see where the restrict keyword is needed at all, neither in C nor in D. If you want to imply to the compiler that there is no need to reload the pointed data between uses, just assign it to a local.


September 04, 2017
On Sunday, 3 September 2017 at 03:04:58 UTC, Uknown wrote:
> I just hope to have a nice discussion on this topic here.
>
> Thanks!
>

You might find interesting the reference capabilities of Pony:
https://tutorial.ponylang.org/capabilities/reference-capabilities.html

So with respect to restrict, there are a few that might be relevant.

iso - can only have one reference
box - similar to const function parameters in D, can give out read-only views
trn - sort of the reverse of const, it's like a write unique, you can write to, but other people cannot

When I think of restrict, it's like telling the compiler that these two pointers don't overlap their data. By contrast, if you pass parameters to a function with these reference capabilities, then it would be providing the compiler slightly different information. If you pass iso, it tells the compiler that no other variable pointers to this variable. If you use box (const), you're telling the compiler that you won't modify it in this function. If you use trn, you're telling the compiler that this reference is the only way to modify the variable (i.e. another variable in the function cannot modify it).

I'm not an expert on pony or anything, so I'm not sure how complicated this makes things with aggregate types.
September 04, 2017
On Monday, 4 September 2017 at 09:47:12 UTC, Moritz Maxeiner wrote:
> On Monday, 4 September 2017 at 09:15:30 UTC, ag0aep6g wrote:
>> On 09/04/2017 06:10 AM, Moritz Maxeiner wrote:
>>> Indeed, but it also means that - other than null dereferencing - pointer issues can by made into reference issues my dereferencing a pointer and passing that into a function that takes that parameter by reference.
>>
>> Why "other than null dereferencing"? You can dereference a null pointer and pass it in a ref parameter. That doesn't crash at the call site, but only when the callee accesses the parameter:
>>
>> [...]
>
> Because I was ignorant and apparently wrong, thanks for the correction.
> Still, though, this is surprising to me, because this means taking the address of a parameter passed by reference (which is in your case is typed as an existing int) can be null. Is this documented somewhere (couldn't find it in the spec and it seems like a bug to me)?

LDC treats passing `null` to a reference parameter as UB.
It doesn't matter when the program crashes after passing null to ref, exactly because it is UB.
Because the caller has to do the dereferencing (semantically) you only have to do the null-check in the caller, and not in callee. This removes a ton of manual null-ptr checks from the code, and enables more optimizations too.
For class parameters, they are pointers not references, as in: it is _not_ UB to pass-in `null`. Very unfortunate, because it necessitates null-ptr checks everywhere in the code, and hurts performance due to missed optimization opportunities.

(The spec requires crashing on null dereferencing, but this spec bit is ignored by DMD and LDC, I assume in GDC too. Crashing on `null` dereferencing requires a null-check on every dereferencing through an unchecked pointer, because 0 might be a valid memory access, and also because ptr->someDataField is not going to lookup address 0, but 0+offsetof(someDataField) instead, e.g. potentially addressing a valid low address at 1000000, say.)

- Johan

September 04, 2017
On Monday, 4 September 2017 at 14:28:14 UTC, Dukc wrote:
> On Sunday, 3 September 2017 at 03:04:58 UTC, Uknown wrote:
>> In C, the `restrict` keyword implies that 2 or more pointer arguments in a function call do not point to the same data.
>
> I really don't see where the restrict keyword is needed at all, neither in C nor in D. If you want to imply to the compiler that there is no need to reload the pointed data between uses, just assign it to a local.

It's need for auto-vectorization, for example.

I would support an LDC PR for adding a magic UDA to be able to attach 'restrict' with C-semantics to function parameters. E.g.
```
 // add restrict to parameters 1 and 2
void foo(int, int*, int*) @restrict(1,2)
```

-Johan

September 04, 2017
On Monday, 4 September 2017 at 17:58:41 UTC, Johan Engelen wrote:
> On Monday, 4 September 2017 at 09:47:12 UTC, Moritz Maxeiner wrote:
>> On Monday, 4 September 2017 at 09:15:30 UTC, ag0aep6g wrote:
>>> On 09/04/2017 06:10 AM, Moritz Maxeiner wrote:
>>>> Indeed, but it also means that - other than null dereferencing - pointer issues can by made into reference issues my dereferencing a pointer and passing that into a function that takes that parameter by reference.
>>>
>>> Why "other than null dereferencing"? You can dereference a null pointer and pass it in a ref parameter. That doesn't crash at the call site, but only when the callee accesses the parameter:
>>>
>>> [...]
>>
>> Because I was ignorant and apparently wrong, thanks for the correction.
>> Still, though, this is surprising to me, because this means taking the address of a parameter passed by reference (which is in your case is typed as an existing int) can be null. Is this documented somewhere (couldn't find it in the spec and it seems like a bug to me)?
>
> LDC treats passing `null` to a reference parameter as UB.
> It doesn't matter when the program crashes after passing null to ref, exactly because it is UB.

Ok, that's good to know, though it'd be nice for this to be defined somewhere in the language spec.

> Because the caller has to do the dereferencing (semantically) you only have to do the null-check in the caller, and not in callee. This removes a ton of manual null-ptr checks from the code, and enables more optimizations too.

Indeed, which is why I currently think the spec should state that this isn't UB, but has to crash at the call site.

> For class parameters, they are pointers not references, as in: it is _not_ UB to pass-in `null`. Very unfortunate, because it necessitates null-ptr checks everywhere in the code, and hurts performance due to missed optimization opportunities.

Well, technically they are "class references". In any case, they don't require injecting null checks from the compiler in general, as using them in any way will be a null dereference (which the hardware&OS are required to turn into a crash).

>
> (The spec requires crashing on null dereferencing, but this spec bit is ignored by DMD and LDC, I assume in GDC too.
> Crashing on `null` dereferencing requires a null-check on every dereferencing through an unchecked pointer, because 0 might be a valid memory access, and also because ptr->someDataField is not going to lookup address 0, but 0+offsetof(someDataField) instead, e.g. potentially addressing a valid low address at 1000000, say.)

It's not implemented as compiler checks because the "actual" requirement is "the platform has to crash on null dereference" (see the discussion in/around [1]). Essentially: "if your platform doesn't crash on null dereference, don't use D on it (at the very least not @safe D)".
The issue concerning turning a pointer into a reference parameter is that when reading the code it looks like the dereference is happening at the call site, while the resulting compiled executable will actually perform the (null) dereference inside the function on use of the reference parameter. That is why I think the null check should be injected at the call site, because depending on platform support for the crash will may yield the wrong result (if the reference parameter isn't actually used in the function, it won't crash, even though it *should*).

[1] https://forum.dlang.org/post/udkdqogtrvanhbotdoik@forum.dlang.org
September 05, 2017
On Monday, 4 September 2017 at 14:28:14 UTC, Dukc wrote:
> On Sunday, 3 September 2017 at 03:04:58 UTC, Uknown wrote:
>> In C, the `restrict` keyword implies that 2 or more pointer arguments in a function call do not point to the same data.
>
> I really don't see where the restrict keyword is needed at all, neither in C nor in D. If you want to imply to the compiler that there is no need to reload the pointed data between uses, just assign it to a local.

You can see the second answer on this Stack overflow question[1]. It explains how `restrict` can be used in C to tell the compiler that there won't be any aliasing between two pointers, and the optimizations the compiler can do, given this knowledge.

[1] https://stackoverflow.com/questions/745870/realistic-usage-of-the-c99-restrict-keyword#745877
September 05, 2017
On Monday, 4 September 2017 at 18:03:51 UTC, Johan Engelen wrote:
>
> It's need for auto-vectorization, for example.
>
> I would support an LDC PR for adding a magic UDA to be able to attach 'restrict' with C-semantics to function parameters. E.g.
> ```
>  // add restrict to parameters 1 and 2
> void foo(int, int*, int*) @restrict(1,2)
> ```

That probably explains it in case of c. But I still think that D might be able to do this better without language changes. This way (not compiler-checked for errors):
```
for(int i = 0; i < a.length; i+=8)
{   int[8] aVec = a[i .. i+8], bVec = b[i .. i+8], cVec;
    foreach(j; 0 .. 8) cVec[j] = aVec[j].foo(bVec[j]);
    c[i .. i+8] = cVec[];
}
```

Of course, if we want to support this we should construct a high-level library template that chooses the correct vector size for the platform, eliminates that outer for loop and handles uneven array lenghts.