Signed word lengths and indexes

bearophile bearophileHUGS at lycos.com
Tue Jun 15 18:56:46 PDT 2010


Walter Bright:

>I'd rephrase that as D supports many different styles. One of those styles is as a "better C".<

D can replace many but not all usages of C; think about programming an Arduino (http://en.wikipedia.org/wiki/Arduino ) with a dmd compiler of today.


>I agree on those points. Those features would not be used when using D as a "better C".<

A problem is that some of those D features can worsen a kernel code. So for example you have to review code to avoid operator overloading usage :-)
There is lot of D compiler complexity useless for that kind of code. A simpler compiler means less bugs and less D manual to read.


>The answer is that C++ doesn't offer much over C that does not involve those trouble causing features. D, on the other hand, offers substantial and valuable features not available in C or C++ that can be highly useful for kernel dev. Read on.<

I don't know if D offers enough of what a kernel developer needs.


>A non-standard feature means the language is inadequate.<

I agree, standard C is not perfect for that purpose.


>There is nothing at all preventing non-standard features from being added to D for specific tasks. There is no reason to believe it is harder to do that for D than to C.<

I agree. (But note that here we are talking just about low level features. Linus has said that such features are important but he desires other things absent in C).


>As for standard features D has that make it more suitable for low level programming than C is:<

I agree.


>Since it has more than C does, and C is used for kernel dev, then it must be enough.<

Kernel C code uses several GCC extensions to the C language. And Linus says he desires higher level features absent from C, C++ and absent from those GCC extensions.


>I'll await your reply there.<

I appreciate your trust, but don't expect me to be able to teach you things about C and the kind of code needed to write a kernel, you have way more experience than me :-)

--------------------

>With all due respect to Linus, in 30 years of professionally writing software, I've found that if you solely base improvements on what customers ask for, all you have are incremental improvements. No quantum leaps, no paradigm shifts, no game changers.<

You are right in general, but I don't know how much you are right regarding Linus.
Linus desires some higher level features but maybe he doesn't exactly know what he desires :-)
I don't know if Linus has ever asked for some of the features of the Sing# language (http://en.wikipedia.org/wiki/Sing_Sharp ), needed to write the experimental Singularity OS.


About Spec#:

>The Spec# language is a superset of the programming language C# extending C# by nonnull types, method contracts, object invariants and an ownership type system [and Spec# also has built-in message passing for concurrency with a syntax to specify message invariants]. The behavior of a Spec# program is checked at runtime and statically verified by Boogie, the Spec# static program verifier [2]. Boogie generates logical verification conditions from a Spec# program. Internally, it uses an automatic theorem prover [7] that analyzes the verification conditions to prove the correctness of the program or find errors in it. One of the main innovations of Boogie is a systematic way (a methodology) for specifying and verifying invariants. The Spec# Programming System handles callbacks and aggregate objects, and it supports both object [4] and static [3] class invariants.<


In Spec# beside the "assert" there is also "assume", it seems similar to this one of C++:
http://msdn.microsoft.com/en-us/library/1b3fsfxw%28VS.80%29.aspx
But Spec# "assume" seems used mostly for the contract programming, for example to state that some condition is true before some method call that has that thing as precondition. I have not fully understood the purpose of this, but I think it can be useful for performance (because contracts are enforces in "release mode" too. So the compiler has to try to remove some of them to improve code performance).


In Spec# nonnull types are specified adding "!" after their type:
T! t = new T(); // OK
t = null; // not allowed

Even if D can't turn all its class references to nonnull on default, a syntax to specify references and pointers that can't be null can be added. The bang symbol can't be used in D for that purpose, it has enough purposes already.


Spec# defines three types of purity:
- [Pure] Method does not change the existing objects (but it may create and update new objects).
- [Confined] Method is pure and reads only this and objects owned by this.
- [StateIndependent] Method does not read the heap at all.
Add one of the three attributes above to a method to declare it as pure method. Any called method in a contract has to be pure.


Spec# "static class invariants" test the consistency of static fields.
http://research.microsoft.com/en-us/projects/specsharp/krml153.pdf

>Sometimes there are even consistency conditions that relate the instance fields of many or all objects of a class; static class invariants describe these relations, too, since they cannot be enforced by any one object in isolation.<
This is an example, written in Pseudo-D:


class Client {
    int id;
    static int last_used_id = 0;

    static invariant() {
        assert(Client.last_used_id >= 0);

        HashSet!int used_ids;
        foreach (c; all Client instances) {
            assert(c.id < Client.last_used_id);
            assert(c.id !in usef_ids);
            usef_ids.add(c.id)
        }
    }
    
    this() {
        this.id = Client.last_used_id;
        Client.last_used_id++;
    }
}

>Every object of class Client has an ID. The next available ID is stored in the static field last_used_id. Static class invariants guarantee that last_used_id has not been assigned to a Client object and that all Client objects have different IDs.<


In D class/struct invariants can access static fields too. Findind all instances of a class is not immediate in D, I don't think D reflection is enough here, you have to store all such references, for example in a static array of Client.


So in D it can become something like:

class Client {
    int id;
    static int last_used_id = 0;
    static typeof(id)[] clients;

    invariant() {
        assert(Client.last_used_id >= 0);

        // assert len(set(c.id for c in clients)) == len(clients)
        // assert all(c.id < Client.last_used_id for c in clients)

        HashSet!int used_ids;
        foreach (c; clients) {
            assert(c.id < Client.last_used_id);
            assert(c.id !in usef_ids);
            usef_ids.add(c.id)
        }
    }

    this() {
        this.id = Client.last_used_id;
        Client.last_used_id++;
        clients ~= this;
    }
}


But running that invariant often is slow. I don't know if/how Spec# solves this problem.

--------------------

> It's interesting that D already has most of the gcc extensions:
> http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html

There's lot of stuff in that page, and some of those things are new for me :-)

4.3 Labels as Values: that's computed gotos, they can be useful if you write an interpreter or you implement some kind of state machine. In the last two years I have found two situations where I have found useful this feature of GCC. I'd like computed gotos in D too (both GDC and LDC can implement them in a simple enough way. If this is hard to implement with the DMD back-end then I'd like this feature to be in the D specs anyway, so other D compilers that want to implement it will implement it with the same standard syntax, improving portability of D code that uses it).

I will write about more of those GCC things tomorrow...

Bye,
bearophile


More information about the Digitalmars-d mailing list