Streams and Their States
The stream state fail records that an I/O operation has failed, so the program can examine it instead of assuming success.
Why Failed Input and Output Goes Unnoticed
Programs constantly read data from somewhere and write data somewhere else. Reading a value typed by a user, loading a file, and sending text to a screen are all input/output operations, usually called I/O. Any of these operations can fail. The data might not match what the program expected, or the connection to the source or destination might have a problem.
A program that ignores these failures can produce wrong results without warning anyone. Imagine a program that asks for a number, receives text that is not a number, and then carries on as if a valid number had arrived. Every later calculation is quietly wrong. This article explains the mechanism a program can use to notice that an I/O operation has failed and to decide what to do about it.
A Stream and Its Working State
A stream is the object through which a program's input or output flows. Like any object, it has a state at each moment. In normal operation the stream is in a state that says it is working. This is the state in which reading and writing behave as the program expects.
When an I/O operation goes wrong, the stream can be placed into the fail state. The fail state records that something went wrong. It does not repair anything and does not by itself decide what the program should do. It is a record, and the program is responsible for reading that record and acting on it.
The Fail State as a Recorded Flag
The stream state fail records that an I/O operation has failed, so the program can examine it instead of assuming success.
The important idea is that failure is recorded as information the program can examine. The program does not have to guess from the output whether something went wrong. It can look at the stream's state and respond. Failure becomes a fact the program can check, not a surprise it discovers later when results look strange.
Notice the order of events. The failure is first recorded by the stream, then the program checks for it, and only then does the program choose a response. Each step is separate. That separation is what makes the handling deliberate rather than accidental. The diagram below shows these three steps in order.
Moving From Working to Fail
The diagram below shows the two states the source develops most directly. A stream starts in the working state during normal operation. If an I/O operation goes wrong, the stream moves into the fail state. The source describes this as the stream being placed into the fail state, which is a one-way record of the failure at the moment it happened.
The source treats getting back to a usable situation as something the program does deliberately after noticing the failure. Recovery means the program takes an action such as asking for the value again, using a fallback, or reporting the problem clearly. Recovery is not described as something that happens automatically just because time passes.
Tracing Control After a Failure
When handling an I/O error, the question is what happens to the program's flow after the failure. The flowchart below follows the general path. The program performs an operation. The stream is either working or in the fail state. The program then branches based on that state. A recovery branch leads back to a new attempt, while a branch that cannot recover leads to reporting the problem.
The diagram is a general model rather than a fixed recipe. It shows the central habit: check the stream after the operation, and let that check decide which path the program takes. The branch on recoverability is a judgment the program must make case by case, which is the next topic.
Why Some Errors Are Only Potentially Recoverable
The source describes the stream state fail as the tool for handling potentially recoverable I/O errors. The word potentially matters. It means that some I/O errors are the kind a program can respond to and continue past, while the program still has to decide, case by case, whether recovery makes sense. The source does not claim that every I/O error can be recovered from.
The practical goal is to handle an error that the program has reason to expect and can react to, rather than to pretend the operation succeeded. Some failures, such as a value that does not match what was expected, give the program a clear next step: ask again. Others, such as a broken connection to the source or destination, may leave no sensible way to continue. The table below compares these two situations.
| Aspect | Potentially recoverable error | Error that cannot be recovered from |
|---|---|---|
| Typical cause from the source | Data does not match what the program expected | A problem with the connection to the source or destination may leave no usable path |
| Stream state | Fail state is recorded and examined | Fail state is recorded and examined |
| Program's decision | Choose a deliberate recovery action such as asking again or using a fallback | Report the problem clearly rather than assume success |
| What the program must avoid | Continuing as if the operation succeeded | Continuing as if the operation succeeded |
Recoverable and unrecoverable I/O errors both require checking the stream. They differ in what the program does next.
Handling a Mistyped Number
Responding to a failed read of a user's number
A program needs the user to type a whole number. The user types text that is not a number. How should the program use the fail state to decide what happens next?
- 1Perform the operation
The program asks the stream to read a value typed by the user. The read cannot produce a valid number from the text, so the operation fails.
- 2Let the stream record the failure
The stream enters the fail state. The failure is recorded rather than being hidden in the output.
- 3Check the state
The program examines the stream state instead of assuming the value is valid. This is the step that prevents wrong results from spreading.
- 4Decide whether recovery makes sense
A mismatch between typed text and the expected number is the kind of error the program can react to. It is potentially recoverable, so the program chooses a recovery action.
- 5Take a deliberate action
The program asks the user to type the number again, starting a new attempt at the operation.
The failure is noticed and handled before any calculation uses bad data. The program resumed by making a deliberate new attempt, not by ignoring the failure.
Change one fact in this scenario. Suppose the connection to the destination the program writes to has a fault. Retrying the same write may not make sense if the fault is not cleared. In that case the program should report the problem clearly rather than repeat the attempt indefinitely. The same check-the-state habit serves both cases; only the branch the program takes differs.
Mistakes When Responding to an I/O Error
Common mistake Ignoring the fail state entirely
What it looks likeThe program reads a value and uses it immediately, without checking whether the operation succeeded.
Why it failsThe source says a program that ignores these failures can produce wrong results without warning anyone.
Do this insteadCheck the stream after the operation and branch on the result before using the data.
Common mistake Retrying without fixing the cause
What it looks likeAfter a connection failure, the program repeats the same write again and again with no change.
Why it failsA retry only makes sense for an error the program has reason to expect and can react to. A fault that persists will keep failing.
Do this insteadDecide case by case whether recovery makes sense. If it does not, report the problem clearly.
Common mistake Treating the stream as healthy because the flag was reset
What it looks likeThe program clears the failure record and continues, without changing the input or the connection that caused the problem.
Why it failsRecovery is described as a deliberate action taken after the failure, so simply moving past the record does not resolve the underlying cause.
Do this insteadTake a specific recovery action such as asking for the value again or using a fallback, and confirm the operation succeeds before using its result.
Common mistake Assuming every I/O error is recoverable
Why it failsThe source explicitly says not every I/O error can be recovered from.
Do this insteadTreat recoverability as a per-case judgment and be ready to report the problem.
Predicting the Next Step After a Failed Read
What do you think happens?
A read operation fails and the stream enters the fail state. Before the program uses the value it just read, what should it do first?
Reveal answer
Check the stream state to see whether the operation failed
The source describes checking the stream after an operation and branching on the result before using the data. Assuming success is the mistake the mechanism exists to prevent.
A program reads a list of numbers from a file. Partway through, the stream enters the fail state. Describe, in order, the steps the program should take before any number is added to a total. Then state whether the error should be retried or reported, and justify your choice using the idea that recoverability is decided case by case.
Hints
- Start with the order of events: the failure is recorded first, then the program checks for it, then it chooses a response.
- Ask whether the cause of the failure is something the program can reasonably fix or retry, or whether it points to a problem that persists.
- Remember that the fail flag only reports the failure; it does not decide the response.
Key Points to Carry Forward
- A stream is the object through which input or output flows, and it has a state at each moment.
- The fail state records that an I/O operation has failed, so the program can examine that record instead of assuming success.
- Control moves through a sequence: the operation runs, the stream records any failure, the program checks the state, and then the program chooses a response.
- Some I/O errors are potentially recoverable, but the program must decide case by case whether recovery makes sense, and some errors must be reported instead.
Key Takeaways
- The fail state is a recorded fact that an I/O operation went wrong, which the program can check instead of guessing from the output.
- The program must check the stream after each operation and branch on that result before using the data.
- Some I/O errors are potentially recoverable, such as a value that does not match what was expected, but not every error can be recovered from.
- Recovery is a deliberate action such as asking again or using a fallback, and an unrecoverable failure should be reported clearly.