Skip to content

Collapse run() overloads behind a generic Execution type#262

Merged
iCharlesHu merged 1 commit into
swiftlang:mainfrom
iCharlesHu:charles/too-many-overloads
May 15, 2026
Merged

Collapse run() overloads behind a generic Execution type#262
iCharlesHu merged 1 commit into
swiftlang:mainfrom
iCharlesHu:charles/too-many-overloads

Conversation

@iCharlesHu
Copy link
Copy Markdown
Contributor

Reduce the 14+ run() overloads to two (one executable-based, one configuration-based) by making Execution generic over its input, output, and error types. The body closure now takes a single Execution<Input, Output, Error>, and type-conditional extensions expose standardInputWriter, standardOutput, and standardError only for the matching stream types.

Companion changes:

  • Merge ExecutionOutcome into ExecutionResult<ClosureResult, Output, Error>, which now carries the body closure's return value via closureOutput. Now all run() methods return ExecutionResult. ExecutionOutcome remains as an internal helper.

  • Expose CustomWriteInput and SequenceOutput publicly, along with the .inputWriter and .sequence factories. Callers opt in per stream:

    • input: .inputWriter unlocks execution.standardInputWriter;
    • output: .sequence unlocks execution.standardOutput;
    • error: .sequence unlocks execution.standardError.

@iCharlesHu
Copy link
Copy Markdown
Contributor Author

Resolves: #249
Resolves: #247

Comment thread Sources/Subprocess/API.swift Outdated
@jakepetroules
Copy link
Copy Markdown
Contributor

This looks really nice, I think it is a big improvement! Summarizing the 6 overloads, there are 3 axes of variation with 2 possibilities each.

First arg Input type Has body: closure?
Executable Span No
Executable InputProtocol No
Executable InputProtocol Yes
Configuration Span No
Configuration InputProtocol No
Configuration InputProtocol Yes

This seems like a fairly reasonable number to me, especially as the overload mechanism no longer relies on the closure arguments.

The only thing I can think of to reduce the overloads further is that you could eliminate the 3 "executable" overloads and have only the "configuration" ones, then move run() from a global to a member of Configuration, which would also address one of the concerns @weissi pointed out w.r.t. global namespace membership. That said, I think that discussion could be had separately from this improvement if that's something you are willing to consider.

Comment thread Sources/Subprocess/Execution.swift
@jakepetroules
Copy link
Copy Markdown
Contributor

I also get compiler warnings about AsyncSequence and nonisolated on Input+Foundation.swift on the write() functions at lines 78 and 132. You should be able to fix this by changing:

for try await data in asyncSequence {

to:

var iterator = self.sequence.makeAsyncIterator()
while let chunk = try await iterator.next(isolation: #isolation) {

but that requires a macOS 15 deployment target. FWIW, I think we could realistically consider raising Subprocess's deployment target to macOS 15 at this point.

Comment thread Sources/Subprocess/Result.swift Outdated
@iCharlesHu iCharlesHu force-pushed the charles/too-many-overloads branch 2 times, most recently from 6a298bc to 7e880d5 Compare May 14, 2026 22:05
Comment thread Sources/Subprocess/Result.swift Outdated
Reduce the 14+ run() overloads to two (one executable-based, one configuration-based) by making Execution generic over its input, output, and error types. The body closure now takes a single Execution<Input, Output, Error>, and type-conditional extensions expose standardInputWriter, standardOutput, and standardError only for the matching stream types.

Companion changes:

- Merge ExecutionOutcome into ExecutionResult<ClosureResult, Output, Error>, which now carries the body closure's return value via closureOutput. Now all run() methods return ExecutionResult. ExecutionOutcome remains as an internal helper.

- Expose CustomWriteInput and SequenceOutput publicly, along with the .inputWriter and .sequence factories. Callers opt in per stream: input: .inputWriter unlocks execution.standardInputWriter; output: .sequence unlocks execution.standardOutput; error: .sequence unlocks execution.standardError.
@iCharlesHu iCharlesHu force-pushed the charles/too-many-overloads branch from 7e880d5 to 274ca48 Compare May 15, 2026 17:04
@iCharlesHu
Copy link
Copy Markdown
Contributor Author

Make ExecutionResult.{standardOutput|standardError|closureOutput} non-conditional and non-optional. For Output with Void OutputType these properties will just be Void, which Xcode correctly warns you about.

warning

@iCharlesHu iCharlesHu merged commit 4b97628 into swiftlang:main May 15, 2026
44 checks passed
@iCharlesHu iCharlesHu deleted the charles/too-many-overloads branch May 15, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants