mutable considered harmful, Range edition

"John W. Eaton" <[email protected]>
Newsgroups gmane.comp.gnu.octave.maintainers
Message-ID <[email protected]>
When using --traditional, I noticed that the result of

   zeros (1, 0)

was [](0x0) instead of [](1x0).

This error is related to the use of a mutable cache value in the Range 
data type.  Here's how:

Constant row vectors (like those produced by zeros and ones) are stored 
as ranges with the number of elemnts set to the number of columns and 
the increment set to zero.

But using --traditional implies "disable_range (true)" so the 
Range::matrix_value method is called is called in the octave_value 
constructor and that appears to fail.  If I understand correctly, the 
matrix_value method returns the incorrect result because it is declared 
const but also modifies and returns a mutable value (the cached Matrix 
value).  The compiler appears to be choosing to return the cache value 
before it is modified (the method is const, so normally it wouldn't 
change any member variables).

Is it possible to make the mutable cache value reliable in situations 
like this?  If not, then this appears to be another example of why we 
need to eliminate mutable in most places in Octave.

Separately, I see that other than the Range::matrix_value method, we set 
the cache value in the operators, like this:

   Range operator + (const Range& r, double x)
   {
     Range result (r.base () + x, r.limit () + x, r.inc (), r.numel ());
     if (result.m_numel < 0)
       result.m_cache = r.matrix_value () + x;

     return result;
   }

As I recall, setting the cache in these functions (and not just the 
matrix_value method) is done so that, for example, adding a constant to 
a range and then converting to a matrix will produce exactly the same 
result as converting a range to a matrix and then adding a constant to 
the matrix (in psuedo code):

   matrix (r) + c == matrix (r + c)

Using the cache this way does avoid the cost of any repeated conversions 
to a matrix value, but it also forces the cache to be created for any 
operation on a range, not just the result.  So it largely defeats the 
purpose of the efficient range object storage, and I'm wondering whether 
it is worth having a special range data type at all?  What do we really 
gain for the additional complexity?

jwe
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.