Skip to content

Conversation

@plemarquand
Copy link
Contributor

Change the underlying storage type from Value? to storing Value, with optional-specific operations moved to constrained extensions.

This improves type safety by eliminating unnecessary optionality for non-optional types.

This stronger type constraint makes it more difficult for the struct to be misused. For instance in the current implementation the extension method increment() will fail to increment if the user forgot to initialize the ThreadSafeBox with a value. Now a value must be set initially before increment is called.

Also this patch prevents a race condition in the memoize methods where the call to the memoized body was not guarded by a lock which allowed multiple threads to call memoize at once and produce inconsistent results.

Finally, fix the subscript setter so it works properly with structs, as the if var value and then value set will set the value on a copy, not on the self.underlying struct. Now that the type is no longer optional this unwrapping isn't necessary and we can set directly on the value.

Change the underlying storage type from `Value?` to storing `Value`, with
optional-specific operations moved to constrained extensions.

This improves type safety by eliminating unnecessary optionality for
non-optional types.

This stronger type constraint makes it more difficult for the struct to
be misused. For instance in the current implementation the extension
method `increment()` will fail to increment if the user forgot to
initialize the `ThreadSafeBox` with a value. Now a value must be set
initially before increment is called.

Also this patch prevents a race condition in the `memoize` methods where
the call to the memoized `body` was not guarded by a lock which allowed
multiple threads to call memoize at once and produce inconsistent
results.

Finally, fix the subscript setter so it works properly with `structs`,
as the `if var value` and then value set will set the value on a copy,
not on the `self.underlying` struct. Now that the type is no longer
optional this unwrapping isn't necessary and we can set directly on the
value.
@plemarquand
Copy link
Contributor Author

@swift-ci test

extension ThreadSafeBox: @unchecked Sendable where Value: Sendable {}

/// Thread-safe value boxing structure that provides synchronized asynchronous memoization of a wrapped value.
public final class AsyncMemoizableThreadSafeBox<Value: Sendable>: @unchecked Sendable {
Copy link
Contributor

@jakepetroules jakepetroules Dec 8, 2025

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was to replace the async version of memoize that was removed from ThreadSafeBox, in order to avoid instantiating the AsyncCoordinator in every case.

AsyncCache does look like it can replace this use case, so I'll remove this and switch to it.

Copy link
Contributor

Choose a reason for hiding this comment

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

AsyncSingleValueCache in this case, not AsyncCache (I edited my post after you already saw it)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants