[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

mutable considered harmful, Range edition

From: John W. Eaton
Subject: mutable considered harmful, Range edition
Date: Tue, 9 Jun 2020 00:11:05 -0400
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.8.1

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?


reply via email to

[Prev in Thread] Current Thread [Next in Thread]