If you think the following idea is useful, then I can turn it into an
enhancement request (or even a little DEP).
Many of the features that D adds to C seems to consist in statically verified
fences and walls that can be added to the flow of information across different
parts of a program state. So such parts can't change each other, hopefully
helping avoid some bugs.
Recently Michel Fortin has written:
>What you really need is to have a const view of the global state. And this
>could apply to all asserts too.<
Generally I'd like a program to behave in the same way in release and not
release mode (Bug 3856 too is related to this). So it can be nice if the type
system assures that asserts have only a const view of the program state.
This shows what I'd like to avoid:
import std.stdio: writeln;
bool test(ref int x) {
x++;
return true;
}
void main() {
int x;
writeln(x);
assert(test(x));
writeln(x); // prints 0 in release mode, 1 otherwise
}
To avoid that, according to Michel, it can be defined a @readonly attribute
that is transitive and is similar to @pure:
import std.stdio: writeln;
@readonly bool test(ref int x) {
x++; // not allowed in a @readonly function
return true;
}
void main() {
int x;
writeln(x);
assert(test(x));
writeln(x);
}
@readonly disallows writing global variables, and instance/static attributes,
but they can be read if visible. Local variables inside the function can be
written/created too as in @pure functions.
@pure functions are a subset of @readonly functions, so the type system has to
allow (code untested):
@pure int sqr1(int x) { return x * x; }
@readonly int sqr2(int x) { return x * x; }
void main() {
@readonly int function(int x)[] funcs = [&sqr1, &sqr2];
}
And it has to disallow:
@pure int sqr1(int x) { return x * x; }
@readonly int sqr2(int x) { return x * x; }
void main() {
@pure int function(int x)[] funcs = [&sqr1, &sqr2];
}
If the D language gains a little more reflectivity, that is a little more
read-only access to some of the metainformation the compiler has about the
code, then @readonly can even become an user-defined attribute defined in a
Phobos module, using only the D language itself (you have to import it to
compile the module). This is a way to extend a bit the D type system with D.
Maybe you can do that with a __traits that allows to know the global and local
names used inside a function plus if they are just read or read/written:
int y;
void foo(int x) {
writeln(x);
y++;
}
foreach (name; __traits(getNamesUsedIn, "foo"))
writefln(typeid(typeof(name)), " ", __traits(isWrittenIn, name, "foo"));
Prints:
int false
int true
Time ago I have shown something related, but here it uses a second language,
JavaScript, on C++ code:
http://lwn.net/Articles/370717/
https://developer.mozilla.org/En/Dehydra/Using_Dehydra
Maybe the @outer attribute I have discussed time ago too can be defined with
those getNamesUsedIn and isWrittenIn traits:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=106098
Bye,
bearophile