We need a way to make functions pure and/or nothrow based on the purity and/or nothrowability of the functions that they call
Jonathan M Davis
jmdavisProg at gmx.com
Sun Nov 14 01:56:02 PST 2010
That is, there are plenty of cases where template code may or may not be able to
pure or nothrow and that whether it can or not depends on what it's templatized
on. For instance, if you had a range which iterated over a range of characters
in some manner (other than simply iterating over it as std.array would). Whether
or not empty could be pure or nothrow would depend on whether the range of
characters that it holds has a empty which is pure or nothrow. At present,
std.array's front is neither pure or nothrow, but it will hopefully become both
later, and you could have a range of characters which isn't actually an array
and whose empty is both pure and nothrow. So, whether or not the empty on the
range type that you're instantiating can be pure or nothrow depends on what it's
iterating over. The only way that I know how to do that at present is to use
static ifs and get 4 different implementations. e.g.
static if((isArray!R && (functionAttributes!(std.array.empty!
(ElementType!R)) & FunctionAttribute.PURE)) ||
(!isArray!R && (functionAttributes!(R.empty) &
FunctionAttribute.PURE)))
{
static if((isArray!R && (functionAttributes!(std.array.empty!
(ElementType!R)) & FunctionAttribute.NOTHROW)) ||
(!isArray!R && (functionAttributes!(R.empty) &
FunctionAttribute.NOTHROW)))
{
@property bool empty() pure nothrow
{
return innerRange.empty;
}
}
else
{
@property bool empty() pure
{
return innerRange.empty;
}
}
}
else
{
static if((isArray!R && (functionAttributes!(std.array.empty!
(ElementType!R)) & FunctionAttribute.NOTHROW)) ||
(!isArray!R && (functionAttributes!(R.empty) &
FunctionAttribute.NOTHROW)))
{
@property bool empty() nothrow
{
return innerRange.empty;
}
}
else
{
@property bool empty()
{
return innerRange.empty;
}
}
}
That is _not_ a pretty way to do this. And if the function that you're declaring
gets very complicated at all, you're going to need to find a way to get the 4
versions to share code (probably via string mixin). The bodies are _identical_
and have no need to be different. _All_ you're changing is the function
signature. And whether the function signature has pure and/or nothrow depends
entirely on empty in this case. A more complicated function could depend on half
a dozen or a dozen different functions, and because you're dealing with a
templated type or function, whether or not the function can be pure and/or
nothrow varies with the type which is used to instantiate the template.
We really need to add a way to have a function marked as nothrow and/or pure
based on whether the functions that it calls are nothrow and/or pure. Whether
that should require listing the functions that need to be pure and/or nothrow or
whether the compiler should be able to figure it out on its own, I don't know.
But the current situation is ugly.
The one problem I see is that if the compiler has to determine whether a given
function can be pure and/or nothrow, it's going to potentially have to go
arbitrarily deep into the call hierarchy to figure it out (which stinks of the
halting problem), and it could require the source code of all of the functions
that it has to check (or require that they've all already determined whether
they can be pure and/or nothrow). I don't know whether that problem can be
gotten around or what the best solution is if there is one, but the current
situation is ugly.
As it stands, functions are likely to either be impure and be allowed to throw
simply because doing otherwise would require declaring the function 4 times.
std.algorithm and std.range are prime targets for places where functions
_should_ be pure and nothrow if they can, but whether they can or not depends on
their template arguments. I really think that we need to find a solution to this
problem and relatively soon.
Does anyone have some good suggestions on how to solve this issue?
- Jonathan M Davis
More information about the Digitalmars-d
mailing list