Immutability or a kind of "reverse shallow const"
I'm looking at writing an immutability wrapper.
Context
Most of the languages I know have immutable strings, which is distinct from C++ const strings, e.g C# like this:
string s = "hello";
s = "hello world" // allowed - the string reference was reassigned to a different string, the original string was not mutated
s = s + '!'; //allowed - a allocates a new string through concatenation
s[0] = 'H'; //won't compile
s = 'H' + s.SubString(1); //allowed - allocates twice, but allowed.
(see also golang, python, js)
The reason, as far as I can tell, is that these languages default to passing most T by T*, so they build immutability into the types (when possible). In C++ we have the option of passing T by T const& or T const*, so built-in immutability has been less of a priority.
Yet, immutability does buy something we don't get with const& - sure, as the caller, we know the callee can't modify the string. But as the callee, just because we wrote std::string const& in our function signature, that doesn't guarantee the string won't be modified elsewhere, whether it be async code, or just that we stored the reference and expected it to stay valid.
Question
Before I spend any time on this - is this a solved problem already?
My initial thought was that the fastest "immutability wrapper" to write would be as simple as
template<typename T>
using Immutable = std::shared_ptr<const T>;
Unfortunately...
int main() {
auto s = std::make_shared<int>(2);
Immutable<int> i = s;
*s = 1;
return *i; //returns 1;
}
same semantics as regular pointers - sure, the callee can't change it out, but they can't depend on its unchanging nature, either.