Skip to content

Commit

Permalink
Deferred is subtype of Effect (#3572)
Browse files Browse the repository at this point in the history
Co-authored-by: maksim.khramtsov <maksim.khramtsov@btsdigital.kz>
  • Loading branch information
2 people authored and mikearnaldi committed Sep 10, 2024
1 parent 63191b4 commit b4dd4b8
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 11 deletions.
16 changes: 16 additions & 0 deletions .changeset/gorgeous-toes-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"effect": minor
---

The `Deferred<A>` is now a subtype of `Effect<A>`. This change simplifies handling of deferred values, removing the need for explicit call `Deffer.await`.

```typescript
import { Effect, Deferred } from "effect"

Effect.gen(function* () {
const deferred = yield* Deferred.make<string>()

const before = yield* Deferred.await(deferred)
const after = yield* deferred
})
```
10 changes: 9 additions & 1 deletion packages/effect/dtslint/Unify.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type * as Deferred from "effect/Deferred"
import type * as Effect from "effect/Effect"
import * as Either from "effect/Either"
import type * as Exit from "effect/Exit"
Expand Down Expand Up @@ -66,8 +67,13 @@ export type RcRefUnify = Unify.Unify<
| RcRef.RcRef<1, 2>
| RcRef.RcRef<"a", "b">
>
// $ExpectType Deferred<1, 2> | Deferred<"a", "b">
export type DeferredUnify = Unify.Unify<
| Deferred.Deferred<1, 2>
| Deferred.Deferred<"a", "b">
>

// $ExpectType 0 | Option<string | number> | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E">
// $ExpectType 0 | Option<string | number> | Ref<1> | SynchronizedRef<1> | SubscriptionRef<1> | Deferred<1, 2> | Deferred<"a", "b"> | Ref<"A"> | SynchronizedRef<"A"> | SubscriptionRef<"A"> | Either<1 | "A", 0 | "E"> | Effect<1 | "A", 0 | "E", "R" | "R1"> | RcRef<1 | "A", 0 | "E">
export type AllUnify = Unify.Unify<
| Either.Either<1, 0>
| Either.Either<"A", "E">
Expand All @@ -83,5 +89,7 @@ export type AllUnify = Unify.Unify<
| SubscriptionRef.SubscriptionRef<"A">
| RcRef.RcRef<1, 0>
| RcRef.RcRef<"A", "E">
| Deferred.Deferred<1, 2>
| Deferred.Deferred<"a", "b">
| 0
>
23 changes: 21 additions & 2 deletions packages/effect/src/Deferred.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import * as core from "./internal/core.js"
import * as internal from "./internal/deferred.js"
import type * as MutableRef from "./MutableRef.js"
import type * as Option from "./Option.js"
import type { Pipeable } from "./Pipeable.js"
import type * as Types from "./Types.js"
import type * as Unify from "./Unify.js"

/**
* @since 2.0.0
Expand All @@ -37,11 +37,30 @@ export type DeferredTypeId = typeof DeferredTypeId
* @since 2.0.0
* @category models
*/
export interface Deferred<in out A, in out E = never> extends Deferred.Variance<A, E>, Pipeable {
export interface Deferred<in out A, in out E = never> extends Effect.Effect<A, E>, Deferred.Variance<A, E> {
/** @internal */
readonly state: MutableRef.MutableRef<internal.State<A, E>>
/** @internal */
readonly blockingOn: FiberId.FiberId
readonly [Unify.typeSymbol]?: unknown
readonly [Unify.unifySymbol]?: DeferredUnify<this>
readonly [Unify.ignoreSymbol]?: DeferredUnifyIgnore
}

/**
* @category models
* @since 3.8.0
*/
export interface DeferredUnify<A extends { [Unify.typeSymbol]?: any }> extends Effect.EffectUnify<A> {
Deferred?: () => Extract<A[Unify.typeSymbol], Deferred<any>>
}

/**
* @category models
* @since 3.8.0
*/
export interface DeferredUnifyIgnore extends Effect.EffectUnifyIgnore {
Effect?: true
}

/**
Expand Down
20 changes: 12 additions & 8 deletions packages/effect/src/internal/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import * as _blockedRequests from "./blockedRequests.js"
import * as internalCause from "./cause.js"
import * as deferred from "./deferred.js"
import * as internalDiffer from "./differ.js"
import { effectVariance, StructuralCommitPrototype } from "./effectable.js"
import { CommitPrototype, effectVariance, StructuralCommitPrototype } from "./effectable.js"
import { getBugErrorMessage } from "./errors.js"
import type * as FiberRuntime from "./fiberRuntime.js"
import type * as fiberScope from "./fiberScope.js"
Expand Down Expand Up @@ -2787,14 +2787,18 @@ const exitCollectAllInternal = <A, E>(
// -----------------------------------------------------------------------------

/** @internal */
export const deferredUnsafeMake = <A, E = never>(fiberId: FiberId.FiberId): Deferred.Deferred<A, E> => ({
[deferred.DeferredTypeId]: deferred.deferredVariance,
state: MutableRef.make(deferred.pending([])),
blockingOn: fiberId,
pipe() {
return pipeArguments(this, arguments)
export const deferredUnsafeMake = <A, E = never>(fiberId: FiberId.FiberId): Deferred.Deferred<A, E> => {
const _deferred = {
...CommitPrototype,
[deferred.DeferredTypeId]: deferred.deferredVariance,
state: MutableRef.make(deferred.pending<A, E>([])),
commit() {
return deferredAwait(this)
},
blockingOn: fiberId
}
})
return _deferred
}

/* @internal */
export const deferredMake = <A, E = never>(): Effect.Effect<Deferred.Deferred<A, E>> =>
Expand Down
10 changes: 10 additions & 0 deletions packages/effect/test/Deferred.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,14 @@ describe("Deferred", () => {
)
assert.isTrue(Exit.isInterrupted(result))
}))
it.effect("is subtype of Effect", () =>
Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const ref = yield* Ref.make(13)
yield* Deferred.complete(deferred, Ref.updateAndGet(ref, (n) => n + 1))
const result1 = yield* deferred
const result2 = yield* deferred
assert.strictEqual(result1, 14)
assert.strictEqual(result2, 14)
}))
})

0 comments on commit b4dd4b8

Please sign in to comment.