Readonly asserts and more

bearophile bearophileHUGS at lycos.com
Mon Mar 1 11:27:42 PST 2010


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



More information about the Digitalmars-d mailing list