On Friday, 27 May 2016 at 10:04:14 UTC, Nick Treleaven wrote:
On Thursday, 26 May 2016 at 08:29:41 UTC, Marc Schütz wrote:
To elaborate: neither `scope` nor reference counting can ever
protect you against explicit premature destruction of a
still-referenced owner. But there is a slightly different
problematic scenario:
RCArray!int arr = [7];
ref r = arr[0];
arr = [9]; // this releases the old array
r++; // use after free
This is the same situation. There's nothing special about
destroy, it just assigns arr = arr.init. destroy is @safe so in
fact it must work with safe RC.
If this is what destroy does, then yes, that's ok. But it is a
misleading name then, IMO.
You seem to have ignored my suggestion (which maybe wasn't
clear enough) to statically prevent the above from compiling
using:
RCArray(T) {
...
ref opIndex(size_t) return;
Local refs cannot be assigned from a function returning ref if
that function has any parameters marked with the return
attribute. If there is no attribute, local refs + function
returning ref is OK.
Huh? `return` means that the returned reference is owned by the
RCArray struct and must therefore not outlive it. If the RCArray
is a local variable (or parameter), the local ref is always
declared after it (because it must be initialized immediately),
and will have a shorter scope than the RCArray. Therefore, such
an assignment is always accepted.
But this issue exists even without locale `ref`s:
void foo() {
RCArray!int arr = [7];
bar(arr, arr[0]);
}
void bar(ref RCArray!int arr, ref int r) {
arr = [9]; // this releases the old array
r++; // use after free
}
This is the reason for the @rc DIP.
It can be solved in one of two ways: Either by making the
owner (`arr`) non-mutable during the existence of the
references, thereby forbidding the call to `bar()` (I would
prefer this one, as it's cleaner and can be used for many more
things, e.g. the byLine problem)
I don't see directly how this affects byLine.front, that does
not return a reference.
It returns a reference in the wider sense, namely a slice to a
private buffer that gets overwritten by each call to `byLine`.
Currently, DIP25 only applies to `ref`s in the narrow sense, but
I'm assuming it will be generalized to include pointer, slices,
class references, AAs and hidden context pointers.
Making the ByLine range constant as long as there's a reference
to its buffer would prevent surprises like this:
auto lines = stdin.byLine.array;
// => all elements of `lines` are the same, should have used
`byLineCopy`
By the way, there's a theoretical third possibility:
Force-invalidating the references after the owner has
(potentially) been mutated. But this would require very advanced
data flow tracking and is probably impossible to implement in the
general case.