View mode: basic / threaded / horizontal-split · Log in · Help
February 18, 2013
Purity, @safety, etc., in generic code
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.
:-(


T

-- 
Tell me and I forget. Teach me and I remember. Involve me and I
understand. -- Benjamin Franklin
Top | Discussion index | About this forum | D home