February 18, 2013
Recently I have been working on a multidimensional array implementation for use in my own projects, and things were working very well (I even got to the point where D's awesome metaprogramming capabilities allowed me to write an opIndex that could make arbitrary slices of a multidimensional array and vary its return type based on how many index ranges were passed in the argument list)...

... until I decided to test unusual element types, like const classes, or structs with const members. Then suddenly the tower of cards came crashing down, because I had gone through most of the functions to mark them const, pure, @safe, nothrow, wherever they can be, and the compiler agreed with me.  At least, for all the prior unittested instantiations of the arrays, that is.

Then I tried instantiating with const element types and things with const members, and the compiler started noticing all sorts of places where these qualifiers don't apply.

The basic problem is this: when the array's opEquals depends on the element type's opEquals, then all bets are off as to whether the result is const, pure, etc., because the element type's opEquals could do *anything*, including run an easter egg flight simulator, overrun the stack and execute arbitrary code, etc.. The array implementation couldn't possibly take such things into account.

But this penalizes *most* use cases where these methods *can* be made pure, const, etc.. So there's no way to make the array implementation usable from pure/@safe code, even though its intended usage certainly *can* be, in theory. But because it's generic, it has to take account of *any* user type, and so it has to sacrifice all of these attributes.

The thing is, AFAIK, there's no way to express "this function is pure if ElementType's opEquals is pure", ditto for const, @safe, etc.. It's all or nothing: either you force all element types to implement every qualifier, or you get none at all, even if *most* instantiations actually can get them all. Furthermore, there's currently no sane way to vary qualifiers at compile-time (so that one could, say, use static if to enable/disable qualifiers depending on what is supported).

What all of this boils down to, is that I'm pretty much ready to just forego *all* of these qualifiers completely, and just work with non-const impure @system, because it's just so painful to write generic code otherwise. Before I came to D, I was convinced that const was evil, and D mostly convinced me to change my mind. But now I'm tempted to revert to my previous conclusion, esp. when it comes to generic code. :-(


Tell me and I forget. Teach me and I remember. Involve me and I understand. -- Benjamin Franklin