-2

[intro.abstract] p8 says:

The following specify the observable behavior of the program:

  • Accesses through volatile glvalues are evaluated strictly according to the rules of the abstract machine.
  • Data is delivered to the host environment to be written into files (See also: ISO/IEC 9899:2024, 7.23.3).
  • The input and output dynamics of interactive devices shall take place in such a fashion that prompting output is actually delivered before a program waits for input. What constitutes an interactive device is implementation-defined.

This is an exhaustive list, which means that things not specified in the list are not considered observable behavior.

Consider this example:

int main(){
  auto t = network_request(); // #1
}

First, calling the IO library has side effects as per [intro.execution] p7:

Reading an object designated by a volatile glvalue ([basic.lval]), modifying an object, producing an injected declaration ([expr.const]), calling a library I/O function, or calling a function that does any of those operations are all side effects

however, side effects are not observable behavior because it is not in the list. So, does it mean a conforming implementation can eliminate the calling to network_request under the "as-if" rule? That is, the whole program is a no-op because calling IO functions not involving things listed in [intro.abstract] p8 are not observable behavior, the conforming implementation does not need to emulate the structure according to the "as-if" rule:

The semantic descriptions in this document define a parameterized nondeterministic abstract machine.This document places no requirement on the structure of conforming implementations.In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.

10
  • the 3rd bullet point of [intro.abstract]/8 covers IO. What is considered IO is implementation defined but if its provided by the compiler its most likely covered. Commented Nov 8 at 2:41
  • 3
    A conforming implementation either understands what network_request() does, and wouldn't remove it because otherwise its users would be unhappy with its vendor; or it's a black-box call into some library (e.g. provided by the OS), and then it wouldn't remove it because it cannot rule out that the call performs I/O as anticipated by the standard, or touches a volatile object or something. I mean, real conforming implementations are authored by real people who understand how their products are used in the real world. Commented Nov 8 at 2:46
  • @NathanOliver The interactive device commonly refers to terminal or console, I think. IO operations are not necessary to be input/output Commented Nov 8 at 6:27
  • 1
    @xmh0511 I/O operations are input or output by definition. 'IO' stands for 'input/output'. Commented Nov 8 at 6:31
  • @user207421 I meant, not the input/output of the interactive device. The third bullet implies that "interactive device" is associated with "display" Commented Nov 8 at 6:39

2 Answers 2

3

Output constitutes observable behavior as a corollary to what the Standard mandates.


In order to eliminate the call to network_request under the "as-if" rule, a conforming implementation must be able to prove that the side-effects of the call do not include observable behavior. In particular, the side effects must not include any of the following, which constitute the overlap between "side effect" and "observable behavior".

  • reading an object designated by a volatile glvalue (this access is observable behavior)
  • modifying an object designated by a volatile glvalue (this access is observable behavior)
  • calling a library I/O function that delivers data to the host environment to be written into files

The difficulty lies in proving this, especially since volatile objects are well-suited for receiving data from outside the program, and for sending data outside the program. The question does not state what network_request does, but if its behavior matches its name, there is a good chance that if you dig deep enough, this network request either accesses a volatile object or strays into a "black box" function that the implementation can prove nothing about. If that happens, the call cannot be eliminated under the "as-if" rule.

If no volatile object is used for the network request, you are probably on a system like Linux, where "everything is a file". In such an environment, a network request would involve writing data to a special file, and that would be accomplished via a library function. This again is an example of something that is both a side effect and an observable behavior. It cannot be eliminated under the "as-if" rule.

Now, the above is not proof that the network request involves observable behavior as defined by the Standard. However, as far as I know, it does cover Linux, Mac, and Windows. So I would put the burden of proof on you. Is there a platform on which network_request is implemented without observable behavior? Is there an output function that involves neither modifying a volatile object nor writing to a file of some sort? I do not know of one, but that does not prove nonexistence, so maybe there is one. If there is, it would likely be considered an example of a defect/oversight in the Standard.

Other languages

If the "black box" mentioned above is written in a language other than C++, then the C++ Standard imposes no semantics on it; the behavior is implementation-defined. Without semantics, the question of optimizing something away is moot. There is nothing to optimize away until you look at the documentation from your implementation, at which point the "as-if" rule no longer applies and we're outside the scope of this question. This is where the Standard trusts implementations to do the right thing.

If a conforming implementation documents that the "black box" has certain behavior, then it has that behavior. The behavior cannot be optimized away unless that is also documented. So the documentation establishing that this black box will do what you want it to do is the same documentation preventing (or explicitly allowing) optimizing that functionality away.

Sign up to request clarification or add additional context in comments.

9 Comments

«there is a good chance that if you dig deep enough, this network request either accesses a volatile object or strays into a "black box" function that the implementation can prove nothing about.» The implementation of network_request must not be written in C++. For example, it can be implemented in assembly, in which there are only concepts like register, memory address, interrupt, and so on. The concepts like "volatile object" in the C++ standard cannot apply to the stuff written in assembly, it's even no "objects" in assembly. For such a function entity...
The C++ standard cannot impose anything on it; at best, it is regulated by [[dcl.link] p10](eel.is/c++draft/dcl.link#10), which is implementation-defined. So, an implementation can still ignore all these functions. Furthermore, even if network_request was written in C++, however, it is now used as an external function in this program, and its definition doesn't appear in the translation Unit in the current program; for this case, it's still regulated by [dcl.link] p10.
"its definition doesn't appear in the translation Unit" -- This makes it a "black box" about which nothing can be proven. As far as the compiler knows, it might have observable behavior. It might not, but "might" is not enough to invoke "as-if".
"he implementation of network_request must not be written in C++." -- I hope you mean "might" and not "must", since nothing in the question prohibits writing it in C++. In any event, I've added an explanation for why implementing in assembly puts you outside the scope of the question. (Briefly: if network_request is not written in C++, then the Standard has nothing to say about it. It's not an observable behavior, not a side effect, not I/O. The implementation defines what it does and if it can be optimized away, not the C++ Standard.)
We agree that the standard cannot impose any requirement on the external function that was written in other languages. However, isn't that still true that even the external function was originally written in C++? Because the function's definition isn't in the TU of the current program, it's a black box to the implementation. If you cannot prove the observable behavior exists in the black box, then it won't exist according to the principle "Null Hypothesis".
«So I would put the burden of proof on you.» The burden of proof is on the people who say it has, not the people who say it doesn't have(Russell's Teapot).
Yes, that describes the situation. I would put the burden of proof on the people who say that a platform ("it") has a way to make a network request without using volatile objects or a library function delivering data or a black box. Did you have a suggestion for improvement, or are you merely engaging in idle chatter?
The burden of proof is on the people who say that a black box external function has observable behavior. To talk about whether a conforming implementation could eliminate the call to this function, we only need to judge whether the function has observable behavior.
"The burden of proof is on the people who say that a black box external function has observable behavior." -- WRONG. Proving that a black box has observable behavior accomplishes nothing; the permitted optimizations are the same as when nothing is proven. Thank you for your feedback, but I have decided to disregard it.
2

Clearly, conforming implementations of C++ must follow the requirements of the C++ Standard. However, actual implementations do not only obey the rules of the C++ Standard, but also the rules of additional specifications.

For example, the libraries shipped with all major compilers also follow the POSIX specification (more or less completely) or the Windows API specifications. These specifications put additional requirements on how C++ code can be compiled to a program.

The function network_request() is not part of any of these specifications (as far as I know), but of some unmentioned "specification" (a better known term is "library"). To make an implementation usable with "specifications" that the makers did not anticipate, they apply common sense in what the compilers do. And common sense tells that it is not a good idea to "optimize" away the call to network_request().

1 Comment

«To make an implementation usable with "specifications" that the makers did not anticipate,...» I would argue that this point is not governed by the C++ standard. An insane implementation can still be arbitrary to ignore all these external functions, including libraries supplied in POSIX, because these functions are external and whose definitions are not part of the translation Unit of the program, they are as external functions are implementation-defined as per [[dcl.link] p10](eel.is/c++draft/dcl.link#10), that is, whether eliminating them is the responsibility of the compiler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.