References in D
Chad J
chadjoan at __spam.is.bad__gmail.com
Sat Oct 6 12:42:56 PDT 2012
On 10/06/2012 04:18 AM, "Franciszek Czekała" <home at valentimex.com>" wrote:
> On Saturday, 6 October 2012 at 04:10:28 UTC, Chad J wrote:
>>
>> I find this to be very suboptimal at the least.
>>
>> This prevents null values from traveling "up" the stack, but still
>> allows them to move "down" (as return values) and allows them to
>> survive multiple unrelated function calls.
>>
>> It catches null values once they've already ended up in a place they
>> shouldn't be. Too late.
>>
>> Nulls can also be placed into variables within structs or classes that
>> then get passed around. Checking for those can require some complex
>> traversal: impractical for casual one-off checks at the start of a
>> function in some cases.
>>
>> void main()
>> {
>> void* x = a(b());
>> c();
>> while(goobledegook)
>> {
>> x = p();
>> d(x);
>> }
>> e(x); /+ Crash! x is null. +/
>> }
>>
>> Where did x's null value come from? Not a. Not p; the while loop
>> happened to be never executed. To say "b" would be closer, but still
>> imprecise. Actually it was created in the q() function that was called
>> by u() that was called by b() which then created a class that held the
>> null value and was passed to a() that then dereferenced the class and
>> returned the value stored in the class that happened to be null. nulls
>> create very non-local bugs, and that's why they frustrate me to no end
>> sometimes.
>>
>> What I really want to know is where errant null values come FROM.
>>
>> I also want to know this /at compile time/, because debugging run-time
>> errors is time consuming and debugging compile-time errors is not.
>>
>> The above example could yield the unchecked null assignment at compile
>> time if all of the types involved were typed as non-nullable, except
>> for the very bare minimum that needs to be nullable. If something is
>> explicitly nullable, then its enclosing function/class is responsible
>> for handling null conditions before passing it into non-nullable space.
>> If a function/class with nullable state tries to pass a null value
>> into non-nullable space, then it is a bug. This contains the
>> non-locality of null values as much as is reasonably possible.
>>
>> Additionally, it might be nice to have a runtime nullable type that
>> uses its object file's debugging information to remember which
>> file/function/line that its null value originated from (if it happens
>> to be null at all). This would make for some even better diagnostics
>> when code that HAS to deal with null values eventually breaks and
>> needs to dump a stack trace on some poor unsuspecting sap (that isn't
>> me) or ideally sends an email to the responsible staff (which is me).
>
>> returned the value stored in the class that happened to be null.
>
> Happened? "I was driving carefully and then it happened I drove into the
> tree, officer." Every function should define its interface, its contract
> with the outside world. If a() function returns a pointer it is a part
> of the contract whether it can be null. Two possibilities:
>
> A) The contract says it can be null. Then it is your duty to check for
> null. Period. Learn to read the signs before you start driving. You
> assinged the value without checking, it is your fault, not a()'s, not
> the language's.
>
I am unconvinced by the driving analogy. When driving, most of the
important bits become muscle memory (acceleration, braking, turn
signals, etc) and the rest falls under the category of "be aware". The
factor in our advantage is that awareness in driving usually only
requires you to focus on one thing at a time: "turn your head before
changing lanes or turning", "look at the sides of the road", "check your
rear view", etc.
Programming involves the management of complex logical relationships.
It is more akin to mathematics. I could continue, but I'll stop here
and leave it at "I'm unconvinced".
Even if I grant the premise, I'll expand on what Timon wrote:
We'd have a lot less accidents if well-designed robots drove our
vehicles for us (with manual overrides, of course).
> B) The description of a() says the return value cannot be null. Then a()
> should check its return value before returning or make otherwise sure it
> is not null. If it returns null it is a bug. One of the infinite number
> of possible bugs that can happen. Again it is not the problem of the
> language. The problem of divergence of specification and code is a human
> problem that cannot be solved formally. Insistance on formal tools is a
> misunderstanding that leads to design bloat and eventually failure (Ada).
>
As I understand it, you would have written my code snippet this way:
void main()
{
MyType j = b();
assert( j !is null );
assert( j.qux !is null );
assert( j.qux.yarly !is null ); /+ Crash! yarly is null. +/
void* x = a(j);
assert( x !is null );
c();
while(goobledegook)
{
x = p();
assert(x !is null);
d(x);
// Note: be sure to put this one in!
// The previous dev forgot it...
assert(x !is null);
}
e(x);
}
If you feel that this is misrepresentative, then please provide your
own. As it stands: give me non-null types, because I like mine better.
> D competes directly with C++ as Ada did before. Ada drowned under the
> weight of its "safety" and so will D if it goes the same route. The only
> thing needed now are mature compilers and good systems API integration.
> If anything I would rather consider removing features from the language
> than adding them.
>
>
Given the two snippets I currently see in my mind's eye that represent
our two different philosophies, I do not see the "weight" of this
safety. I think it makes for much more concise code, and a faster
development process because I don't have to worry about inane stuff like
checking for nulls. If I don't have to worry about inane stuff, then I
can allocate those short-term memory slots to solving problems that are
actually novel and interesting.
More information about the Digitalmars-d
mailing list