Immutable object: Difference between revisions

Content deleted Content added
Python: PEP-8
Tags: Mobile edit Mobile web edit
 
(One intermediate revision by one other user not shown)
Line 38:
 
=== Interning ===
The practice of always using references in place of copies of equal objects is known as ''[[intern (computer science)|interning]]''. If interning is used, two objects are considered equal [[if and only if]] their references, typically represented as pointers or integers, are equal. Some languages do this automatically: for example, [[Python (programming language)|Python]] automatically [[String intern pool|interns short strings]]. If the algorithm that implements interning is guaranteed to do so in every case that it is possible, then comparing objects for equality is reduced to comparing their pointers – a substantial gain in speed in most applications. (Even if the algorithm is not guaranteed to be comprehensive, there still exists the possibility of a [[fast path]] case improvement when the objects are equal and use the same reference.) Interning is generally only useful for immutable objects.
 
=== Thread safety ===
Line 44:
 
=== Violating immutability ===
Immutability does not imply that the object as stored in the computer's [[Computer storage|memory]] is unwriteable. Rather, immutability is a [[compile-time]] construct that indicates what a programmer can do through the normal interface of the object, not necessarily what they can absolutely do (for instance, by circumventing the [[type system]] or violating [[const correctness]] in [[C (programming language)|C]] or [[C++]]).
 
== Language-specific details ==
Line 97:
 
=== C++ ===
In C++, a [[const-correctness|const-correct]] implementation of <code>CartShoppingCart</code> would allow the user to create instances of the class and then use them as either <code>const</code> (immutable) or mutable, as desired, by providing two different versions of the <code>items()</code> method. (Notice that in C++ it is not necessary — and in fact impossible — to provide a specialized constructor for <code>const</code> instances.)
 
<syntaxhighlight lang="cpp">
class CartShoppingCart {
private:
public:
Cart( std::vector<ItemMerchandise> items): items_(items) {};
public:
explicit Cart(std::vector<Item> items_;items):
items{items} {}
 
std::vector<ItemMerchandise>& items() { return items_; }
const std::vector<Item>& items() const { return items_items; }
}
 
const std::vector<Item>& items() const {
int ComputeTotalCost() const { /* return sum of the prices */ }
return *total_cost_items;
}
 
double computeTotalCost() const {
private:
return std::ranges::accumulate(
std::vector<Item> items_;
items | std::views::transform([](const Merchandise& m) -> double { return m.getPrice(); }), 0.0
);
}
};
</syntaxhighlight>
Line 119 ⟶ 128:
 
<syntaxhighlight lang="cpp">
class CartShoppingCart {
private:
public:
Cart( std::vector<ItemMerchandise> items): items_(items) {};
mutable std::optional<int> total_cost_totalCost;
public:
explicit Cart(std::vector<Merchandise> items): items{items} {}
 
const std::vector<ItemMerchandise>& items() const {
return items_items; }
 
int ComputeTotalCost() const {
if (total_cost_) {
return *total_cost_;
}
 
int total_costcomputeTotalCost() =const 0;{
for (const auto& item :if items_(!totalCost) {
totalCost = std::ranges::accumulate(
total_cost += item.Cost();
items | std::views::transform([](const Merchandise& m) -> double { return m.getPrice(); }), 0.0
);
}
return total_cost*totalCost;
}
total_cost_ = total_cost;
return total_cost;
}
 
private:
std::vector<Item> items_;
mutable std::optional<int> total_cost_;
};
</syntaxhighlight>
Line 175 ⟶ 181:
A function of type <code>const(S) function(const(T))</code> returns <code>const(S)</code> typed values for mutable, const and immutable arguments. In contrast, a function of type <code>inout(S) function(inout(T))</code> returns <code>S</code> for mutable <code>T</code> arguments, <code>const(S)</code> for <code>const(T)</code> values, and <code>immutable(S)</code> for <code>immutable(T)</code> values.
 
Casting immutable values to mutable inflicts undefined behavior upon change, even if the original value comes from a mutable origin. Casting mutable values to immutable can be legal when there remain no mutable references afterward. "An expression may be converted from mutable (...) to immutable if the expression is unique and all expressions it transitively refers to are either unique or immutable."<ref name="d_spec_const"/> If the [[compiler]] cannot prove uniqueness, the casting can be done explicitly and it is up to the programmer to ensure that no mutable references exist.
 
The type <code>string</code> is an alias for <code>immutable(char)[]</code>, i.e. a typed slice of memory of immutable characters.<ref>[https://dlang.org/spec/arrays.html#strings D Language Specification §&nbsp;12.16] (The terms ''array'' and ''slice'' are used interchangeably.)</ref> Making substrings is cheap, as it just copies and modifies a pointer and a length filed, and safe, as the underlying data cannot be changed. Objects of type <code>const(char)[]</code> can refer to strings, but also to mutable buffers.