First Draft: ref For Variable Declarations

Quirin Schroll qs.il.paperinik at gmail.com
Fri Apr 26 09:36:17 UTC 2024


On Sunday, 14 April 2024 at 23:28:07 UTC, Walter Bright wrote:
> I appreciate your thoughts.
>
> I agree that `ref` parameters make it slightly less clear what 
> is happening at the call site. But we don't really put 
> documentation at the call site, we put the documentation at the 
> callee. A `ref` parameter self-documents restrictions on how 
> the pointer is used. `out` goes even further, it says that a 
> value is not being passed in, only out. Pointers come with 
> other behaviors - they can be incremented, and they can be 
> free'd.
>
> In my years of experience, I see a lot of operating system APIs 
> that use a pointer. It's often unclear what is going to happen 
> with that pointer. Most of the time, they stick to `ref` 
> semantics, but not always. Like a `char*` being actually a 
> string in C, rather than a reference to a `char`.

Zig tries to be explicit about how an argument is passed: It only 
allows pass-by-value. If you want to pass by reference, pass the 
address by value.

While this looks like the same mess as in C, Zig has a whole zoo 
of pointer types that indicate the various intentions behind a 
pointer. Zig distinguishes a single-element pointer and a pointer 
into an array; only the latter allows pointer arithmetic. Zig 
also distinguishes pointers into arrays that are 
sentinel-terminated.
A C `char*` that’s intended to be a string would be typed as 
pointer into 0-terminated array of `char`. A C `int*` that’s 
supposed to be `ref` or `out` would be a single-element pointer 
to `int`. Zig also has `null` indicators, i.e. it distinguishes 
pointers and slices that can be null and those that can’t be.

It’s a complete 180° from what D’s philosophy is. D style is 
passing a `ref` or a slice when you can. This means when you see 
a pointer, it means something more complicated is going on. One 
thing that I’d never do because it would confuse my future self: 
Passing `*null` via ref. It’s legal in D (not in C++), but I have 
never seen that being meaningfully used, i.e. I have yet to see 
an API that takes some `ref` parameter and the docs say that 
passing `*null` does X and Y.

I can see the value in both philosophies. While they seem 
incompatible, they’re not. D can take a concept or two from Zig.

Notably, in C#, to pass by reference, you have to put `ref` also 
before the argument in the function call. This ship has sailed 
for D. Also in C#, `ref` variables can be reassigned:
```cs
int i = 0, j = 1;
ref int r = ref i;
r = 2; // as if i = 2
r = ref j; // r points to j now
r = 3; // as if j = 3
```
I’m not saying D should allow reassigning `ref`, just pointing 
out that C#’s `ref` is quite different to D’s `ref` in that 
regard.


More information about the dip.development mailing list