immutability

Added immutability under "Philosophy" and fleshed out the Con section
This commit is contained in:
Bjarne Stroustrup 2016-02-13 14:35:22 -05:00
parent f1fcc0fe68
commit dfd29f3963

View File

@ -343,6 +343,7 @@ Philosophy rules summary:
* [P.7: Catch run-time errors early](#Rp-early) * [P.7: Catch run-time errors early](#Rp-early)
* [P.8: Don't leak any resources](#Rp-leak) * [P.8: Don't leak any resources](#Rp-leak)
* [P.9: Don't waste time or space](#Rp-waste) * [P.9: Don't waste time or space](#Rp-waste)
* [P.10: Prefer immutable data to mutable data](#Rp-mutable)
Philosophical rules are generally not mechanically checkable. Philosophical rules are generally not mechanically checkable.
However, individual rules reflecting these philosophical themes are. However, individual rules reflecting these philosophical themes are.
@ -928,6 +929,19 @@ After that, we can look at waste related to algorithms and requirements, but tha
Many more specific rules aim at the overall goals of simplicity and elimination of gratuitous waste. Many more specific rules aim at the overall goals of simplicity and elimination of gratuitous waste.
### <a name="Rp-mutable"></a>P.10: Prefer immutable data to mutable data
##### Reason
It is easier to reason about constants than about variables.
Sumething immutable cannot change unexpectedly.
Sometimes immutability enables better optimization.
You can't have a data race on a constant.
See [Con: Constants and Immutability](#S-const)
# <a name="S-interfaces"></a>I: Interfaces # <a name="S-interfaces"></a>I: Interfaces
An interface is a contract between two parts of a program. Precisely stating what is expected of a supplier of a service and a user of that service is essential. An interface is a contract between two parts of a program. Precisely stating what is expected of a supplier of a service and a user of that service is essential.
@ -10715,16 +10729,29 @@ Constant rule summary:
##### Reason ##### Reason
Immutable objects are easier to reason about, so make object non-`const` only when there is a need to change their value. Immutable objects are easier to reason about, so make object non-`const` only when there is a need to change their value.
Prevents accidental or hard-to-notice change of value.
##### Example ##### Example
for ( for (const string& s : c) cout << s << '\n'; // just reading: const
container
??? for (string& s : c) cout << s << '\n'; // BAD: just reading
for (string& s: c) cin>>s; // needs to write: non-const
##### Exception
Function arguments are rarely mutated, but also rarely declared const.
To avoid confusion and lots of false positives, don't enforce this rule for function arguments.
void f(const char*const p); // pedantic
void g(const int i); // pedantic
Note that function parameter is a local variable so changes to it are local.
##### Enforcement ##### Enforcement
??? * Flag non-const variables that are not modified (except for parameters to avoid many false positives)
### <a name="Rconst-fct"></a>Con.2: By default, make member functions `const` ### <a name="Rconst-fct"></a>Con.2: By default, make member functions `const`
@ -10759,39 +10786,64 @@ This gives a more precise statement of design intent, better readability, more e
##### Reason ##### Reason
??? To avoid a called function unexpectedly changing the value.
It's far easier to reason about programs when called functions don't modify state.
##### Example ##### Example
??? void f(char* p); // does f modify *p? (assume it does)
void g(const char* p); // g does not modify *p
##### Note
It is not inherently bad to pass a pointer or reference to non-const,
but that should be done only when the called function is supposed to modify the object.
##### Note
[Do not cast away `const`](#Res-casts-const).
##### Enforcement ##### Enforcement
??? * flag function that does not modify an object passed by pointer or reference to non-cost
* flag a function that (using a cast) modifies an object passed by pointer or reference to const
### <a name="Rconst-const"></a>Con.4: Use `const` to define objects with values that do not change after construction ### <a name="Rconst-const"></a>Con.4: Use `const` to define objects with values that do not change after construction
##### Reason ##### Reason
??? Prevent surprises from unexpectedly changed object values.
##### Example ##### Example
??? void f()
{
int x = 7;
const int y = 9;
for (;;) {
// ...
}
// ...
}
As `x` is not const, we must assume that it is modified somewhere in the loop.
##### Enforcement ##### Enforcement
??? * Flag unmodified non-const variables.
### <a name="Rconst-constexpr"></a>Con.5: Use `constexpr` for values that can be computed at compile time ### <a name="Rconst-constexpr"></a>Con.5: Use `constexpr` for values that can be computed at compile time
##### Reason ##### Reason
??? Better performance, better compile-time checking, guaranteed compile-time evaluation, no possibility of race conditions.
##### Example ##### Example
??? double x = f(2); // possible run-time evaluation
const double x = f(2); // possible run-time evaluation
constexpr double y = f(2); // error unless f(2) can be evaluated at compile time
##### Note ##### Note
@ -10799,7 +10851,7 @@ See F.4.
##### Enforcement ##### Enforcement
??? * Flag `const` definitions with constant expression initializers.
# <a name="S-templates"></a>T: Templates and generic programming # <a name="S-templates"></a>T: Templates and generic programming