Don wrote:
Walter Bright wrote:
Don wrote:
A has called a function in B. B is not a floatingpoint module, so b()
can only be called when the mode is set back to the default. a()
violates this contract, so a() is incorrect. There's nothing wrong
with b() or c(). If a() wants to call b(), it needs to restore the
mode first; or else change b() into another floatingpoint module.
Ok, this was the missing piece in my understanding of the proposal.
But this requires that std.math either be floatingpoint, or two
versions of it must exist if you want to do change the rounding modes
on it.
I'm proposing that std.math would be floatingpoint. The docs contain
references to the sticky flags; I just went to a lot of trouble to make
sure that exp() sets the sticky flags correctly.
If std.math was floatingpoint, then its functions could not be pure.
Something interesting about my proposal is that although it is
motivated by the purity problem, that's simply a rule for the
compiler -- the rules for programmers do not involve purity at
all.(See my other post). Do not call _any_ functions in
non-floatingpoint modules (pure or not) without restoring the
rounding modes back to the default.
They could be done in terms of pure - if you call any pure function,
the modes must be set to the default.
(1) If it's totally forbidden to call a pure function with non-default
rounding modes, you need a separate non-pure function for the
non-default case. And unfortunately, it's viral -- you'd need
non-default rounding mode functions for every function. Even though
these functions are the same for pure and non-pure.
I agree that's a problem.
(2) You could do it as, 'pure' is cacheable only if the control mode is
set to default, otherwise it's not allowed to be cached. That would
require the complier to check the control mode all the time if it's
implementing caching. And it has to check it on EVERY function, it can't
rely on the signature. Something like:
pure int foo(int x)
{
return (x*0.5 > 6.0)? 1 : 2;
}
depends on the rounding mode! Consider that this might be in a library
-- I just don't think it's viable.
Additionally, in both cases, you either lose access to the sticky flags,
or else have to deal with them explicitly.
I don't see how your proposal fixes this problem.
(3) There is another option which would actually work. That is to
introduce a secret threadlocal 'must_not_cache_pure_functions' bool
variable.
At any point where the mode is about to change,
must_not_cache_pure_functions must be set to true, and set to false when
the mode is restored.
Likewise, that variable should be set to true whenever you're beginning
a scope where you care about the sticky flags.
_Every_ attempt to use the cached result of a pure function would have
to check that bool before doing anything else.
Maybe a solution is to just have a global compiler flag that says "don't
cache pure functions." Because this problem applies to every pure
function, because pure functions can call other pure functions which
call floating point pure functions.