Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differentiating between const references to immutable vs. mutable objects

Tags:

c++

Is there any accepted way in C++ to differentiate between const references to immutable objects vs. mutable ones?

e.g.

class DataBuffer {
   // ...
};

class Params {
   // ...
};

class C {
public:
    // Given references must be valid during instance lifetime.
    C(const Params& immutableParameters, const DataBuffer& mutableDataBuffer) :
        m_immutableParameters{immutableParameters},
        m_mutableDataBuffer{mutableDataBuffer}
    {
    }

    void processBuffer();
private:
    const Params& m_immutableParameters;
    const DataBuffer& m_mutableDataBuffer;
};

Here the semantic difference is given just in the names.

The problem is that const& instance variables only let you know the object won't be modified by the instance. There is no distinction in the interface whether or not they may be modified elsewhere, which I think is a useful feature to be able to describe in the interface.

Expressing this through the type-system would help make interfaces clearer, allow the compiler to catch errors (e.g. accidentally modifying parameters handed to a C instance, outside of the instance, in the example above), and possibly help with compiler optimizations.

Assuming that the answer is that the distinction isn't possible in C++, maybe there is something close which can be achieved with some templates magic?

like image 354
Danra Avatar asked Jan 22 '17 15:01

Danra


People also ask

How do you know if its mutable or immutable?

An object is mutable if it is not immutable. An object is immutable if it consists, recursively, of only immutable-typed sub-objects. Thus, a tuple of lists is mutable; you cannot replace the elements of the tuple, but you can modify them through the list interface, changing the overall data.

What is the difference between immutable and const?

Immutable makes the contract that this object will not change, whatsoever (e.g. Python tuples, Java strings). Const makes the contract that in the scope of this variable it will not be modified (no promise whatsoever about what other threads might do to the object pointed to during this period, e.g. the C/C++ keyword).

What is the difference between mutable and immutable objects?

A mutable object can be changed after it's created, and an immutable object can't. That said, if you're defining your own class, you can make its objects immutable by making all fields final and private. Strings can be mutable or immutable depending on the language.

Are references immutable?

By default, all variables and references are immutable. Mutable variables and references are explicitly created with the mut keyword.


1 Answers

Immutability is not part of the C++ type system. As such, you cannot differentiate between immutable objects and mutable ones. And even if you could, std::as_const will always ruin your attempt to do so.

If you are writing an interface that requires immutability of objects, the easiest way to handle this is to invoke the Fundamental Theorem of Software Engineering: "We can solve any problem by introducing an extra level of indirection." So make immutability part of the type system. For example (FYI: uses some small C++17 library stuff):

template<typename T>
class immutable
{
public:
  template<typename ...Args>
  immutable(std::in_place_t, Args &&...args) t(std::forward<Args>(args)...) {}

  immutable() = default;
  ~immutable() = default;

  immutable(const immutable &) = default;
  //Not moveable.
  immutable(immutable &&) = delete;

  //Not assignable.
  immutable operator=(const immutable &) = delete;
  immutable operator=(immutable &&) = delete;

  const T* operator->() const {return &t;}
  const T& operator*() const {return t;}

private:
  const T t;
};

With this type, the internal T will be immutable regardless of how the user declares their immutable<T>. Your C class should now take an immutable<Params> by const&. And since immutable<T> cannot be constructed from a copy or move of an existing T, the user is forced to use immutable<Params> whenever they want to pass that as a parameter.

Of course, your biggest danger is that they'll pass a temporary. But that was a problem you already needed to solve.

like image 55
Nicol Bolas Avatar answered Oct 31 '22 07:10

Nicol Bolas