On Friday, 12 April 2024 at 20:43:50 UTC, Walter Bright wrote:
> https://github.com/WalterBright/documents/blob/984374ca885e1cb10c2667cf872aebc13b4c1663/varRef.md
I am not exactly sure what is this solving, or how it improves code. And DIP draft does not exactly explain that either.
I am afraid D code will then become C++-like, and be riddled with all these refs.
For the last 20 years I was actively avoiding using references in C++ code, (with only exception of const&
being ok, only because this avoids ->
in C++, and implicitly in general tells me that pointer ownership is not being transferred to the called function). And I have seen many companies with large code bases doing the same. One of the main reasons for me to avoid it, is that it is obstructing call site by making things implicit. One could say similar things about lazy
, but I think that is fine, as it is used in way more narrow context. Another reason to avoid are reassignment semantics, and complex interactions with construction, destruction, which are non trivial.
From all C++ devs that I do know in professional setting (most of them 10-20 years writing C++ code every day), in fact not a single one of them, know exact semantics of C++ references. And anybody who said they do for sure, in fact didn't.
In C++, I didn't write a single ref variable in my life (by choice), other than while debugging others code. And not a single (non-const) ref parameter. And it never was limiting me or caused readability problems (quite the contrary actually).
(Usage of &
in lambda capture is fine, as there is no other way, and this is useful. But in D, things are currently inferred automatically by compiler. Plus in lambda capture semantic is pretty clear and very rarely abused in a way that makes code hard to follow).
I would say that ref variables is the worst C++ feature from all its "features".
In C++, they are kind of needed sometimes, i.e. for example when implementing mutable containers, to implement things like x[foo] += 1
, but it can be abused (i.e. if x[foo]
is assigned to auto &z
somewhere first, then one mutates x
in a way, that z
becomes invalid reference, and only then you access z
. But in D, we have nicer and more power ways to deal with things like x[foo] += 1
using op*
family of function. So we do not need these kinds of references most of the time. (I do know some people do use non-const ref return values for functions in D. But it is not exactly needed most of the time, or can be implemented using wrapper structs with some kind of forwarding if really really required).
As of safety. I would say references, as they are in C++, make C++ less safe. Exactly because of extra complications, implicitness, and other issues.
In D, readability is even less of an issue for pointers, as ->
is not required, and one will use a .
, which is nice, and one will sporadically see maybe something like (*x) =
, or similar (rarely, as this is usually used for out parameters for returning multiple values, but that can be easily done with out
or some multi-value return / tuple return maybe). And using *x =
is in fact pretty nice to remind you (and code reviewer, or future you) what is happening exactly.
I am not totally against (it is a choice to use or not use this future), but if it proliferates into libraries (or phobos!), I would be rather disappointed for me personally.
And yes, I do like and use const ref
in D sometimes (i.e. for fixed arrays, or some structs), and sporadically ref
in foreach
which is handy. Still I not needed, I don't. I.e. I trust compiler to not copy some structs in array if I do not modify them for example.
And for classes everything is by "ref" (the object itself, not the variable), so that mostly avoid copying issues, that C++ needs to deal with.
More concretely. Example you show
ref int dark(ref int x, int i) {
ref j = i; // j now points to i
j = 3; // now i is 3 as well
...
and I am already lost basically. Lets say one has very slightly modified same code:
struct A {
~this() {
....
}
}
ref int dark(ref A x, A i) {
ref j = i; // j now points to i
j = A(3); // now i is 3 as well
...
And now, I need to think very hard to know what is actually happening. Or even miss the fact that my assignment probably caused call to A
s destructor. And god forgive there were other references (by pointers) to object in j
previously.
I do not like implicit mechanisms that are not easy to track without extra context.
And I do fail to see why one would complicating language and implementation for very small gain, where in very rare cases where one there would be benefit, doing it explicitly using pointers is in fact better and cleaner by being explicit. If compiler could fully prove correctness, than maybe I could see some benefit, but good luck with that.
You can also see languages like Go, where there are pointers, and no references. And they are perfectly happy with that, with gazillion of libraries showing it is not really an issue.
Regards.