This proposal addresses specific terminology issues in the Terminal.Gui Application.Run lifecycle while preserving what works well. Based on maintainer feedback, we keep Begin, End, and RequestStop unchanged, and focus on the real sources of confusion.
Begin and End - Clear, concise lifecycle pairing without being wordyRequestStop - Non-blocking nature is appropriately conveyed by "Request"RunLoop and RunIteration - RunLoop starts the driver's mainloop, RunIteration processes one iterationRunState Sounds Like State DataCurrent:
RunState runState = Application.Begin(toplevel);
Application.RunLoop(runState);
Application.End(runState);
Issue: The name RunState suggests it holds state/data about the run, but it's actually:
Begin() to pair with End()Proposed Options:
Option A: RunToken
RunToken token = Application.Begin(toplevel);
Application.RunLoop(token);
Application.End(token);
Option B: ExecutionContext
ExecutionContext context = Application.Begin(toplevel);
Application.RunLoop(context);
Application.End(context);
Option C: Keep RunState but clarify in docs
EndAfterFirstIteration Confuses "End" with Loop ControlCurrent:
Application.EndAfterFirstIteration = true; // Controls RunLoop, not End()
RunState rs = Application.Begin(window);
Application.RunLoop(rs); // Stops after 1 iteration due to flag
Application.End(rs); // This is actual "End"
Issue:
End() method, but it actually controls RunLoop()End() gets calledProposed Options:
Option A: StopAfterFirstIteration
Application.StopAfterFirstIteration = true;
RequestStop which also affects the loopOption B: SingleIteration
Application.SingleIteration = true;
Option C: RunLoopOnce
Application.RunLoopOnce = true;
Current:
Application.Run(window); // Complete lifecycle
Application.RunLoop(state); // Starts the driver's mainloop
Application.RunIteration(state); // One iteration
Issue: Three different APIs with "Run" in the name doing different things at different levels.
Note: @tig's feedback indicates the distinction between RunLoop and RunIteration is important and understood. The "Run" prefix may not be a critical issue if the distinction is clear.
Possible future consideration (not recommended now):
Change only what's most confusing:
RunState → RunToken (or ExecutionContext)
EndAfterFirstIteration → StopAfterFirstIteration
RequestStop terminologyKeep everything else:
Begin / End - Perfect as-isRequestStop - Clear non-blocking signalRunLoop / RunIteration - Distinction is valuableRun() - Familiar high-level APICurrent (Confusing):
// High-level
Application.Run(window);
// Low-level
Application.EndAfterFirstIteration = true;
RunState rs = Application.Begin(window);
Application.RunLoop(rs);
Application.End(rs);
Proposed (Clearer):
// High-level (unchanged)
Application.Run(window);
// Low-level (clearer)
Application.StopAfterFirstIteration = true;
RunToken token = Application.Begin(window);
Application.RunLoop(token);
Application.End(token);
It's important to preserve the distinction:
RunLoop(token) - Starts the driver's MainLoop and runs until stopped
RunIteration repeatedlyRequestStop() is called or StopAfterFirstIteration is trueRunIteration(ref token) - Processes ONE iteration
Visual:
RunLoop(token):
┌─────────────────────┐
│ while (Running) │
│ RunIteration() │ ← One call
│ RunIteration() │ ← Another call
│ RunIteration() │ ← Another call
└─────────────────────┘
This distinction is valuable and should be preserved.
// Add new type
public class RunToken { ... }
// Add conversion from old to new
public static implicit operator RunToken(RunState state) => new (state.Toplevel);
// Mark old type obsolete
[Obsolete("Use RunToken instead. RunState will be removed in a future version.")]
public class RunState { ... }
// Add new property
public static bool StopAfterFirstIteration { get; set; }
// Mark old property obsolete
[Obsolete("Use StopAfterFirstIteration instead.")]
public static bool EndAfterFirstIteration
{
get => StopAfterFirstIteration;
set => StopAfterFirstIteration = value;
}
| Option | Pros | Cons | Recommendation |
|---|---|---|---|
RunToken |
Clear it's a token, concise | New terminology | ⭐ Best |
ExecutionContext |
Industry standard | Slightly longer | Good alternative |
RunHandle |
Clear it's a handle | "Handle" sounds Win32-ish | Acceptable |
RunContext |
Familiar pattern | "Context" overloaded in .NET | OK |
Keep RunState |
No change needed | Remains misleading | Not recommended |
| Option | Pros | Cons | Recommendation |
|---|---|---|---|
StopAfterFirstIteration |
Aligns with RequestStop | Slightly longer | ⭐ Best |
SingleIteration |
Shorter | Less obvious meaning | Good alternative |
RunLoopOnce |
Very explicit | Awkward phrasing | OK |
Keep EndAfterFirstIteration |
No change | Continues confusion | Not recommended |
Token/Context Pattern:
CancellationToken - token for cancellation scopeHttpContext - context for HTTP requestDbContext - context for database sessionRunToken (proposed) - token for execution scopeLoop Control Flags:
Application.Exit() - stops message loopDispatcher.InvokeShutdown() - stops dispatcherRequestStop() (keep), StopAfterFirstIteration (proposed)Q: Why not change Begin and End to BeginSession and EndSession?
A: Per maintainer feedback, "Session" makes the names wordy without adding clarity. Begin and End are clear, concise, and work well as a lifecycle pair.
Q: Why keep RunLoop?
A: The distinction between RunLoop (starts the driver's mainloop) and RunIteration (one iteration) is important and well-understood. The "Run" prefix is not the primary source of confusion.
Q: Why change RunState?
A: "State" implies the object holds state/data about the run. In reality, it's a token/handle for the Begin/End pairing. Calling it a "Token" or "Context" is more accurate.
Q: Why change EndAfterFirstIteration?
A: "End" in the flag name creates confusion with the End() method. The flag controls loop behavior, not lifecycle cleanup. "Stop" aligns better with RequestStop which also affects the loop.
Q: Is this bikeshedding?
A: No. These specific names (RunState, EndAfterFirstIteration) cause real confusion. The changes are minimal, focused, and address documented pain points while preserving what works.
Recommended Changes (Minimal Impact):
RunState → RunTokenEndAfterFirstIteration → StopAfterFirstIterationKeep Unchanged:
Begin / End - Clear and conciseRequestStop - Appropriately conveys non-blockingRunLoop / RunIteration - Distinction is valuableRun() - Familiar high-level APIBenefits:
This focused approach addresses real problems without over-engineering the solution.