On 10/07/2012 02:22 AM, David Piepgrass wrote:
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.

Since this thread's attracted lots of commotion I thought I'd just drop
by and +1 for non-nullable types, and +1 for your arguments.

I keep wondering, though, if it is 'enough' to solve the null problem,
or if it would be possible to devise a more general mechanism for
solving other problems too, like say, the fact that certain integers
have to always be positive, or if you want to go more general, that a
certain relationship must hold between two structures...


I agree.

Not having used D's invariants so far (well, I haven't used D itself for
a real project actually)... what's stopping D's invariant mechanism from
handling all this?

http://dlang.org/class.html#invariants (as is typical of D
documentation, this says nothing about invariants on structs, but the
page about structs says that they support invariants with an X.)

I mean, problems are detected at runtime this way, and slightly too
late, but still, it would be better than most popular languages that
can't do anything about nulls at all. Since D's devs don't even seem to
have enough time to implement D as described in TDPL (published more
than two years ago), I wouldn't expect to see this feature in the D
language in the near future.

Invariants might work... create a proxy struct and then have assignment always check the invariant. I don't like the idea that they get removed during release mode. I'd like to be able to control which checks I pay for. I think this might just mean that the important thing is overloading assignment to do checks, which could be done in principle, and this could work without invariants and thus give the desired control.

I just haven't had much luck creating proxy types in the past. As of some months ago, D just wasn't there yet. :(

In another post in this thread I mentioned something similar:


It would be cool to have templates like this:

51.  bool isPrime(int val)
52.  {
53.      ...
54.  }

101. Watch!(int,&isPrime) primeNumber = primeGenerator();
102. primeNumber = 8;
103. doStuff();
104. checkPrime(primeNumber); /+ Crash! +/
Error: checkPrime(primeNumber): primeNumber is not prime.
primeNumber: isPrime returned false after assignment at
  (foobar.d, line 102)

~or~

101. Constrain!(int,&isPrime) primeNumber = primeGenerator();
102. primeNumber = 8; /+ Crash! +/
103. doStuff();
104. checkPrime(primeNumber);
foobar.d, line 102: isPrime returned false after assignment.

For convenience one could define this:
alias Constrain!(int,&isPrime) PrimeInt;

Maybe these could be turned on/off in release mode on a case-by-case basis. I would probably leave the checks and tracking in always, with the one exception of code that has been shown (with profiling) to need the extra performance.

Reply via email to