Skip to content

Conversation

@sebsto
Copy link
Collaborator

@sebsto sebsto commented Nov 12, 2025

The goal of this PR is to simplify the code and take advantage of new capabilities offered by the Swift 6.2 compiler, when possible.

However, one of the tenet of this project is to support the last three Swift version (6.0, 6.1, and 6.2 at the time of this writing). I therefore introduced this change for Swift 6.2 only, keeping existing code for Swift 6.0 and Swift 6.1.
When this change will be merged, we will create an issue to remember cleaning up this code when this project will not support 6.0 and 6.1 anymore (when 6.4 will be released, probably in Sept - Oct 2026)

Issue

Get rid of the isolation: isolated (any Actor)? = #isolation parameter and rely on the non isolated(nonsending) default instead.

Description of changes

  • Enable two feature flags for upcoming features
        .enableUpcomingFeature("NonisolatedNonsendingByDefault"),
        .enableUpcomingFeature("InferIsolatedConformances"),
  • Duplicate the file LambdaRuntimeClient+ChannelHandler.swift. One copy for Swift >= 6.2 and one copy for Swift < 6.2
  • Remove isolation: isolated (any Actor)? = #isolation on the >= 6.2 version
  • Add Sendable conformance to LambdaResponseStreamWriter (read the API Breakage section hereunder)
  • Update LambdaResponseStreamWriterTests to transform mock classes to actors

New/existing dependencies impact assessment

We think these changes might require a major version update, for multiple reasons.

First, by default, all public functions are now nonisolated. This might break existing Lambda functions making assumptions about isolation status.

Second, to allow the compiler to add nonisolated(nonsending) by default, all parameters to closures must be Sendable.
This is unfortunately not the case for the low-level Lambda handle() function (when used as a closure), because LambdaResponseStreamWriter is not Sendable.

Therefore, we added Sendable conformance to LambdaResponseStreamWriter which might be a breaking change for anyone doing something fancy with it. Basic usage to this writer will not be affected.

Existing Lambda functions using this function might break.

    public mutating func handle(
        _ event: ByteBuffer,
        responseWriter: some LambdaResponseStreamWriter,
        context: LambdaContext

Two examples projects where affected by the feature flag: HelloWorldNoTraits and Streaming+Codable.

  1. [HelloWorldNoTraits]: no change required to the project, adding Sendable to LambdaResponseStreamWriter was enough to allow the project to compile
  2. [Streaming+Codable]: we turned on the feature flag on the example project to solve compilation errors.

We want to collect community feedback about your usage and trying to understand use cases where this change breaks your code.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@sebsto sebsto self-assigned this Nov 12, 2025
@sebsto sebsto added 🔨 semver/patch No public API change. ⚠️ semver/major Breaks existing public API. and removed 🔨 semver/patch No public API change. labels Nov 12, 2025
@sebsto sebsto force-pushed the sebsto/nonisolatednonsending branch from e5e6694 to 03dc004 Compare November 13, 2025 08:50
Sebastien Stormacq added 3 commits November 13, 2025 10:05
@sebsto
Copy link
Collaborator Author

sebsto commented Nov 13, 2025

@mattmassicotte WDYT ?

Copy link
Contributor

@mattmassicotte mattmassicotte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not have enough context here to know if this is a reasonable path to take. However!

I remain surprised that these problems even came up. Moving from an isolated param to nonisolated(nonsending) is supposed to be source-compatible if a #isolation default was present and being used. And it seems like it was in all these cases...

/// A writer object to write the Lambda response stream into. The HTTP response is started lazily.
/// before the first call to ``write(_:)`` or ``writeAndFinish(_:)``.
public protocol LambdaResponseStreamWriter {
public protocol LambdaResponseStreamWriter: Sendable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a Sendable requirement to a public protocol is definitely a breaking change. I do not understand the full implications of this, but it certainly has the potential to make it much harder for clients to conform to the protocol.


/// Mock implementation of LambdaResponseStreamWriter for testing
final class MockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
final actor MockLambdaResponseStreamWriter: LambdaResponseStreamWriter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A common effect of adding a Sendable conformance to a protocol is pushing implementers to move from classes to actors. This is also a major change, because it now forces call sites to be async, as we see above. This, in turn, can introduce actor reentrancy problems.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but this is a mock just used for unit testing. I think we can afford the change in this context. Also, it doesn't break the public API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚠️ semver/major Breaks existing public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants