Tuesday 19 June 2007

Const Wars

A long time ago, in an IRC channel far, far away...

Episode 5

A NEW CONST

It is a period of civil war. Rebel posters, striking from irc and the newsgroups, strive to win their final victory against the evil Constant Empire.

During this battle, Rebel agents were horrified to discover that the Empire's ultimate weapon, the D 2.0 Release, a new compiler with three kinds of const, had been released.

Pursued by the Empire's sinister agents, Princess Mutable races against the clock to find a way to destroy the terrible compiler to save her people and restore mutability to the galaxy...

Episode 5

A NEW CONST

It is a period of civil war. Rebel posters, striking from irc and the newsgroups, strive to win their final victory against the evil Mutable Empire.

During this battle, Rebel agents were horrified to discover that the Rebel's ultimate weapon, the D 2.0 Release, a new compiler with three kinds of const, was feared and hated.

Pursued by the Empire's sinister agents, Princess Invariant races against the clock to find a way to justify the badly needed compiler to save her people and restore type safety to the galaxy...

That's the wonderful thing about religion; you can use it to justify anything, with no requirement for facts or logic!

Thursday 14 June 2007

Wrapping functions for fun and profit

Error handling sucks. I mean, I've got code to write! I don't want to have to waste my time making sure my function calls actually worked. After all, nothing ever goes wrong when I'm running it, so any problems are the user's fault.

Or something along those lines. That's one thing that always annoyed me about C-style libraries: you had to sit there writing all this code to handle errors on every single damn call. I can't count the number of times I've seen OpenGL examples where they never do a single error check, apparently because it's too much work.

So when I started writing GL code in D, I realised pretty quickly that this was sub-optimal. After all, you want to know when something's gone wrong (if you don't find out, how can you ever fix it?) but having to write all those ifs was out of the question on account of me being supremely lazy.

One way around this is to have a function that takes the error code from a function, and throws an exception if its something other than NO_ERROR. Sadly, OpenGL doesn't use return values; it has a separate function called glError that tells you if an error's occured.

OK, we can deal with this; we just need a templated function that checks for an error, throws an exception if there was one, or passes back what we pass into it.

T glCheck(T)(T result)
{
    if( glError() == GL_NO_ERROR )
        return result;
    else
        throw new GLException("OH NOES!");
}

And that does work. Well, except for functions that have void return types. That's when it starts to get a little ugly; we need to have a different function that we call afterwards.

And this is all well and good if you happen to like simple solutions to problems. Not me, though. I wanted something that I could stick in front of any GL call and have it do error checking. I also wanted to try and remove the double closing paren problem (every time you nest an expression, it gets just that tiny bit uglier).

So let's change things around a bit. Instead of a function that we pass the GL call's result to, let's create a function that wraps the GL call.

ReturnType!(Fn) glCheck(alias Fn)(ParameterTypeTuple!(Fn) args)
{
    alias ReturnType!(Fn) returnT;

    static if( is( returnT == void ) )
        Fn(args);
    else
        auto result = Fn(args);

    glCheckError();

    static if( !is( returnT == void ) )
        return result;
}

What we're doing here is creating a function that has the exact same signature as the function we want to call. When we call this wrapper function, it calls the underlying function, checks for errors (throwing an exception as necessary: that's the job of glCheckError), and returning the result.

Those static ifs are there because you can't declare a variable of type void in D, which kinda sucks. You'd use the above function like this:

glCheck!(glClear)(GL_COLOR_BUFFER_BIT);

For those keeping count, that's one character longer than the "pass-through" style. The nice thing is that this works uniformly with any function, no matter its return type.

However, we can still improve this. For instance, since we have an alias to the function being called, we can improve the call to glCheckError to this:

glCheckError((&Fn).stringof)

This allows us to report the exact GL call that failed (normally, all we would get is an exception telling us which error code we got). Even cooler, however, is we can use this information to actually log our GL calls as they happen:

version( gl_LogCalls )
{
    log.writef("%s",(&tFn).stringof[2..$]);
    log.writef("(");
    static if( args.length > 0 )
    {
        log.writef("%s", args[0]);
        foreach( arg ; args[1..$] )
            log.writef(", %s", arg);
    }
    log.writeLine(")");
    version( gl_LogCalls_Flush )
        log.flush();
}

If we place that in our glCheck function just before we call the function itself, it gives us the ability to trace through our GL code without having to hunt through functions. This can be really useful when you've got some weird behaviour, and can't figure out what's causing it.

One last improvement: in OpenGL, there are times where calling glError can itself cause an error. The most obvious of these are between glBegin and glEnd calls. You can solve this by either building some logic in to glCheck to account for glBegin/glEnd blocks, or you can do what I did and split the function into two: glSafe which does the error checking and glRaw which doesn't.

Before I go, one small note: if you are using DerelictGL, you need to replace the Fn in ReturnType!(Fn) and ParameterTypeTuple!(Fn) with typeof(Fn) because of a weird bug with specialising templates on aliases to function pointers, and replace the line that logs the name of the function with:

log.writef("%s",tFn.stringof);
Wrap me up, in your love, your love takes me higher...

Friday 8 June 2007

Mixins, CTFE and shell-style variable expansion

Edit: Frits van Bommel pointed out that I'd forgotten about declaration mixins, which have now been added.

It didn't take all that long before PHP started annoying me. Don't get me wrong; it's a great language for hacking together dynamic web pages, but if I have to look at another full-blown CMS written in it, I am going to scream.

That said, PHP did get a few things right. One of these is the syntax it uses for variable expansion in strings. Basically, it's stolen almost verbatim from the Bourne shell and relatives:

$life = 42;
echo "Meaning of life: $life";

Which obviously expands to Meaning of life: 42. PHP adds to this by allowing you to use braces to expand a more complex expression involving member and array access.

Sadly, those of us in the statically-typed world have to make do with rather less attractive options like C-style format strings...

printf("Meaning of life: %d", life);

...C#-style format strings...

WriteLine("Meaning of life: {}", life);

..."whisper" syntax...

Cout("Meaning of life: ")(life).newline;

...or worst of all, the hideous monster that is C++'s iostreams.

cout << "Meaning of life: " << life
     << endl;

What would be really cool is a formatting function that uses PHP/shell style inline expansion, optionally with C-style formatting options. Best of both worlds. So, today I sat down and implemented such a formatter which makes this possible:

int a = 13;
int b = 29;

mixin(writeFln(
    "     a: $a" "\n"
    "     b: $b" "\n"
    " a + b: ${a+b}" "\n"
    "in hex: $(x){a+b}"));
     a: 13
     b: 29
 a + b: 42
in hex: 2a

Those already familiar with both string mixins and CTFE will no doubt already have an idea how I accomplished this; you can skip to the code at the end if you like. For those of you who would like to know how D makes this possible, read on.

Compile time function execution

The first feature that D adds to make this possible is compile time function execution or CTFE. Now this is basically just an extension of regular constant folding. Imagine you have code like this:

int registry = 1700 + 1;

You would expect any good compiler to be able to simplify this code since both numbers are constant (and the compiler hopefully knows how to add two numbers.) CTFE simply expands on this and allows you to use function calls in constant-folding, provided they satisfy a stringent set of requirements. The requirements are too long to list here, but suffice to say that they all boil down to two things: stick to basic structural constructs (no labelled breaks, gotos, nested functions, etc.), and don't do anything that involves pointers or memory allocation.

For example, CTFE allows us to do things like this:

char[] repeat(char[] a, uint n)
{
    char[] result;
    for( ; n>=0; --n )
        result ~= a;
    return result;
}

It's worth noting that simple array operations like changing the length, concatenation, etc. are allowed for CTFE.

String mixins

The other half of this magic trick are string mixins. In D, there are actually four different mixins:

  1. "Regular" mixins, or as I call them, scope mixins. These will, when you specify a template, mix the contents of that template into the current scope. For example:

    template foo()
    {
        char[] bar = "baz";
    }
    
    void main()
    {
        mixin foo;
        writefln(bar); // Outputs "baz".
    }
  2. Statement mixins. These mixins take a list of statements (as in D source code) as a compile-time constant string, and inserts them into the souce at that location. For instance, we could replace the last line of the previous example with:

    mixin("writefln(bar);"); // Outputs "baz".
  3. Expression mixins. These are like the statement mixins, except that they allow you to mix in any semantically complete expression. That includes things like "bar", "12+34", "a = foo(PI)" and even "writefln(bar)" (note the lack of a semicolon!)

  4. Declaration mixins. These are like statement mixins, except instead of mixin in executable statements, they mix in declarations (like functions, classes, imports, etc.).

    Many thanks to Frits van Bommel for pointing out that I stupidly missed this one.

Those last three are collectively known as "string mixins" since they take plain old strings of D source code. Now, you may be wondering how mixing in plain D source could be useful. It isn't, until you combine it with a CTFE function (or a template) that produces D source code from some other format.

Putting them together

The idea now is quite straightforward. We're going to write a CTFE compatible function that takes our format string and converts it into D source code. We then feed the result of this function into a string mixin which inserts our freshly generated code into our source file.

So what are we aiming for? Basically, we want to turn this:

"foo $bar baz"

Into this:

"foo ",bar," baz"

There are various ways of doing this, but my personal favourite is to write a simple state machine to process the string. So how would such a state machine look in a CTFE function? Lots of weird, crazy syntax? Sadly, no. It's actually pretty anticlimactic...

char[] ctfe_format_string(char[] fs)
{
    State state;
    char[] result;

    foreach( char c ; fs )
    {
        if( state == State.Default )
        {
            // output character & look for '$'
        }
        else if( state == State.PostDollar )
        {
            // work out if this is a variable or not...
        }
        else if( state == State.Varname )
        {
            // write out the variable name...
        }
        // ...
    }

    return result;
}

That's pretty much it; the actual details are just ordinary string manipulation code. There's really nothing terribly interesting to it at all. Aside from that, there's a few convenience methods for joining the string pieces together and dumping the result to STDOUT. You can check out the details by grabbing the source code. In fact, I encourage you to go read it now, just to see how stupidly simple this kind of manipulation is.

I mean, look at this:

// Finish the variable expansion
result ~= "))";

That's about as complex as the code gets.

So, OK; we've got it splitting strings up. Yeah, it's cute, but can you do anything else with it?

Perhaps the best example to date is Don Clugston's BLADE library which uses CTFE and string mixins to generate near-optimal floating-point vector code from library code.

Another example is Kirk McDonald's Pyd which uses string mixins behind the scenes. Or how about Gregor Richards' compile-time brainf**k compiler?

And there are other possibilities that haven't been explored yet. Like compiling SQL or LINQ statements, or creating parsers out of BNF grammars.

So the next time you've got some recurring pattern that you can't quite express concisely using ordinary code, think about how a little CTFE and mixin magic might help things along.

"Don't worry about people stealing your ideas. If your ideas are any good, you'll have to ram them down people's throats." —Howard Aiken

The source code for the formatter can be downloaded from the D wiki here, and is licensed under the BSDv2 license.

D 1.0 to be frozen in carbonite

So after much crying and gnashing of teeth, Walter has finally confirmed what I'm sure a lot of D users have been waiting to hear:

It's getting pretty clear to me that the 1.0 series won't get any new features, just bug fixes, as the recent 1.015 release suggests.

The new features will all go into the 2.0 series.

Walter Bright, Re: Do we need a time-out in D evolution?

This is somewhat mixed news. It's good in that we will now (hopefully) end up with a nice, stable compiler release and a less stable but cutting-edge experimental compiler release. It's bad in that it means more work for Walter; he introduced the largely unused -v1 compiler switch so that he wouldn't have to maintain two compiler branches.

Interesting question: does this mean GDC is going to branch, too?

That's very funny. You know something? No new features for you!

Thursday 7 June 2007

You can't touch this.

So, there seem to be quite a few people who are confused about the upcoming changes to const-ness in D 2.0. The topic came up, once again, in the #D IRC channel, and I've been persuaded to write up how I understand it.

It is worth pointing out that this is all up in the air at the moment, meaning all of this could be rendered incorrect before I even finish writing it. Also, I'm not going to give any examples of what the code will look like, since the syntax appears to have recently changed, and I'm still not entirely sure what the impact is. Think of the examples as being "pseudo code."

That said, the concept itself seems fairly stable, which is what I'm going to talk about. With that, on with the show.

Firstly, it's important to disregard any pre-conceived notions you may have about what the word const means. What it will mean in D 2.0 is very different to what it means in D 1.x, C, C++ or any other language you might know.

Now, with D 2.0 will come three kinds of const-ness. For the moment, we will call these "storage const", "reference const" and "reference immutable."

Storage const is the easy one; it simply means that whatever bits are being used to store a particular variable cannot be changed once they are initialised. For example, every int variable in your program has four bytes of memory allocated to it somewhere, be it on the stack or in the static data segment. Storage const says that you can store a value into this int, but you cannot change it afterwards. One pretty obvious use of this would be:

"storage const" PI = 3.1415926535897931;

Unless you work for Xerox, you aren't likely to change the value of Pi. The same thing can be done with variables in functions:

void doStuff(int a, int b)
{
    "storage const" int c = a + b;
}

This is fine since we set the value of c during initialisation. However, the following wouldn't compile:

"storage const" int meaning_of_life = 42;
meaning_of_life = 72;

Once a storage const variable has had its value set, there's no changing it. There's one other interesting question: what about reference types like pointers, arrays and objects? Remember that a reference type stores an address of some kind. A storage const pointer, for example, would have the pointer itself fixed, but what it points to is unaffected. For example:

"storage const" int* stuff = new int;

(*stuff) = 23; // This is cool
(*stuff) = 19; // Still cool
stuff = new int; // This ain't cool at all.

In this example, we're free to change what stuff points to, but we are not allowed to change stuff itself.

Once you've wrapped your head around that, we can move on to "reference const".

Unlike storage const, reference const says nothing about a variable's storage. Rather, it deal with what that variable points at. If we take the previous example and change "storage const" to "reference const", we get:

"reference const" int* stuff = new int;

(*stuff) = 23; // This isn't cool anymore.
(*stuff) = 19; // Neither is this.
stuff = new int; // This *is* cool.

What reference const is saying is "Ok, you've got a pointer to something, but you aren't allowed to change it; feel free to point at something else, though!" In a way, reference const can be thought of as a read-only view of some data. You can look, but can't touch.

Another important thing is that reference const is transitive. Take this, for example:

"reference const" int** foo;

foo is a reference const pointer to a pointer to an int. Notice that we didn't say anything about the int* we're pointing to; just foo itself. That means we can't do this:

(*foo) = new int;

However, we also can't do this:

(*(*foo)) = 42;

This can be kinda tricky to explain, so just think of it like this: once you go through a "reference const" reference (be it a pointer, array or object reference), all references from that point onward are "reference const". Essentially, you can't change anything beyond a reference const.

Go back over that, and make sure you understand what's going on. Once you've done that, we'll move on to the last and strongest form of const-ness: "reference immutable".

Now, reference immutable is very similar to reference const; it applies to reference types and says "you can look, but can't touch." The important difference is that where reference const says "you can't touch", reference immutable says "no one can touch." Reference immutable is a guarantee to you and the compiler that nothing can modify the data being pointed at. For instance, if you have a static string in your program stored in the data segment (a part of the executable itself), that string is reference immutable since no one is able to change it. In fact, a reference immutable piece of data may not even necessarily have an address in memory; if it never changes, the compiler could potentially just insert its value wherever it gets used.

From the user's end, there isn't any appreciable difference between something that's reference const and something that's reference immutable. The difference is on the creator's end; you might get a reference const buffer that the owner keeps updating, or a reference immutable buffer that gets filled and then fixed.

So, the only question remaining is: how do these three concepts map to keywords in D 2.0? At the moment, it looks like this:

  • "storage const" will be final,
  • "reference const" will be const and
  • "reference immutable" will be invariant.

Let me just reiterate that I'm not saying anything about where these keywords go, where you put parenthesis, etc. I'm just trying to explain the concepts; don't take any of the code examples above literally.

One last thing I'd like to point out (as suggested by Oskar Linde): whilst reference const and reference immutable are part of a variable's type, storage const isn't; it only affects one particular variable. For example:

"storage const"   int  a;
"reference const" int* b;

int  c = a; // You can do this; typeof(a) is int
int* d = b; // But can't do this; typeof(b) is "reference const" int*

Hopefully, that's helped to clear things up, at least a little. If you have any questions or corrections, let me know and I'll try to clear it up.

Stop! Hammer time!

Incidentally...

... while(nan) doesn't compile since nan isn't defined. Technically, it should be while(real.nan), but that was a bit unwieldy.

As for what it does, it turns out that despite nan comparing false to everything including itself, it's effectively the same as while(true). Go figure.