44

Is it a standard term which is well defined, or just a term coined by developers to explain a concept (.. and what is the concept)? As I understand this has something to do with the all-confusing sequence points, but am not sure.

I found one definition here, but doesn't this make each and every statement of code a side effect?

A side effect is a result of an operator, expression, statement, or function that persists even after the operator, expression, statement, or function has finished being evaluated.

Can someone please explain what the term 'side effect' formally means in C++, and what is its significance?

For reference, some questions talking about side effects:

  1. Is comma operator free from side effect?
  2. Force compiler to not optimize side-effect-less statements
  3. Side effects when passing objects to function in C++
Community
  • 1
  • 1
Lazer
  • 90,700
  • 113
  • 281
  • 364
  • 2
    Usually with programming languages, any deviation from the strict mathematical meaning of the operation is meant. So if C=A+B changes anything but the value of C. Sometimes funny things can happen if you e.g. pass the same reference/pointer to both sides (A and B). E.g. or if some typeconversion happens that mutilates one of the operands. (due to float->int->float conversions or so) – Marco van de Voort Mar 05 '12 at 08:31
  • 4
    Did you read the [wiki page](http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29)? – amit Mar 05 '12 at 08:31
  • 2
    it's a synonym for "collateral damage" :) – Nick Dandoulakis Mar 05 '12 at 08:34
  • 1
    @amit: Just read it, I do not usually go to Wikipedia for programming doubts, but thanks! – Lazer Mar 05 '12 at 08:35
  • 1
    "Is it a standard term ... ?" - The term side-effect has a specific definition in the C++ standard, as many people have already covered. It is also a general concept in programming that isn't specific to C++. [Functional Programming](http://en.wikipedia.org/wiki/Functional_programming) is a style of programming that is highly concerned with corralling and trying to eliminate side-effects. – Merlyn Morgan-Graham Mar 05 '12 at 08:44
  • Minor nitpick - the concept of sequence points has been replaced by "sequenced before/sequenced after" relation. – Rafał Dowgird Mar 05 '12 at 09:13
  • 2
    @MarcovandeVoort in `C=A+B`, the write of `C` is a side-effect. The "main effect", i.e. the value computation, is the value which will be stored in `C`. – M.M Nov 04 '14 at 04:23

4 Answers4

24

A "side effect" is defined by the C++ standard in [intro.execution], by:

Reading an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment.

Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • 1
    I'm wondering how to interpret the "accessing an object" part. – Jesse Good Mar 05 '12 at 08:43
  • 2
    @Jesse: Perhaps [this](http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=187) helps. – Alok Save Mar 05 '12 at 08:48
  • @Als: Does "accessing a volatile object" == "dereferencing a pointer to a volatile object"? – Jesse Good Mar 05 '12 at 08:53
  • 1
    @Jesse: No, "accessing a volatile object" ∋ "dereferencing a pointer to a volatile object". There are other ways to access a volatile object: directly, or via a reference. Also, you probably should have written "dereferencing a volatile pointer to an object". – MSalters Mar 05 '12 at 09:09
  • @MSalters, your first part is correct, but dereferencing a _volatile pointer_ __is__ accessing a volatile object, the pointer itself is the volatile object (and you're reading it). – edA-qa mort-ora-y Mar 05 '12 at 09:15
  • @edA-qamort-ora-y: I meant a `volatile T*`, not a `T* volatile`. – MSalters Mar 05 '12 at 09:18
  • 1
    FWIW, the terminology I prefer when this stuff gets hairy is that `volatile T*` is a "pointer-to-volatile". The referand of a pointer-to-volatile may or may not actually be a volatile object, that's a matter of how the object was defined rather than the type of the pointer you happen to have. `int i; volatile int *p = &i;` creates a pointer-to-volatile whose referand isn't a volatile object, so calling `p` a pointer to a volatile object is potentially confusing. Usually not. – Steve Jessop Mar 05 '12 at 10:27
11

What exactly is a 'side-effect' in C++? Is it a standard term which is well defined...

c++11 draft - 1.9.12: Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression (or a sub-expression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a library I/O function returns or an access to a volatile object is evaluated the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile access may not have completed yet.

I found one definition here, but doesn't this make each and every statement of code a side effect?

A side effect is a result of an operator, expression, statement, or function that persists even after the operator, expression, statement, or function has finished being evaluated.

Can someone please explain what the term 'side effect' formally means in C++, and what is its significance?

The significance is that, as expressions are being evaluated they can modify the program state and/or perform I/O. Expressions are allowed in myriad places in C++: variable assignments, if/else/while conditions, for loop setup/test/modify steps, function parameters etc.... A couple examples: ++x and strcat(buffer, "append this").

In a C++ program, the Standard grants the optimiser the right to generate code representing the program operations, but requires that all the operations associated with steps before a sequence point appear before any operations related to steps after the sequence point.

The reason C++ programmers tend to have to care about sequence points and side effects is that there aren't as many sequence points as you might expect. For example: given x = 1; f(++x, ++x);, you may expect a call to f(2, 3) but it's actually undefined behaviour. This behaviour is left undefined so the compiler's optimiser has more freedom to arrange operations with side effects to run in the most efficient order possible - perhaps even in parallel. It also avoid burdening compiler writers with detecting such conditions.

1.Is comma operator free from side effect?

Yes - a comma operator introduces a sequence point: the steps on the left must be complete before those on the right execute. There are a list of sequence points at http://en.wikipedia.org/wiki/Sequence_point - you should read this! (If you have to ask about side effects, then be careful in interpreting this answer - the "comma operator" is NOT invoked between function arguments, array initialisation elements etc.. The comma operator is relatively rarely used and somewhat obscure. Do some reading if you're not sure what the comma operator really is.)

2.Force compiler to not optimize side-effect-less statements

I assume you mean "side-effect-ful" statements. Compiler's are not obliged to support any such option. What behaviour would they exhibit if they tried? - the Standard doesn't define what they should do in such situations. Sometimes a majority of programmers might share an intuitive expectation, but other times it's really arbitary.

3.Side effects when passing objects to function in C++

When calling a function, all the parameters must have been completely evaluated - and their side effects triggered - before the function call takes place. BUT, there are no restrictions on the compiler related to evaluating specific parameter expressions before any other. They can be overlapping, in parallel etc.. So, in f(expr1, expr2) - some of the steps in evaluating expr2 might run before anything from expr1, but expr1 might still complete first - it's undefined.

Community
  • 1
  • 1
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
11

The term "side-effect" arises from the distinction between imperative languages and pure functional languages. A C++ expression can do three things:

  1. compute a result (or compute "no result" in the case of a void expression),
  2. raise an exception instead of evaluating to a result,
  3. in addition to 1 or 2, otherwise alter the state of the abstract machine on which the program is nominally running.

(3) are side-effects, the "main effect" being to evaluate the result of the expression. Exceptions are a slightly awkward special case, in that altering the flow of control does change the state of the abstract machine (by changing the current point of execution), but isn't a side-effect. The code to construct, handle and destroy the exception may have its own side-effects, of course.

The same principles apply to functions, with the return value in place of the result of the expression.

So, int foo(int a, int b) { return a + b; } just computes a return value, it doesn't alter anything else. Therefore it has no side-effects, which sometimes is an interesting property of a function when it comes to reasoning about your program (e.g. to prove that it is correct, or by the compiler when it optimizes). int bar(int &a, int &b) { return ++a + b; } does have a side-effect, since modifying the caller's object a is an additional effect of the function beyond simply computing a return value. It would not be permitted in a pure functional language.

The stuff in your quote about "has finished being evaluated" refers to the fact that the result of an expression (or return value of a function) can be a "temporary object", which is destroyed at the end of the full expression in which it occurs. So creating a temporary isn't a "side-effect" by that definition: other changes are.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
-1

1.9.6

The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.

A side-effect is anything that affects observable behavior.

Note that there are exceptions specified by the standard, where observable behavior doesn't have to conform to that of the abstract machine - see return value optimization, temporary copy elision.

Community
  • 1
  • 1
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 4
    "*A side-effect is anything that affects observable behavior.*" And what is "*observable behavior*"? Does changing a `mutable` member in a const member function constitute "observable behavior"? – Nawaz Mar 05 '12 at 08:41
  • @Nawaz I explained that in the quote. If that change affects callso to I/O functions, or if the variable is `volatile`, then yes. – Luchian Grigore Mar 05 '12 at 08:43
  • @JohannesSchaub-litb Why not true? The only problem in the answer is that a side effect is anything that modifies the state of the execution environment. But the standard doesn't say "change execution environment"="change observable behavior". Don't know why "execution environment" was defined in C but not C++. – jinawee Jan 11 '19 at 10:57
  • 1
    Now that I think about it, the answer is wrong, since there are side-effects that don't affect observable behavior, such as modifying a non-volatile object. – jinawee Jan 11 '19 at 11:07