On Wednesday, 5 September 2012 at 11:01:50 UTC, Artur Skawina
wrote:
On 09/04/12 20:19, Era Scarecrow wrote:
I ask you, how do you check if it's a null pointer? &s?
Yes, obviously. If you need to do that manually.
But you shouldn't have to.
int getx(ref S s)
//How does this make sense?? it looks wrong and is misleading
in {assert(&s); }
body {return s.x); }
It looks correct and is perfectly obvious. But see below - you
don't need to do this manually - the compiler does it for you
when calling methods and could handle the UFCS case too.
How I'm understanding references in D (And perhaps I'm repeating
myself in two different topics) is they point to live variables
(IE guaranteed pointers), and remains this way until you return
from that function.
This is entirely valid and simplifies things. Remember in D we
want the language to 'do the right thing', but if you make
references where it works to 'sometimes works' then it becomes a
problem (pointers 'sometimes' work and are not @safe, while ref
is @safe). Checking the address of a reference shouldn't be
needed, since it should be dereferenced at where it was called at
if need be (throwing it there).
Any side effects that may rely on the validity of the 'pointer'
(once the function ends) are compromised afterwards (I'm always
assume you pass local variables for this logic, since it's likely
80% of the time).
Would you REALLY want to mark every single function that uses
ref as @trusted? You're then blindly telling the compiler to
'shut up' so you can use the code and ignoring the checking; Or
am I wrong?
int getItem(string[] inp, string cmp) @safe {
//foreach not @safe!
//only works not @safe or blindly adding @trusted
foreach(i, ref s; inp) {
if (s == cmp)
return i;
}
//still might not compile, if foreach calls opApply
//(Even if it doesn't use the reference).
foreach(i, s; inp) {
}
}
More importantly, if it's now a possibility do we have to
start adding checks everywhere?
int getx(S *s)
in {assert(s); } //perfectly acceptable check, we know it's
a pointer
body {return s.x); }
struct S { int i; auto f() { return i; } }
int main() {
S* s;
return s.f();
}
This program will assert at runtime (and (correctly) segfault
in a release-build). The compiler inserts not-null-this checks
for "normal" methods in non-release mode, and could also do
that before invoking any UFCS "method". So you wouldn't need to
check for '!!&this' yourself.
I thought those checks weren't added (via the compiler) since if
it causes a seg fault the CPU would catch it and kill the program
on it's own (just add debugging flags); If you added the checks
they would do the same thing (More buck for the same bang).
The problem w/ these checks is that they can not be disabled
per-type - which prevents certain valid uses. The
compiler-inserted assertions fire also when the methods can
deal with null-this themselves (happens eg. when dealing with
'C' APIs and libraries, when you want to keep the C part as
unmodified as possible). But that is a different issue.