null references redux + Looney Tunes
bearophile
bearophileHUGS at lycos.com
Sun Oct 4 15:49:38 PDT 2009
To test my level of ignorance of D2, and to test how structs can be used to implement complex numbers in the std lib I have done few experiments with something simile, subsets of integers.
I have found some problems, some of them may come from my ignorance. This is a natural number:
import std.stdio: writeln;
struct Natural {
int x = 1;
alias x this;
invariant() {
assert(x >= 1);
}
}
void main() {
Natural x, y;
x = 10;
y = -20; // OK, invariant() isn't called because it's a direct access
// From the D2 docs: http://www.digitalmars.com/d/2.0/class.html#Invariant
// The invariant can be checked when a class object is the argument
// to an assert() expression, as:
assert(x); // test.d(20): Error: expression x of type Natural does not have a boolean value
}
It seems invariant() can be used in structs too (even if in D2 docs they are named class invariants), but I think the assert(x) doesn't work.
To solve the problem of the invariant not being called in the assignment I have written this second version:
import std.stdio: writeln;
import std.conv: to;
struct Natural {
int x_ = 1;
int x() { return this.x_; }
int x(int xx) { this.x_ = xx; return xx; }
alias x this;
invariant() { assert(this.x_ >= 1, "not a natural"); }
string toString() { return to!string(this.x_); }
}
void main() {
Natural x, y;
x = 10;
writeln(x, " ", x + x * 3); // OK
// a problem: the error message gives the line number of the
// assert instead of the assignment
y = -20; // core.exception.AssertError at test2.d(11): not a natural
}
Now it works better, but the assert gives an unhelpful line number.
This is a variant, a ranged value:
import std.stdio: writeln;
import std.conv: to;
struct Ranged(int RANGED_MIN, int RANGED_MAX) {
int x_ = RANGED_MIN;
int x() { return this.x_; }
int x(int xx) { this.x_ = xx; return xx; }
alias x this;
invariant() {
//assert(this.x_ >= RANGED_MIN, "Ranged value too much small");
assert(this.x_ < RANGED_MAX, "Ranged value too much big");
}
string toString() { return to!string(this.x_); }
}
void main() {
typedef Ranged!(10, 20) ranged;
ranged x;
writeln(x);
ranged y = 1000; // Uh, bypasses the setter, no errors
writeln(y); // 0?
}
I have commented out the first assert to understand better what's happening.
In the line:
ranged y = 1000;
The invariant isn't called, the value 1000 goes nowhere, and even the int x_ = RANGED_MIN; is being bypassed, so in this.x_ goes a zero.
This will be another problem for library-defined complex numbers. So in the end I may like to keep complex numbers in the language for now.
Bye,
bearophile
More information about the Digitalmars-d
mailing list