effect icon indicating copy to clipboard operation
effect copied to clipboard

feat(Stream): switchMap

Open dilame opened this issue 1 year ago • 10 comments

Type

  • [ ] Refactor
  • [x] Feature
  • [ ] Bug Fix
  • [ ] Optimization
  • [ ] Documentation Update

Description

Related

  • Related Issue #
  • Closes #

dilame avatar Jun 10 '24 16:06 dilame

🦋 Changeset detected

Latest commit: d86a4164fed8fb88013e8f4089f16fe4492eef4a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 31 packages
Name Type
effect Minor
@effect/cli Major
@effect/cluster-browser Major
@effect/cluster-node Major
@effect/cluster-workflow Major
@effect/cluster Major
@effect/experimental Major
@effect/opentelemetry Major
@effect/platform-browser Major
@effect/platform-bun Major
@effect/platform-node-shared Major
@effect/platform-node Major
@effect/platform Major
@effect/printer-ansi Major
@effect/printer Major
@effect/rpc-http Major
@effect/rpc Major
@effect/schema Major
@effect/sql-d1 Major
@effect/sql-drizzle Major
@effect/sql-kysely Major
@effect/sql-mssql Major
@effect/sql-mysql2 Major
@effect/sql-pg Major
@effect/sql-sqlite-bun Major
@effect/sql-sqlite-node Major
@effect/sql-sqlite-react-native Major
@effect/sql-sqlite-wasm Major
@effect/sql Major
@effect/typeclass Major
@effect/vitest Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

changeset-bot[bot] avatar Jun 10 '24 16:06 changeset-bot[bot]

What is the benefit over flatMap(f, { switch: true })?

tim-smart avatar Jun 11 '24 22:06 tim-smart

I guess just verbosity, not sure if this is common enough to justify it

mikearnaldi avatar Jun 12 '24 09:06 mikearnaldi

RxJS also do have a switchMap operator, and it's one of the most important and widely used operator.

I decided to make it as a separate operator not just because of verbosity, but because of clarity and visualization.

This is a real code from my project

export const BinanceWsUnitSingleLayer = Layer.effect(
  BinanceWsUnitTag,
  Effect.gen(function* () {
    // ....................................................................
    return {
      createStream(
        stream: string,
      ): Stream.Stream<
        unknown,
        | BinanceWsConnectionError
        | BinanceWsResponseError
        | BinanceWsConnectionCloseError
      > {
        return Stream.suspend(() => {
          debug(`📤Requesting stream "${stream}"`);
          let stream$ = streams.get(stream);
          if (stream$) {
            return stream$;
          }
          stream$ = connection.pipe(
            Stream.flatMap(
              (ws) =>
                Effect.request(
                  BinanceWsSubscribeRequest({ stream, ws }),
                  RequestResolver.contextFromEffect(subscribe),
                ).pipe(
                  Stream.unwrap,
                  Stream.ensuring(
                    Effect.gen(function* () {
                      debug(`🔻 Unsubscribing ${stream}`);
                      streams.delete(stream);
                      yield* Effect.request(
                        BinanceWsUnsubscribeRequest({ stream, ws }),
                        RequestResolver.contextFromEffect(unsubscribe),
                      );
                    }),
                  ),
                ),
              { switch: true, concurrency: 1 },
            ),
          );
          streams.set(stream, stream$);
          return stream$;
        });
      },
    } satisfies BinanceWsUnit;
  }),
)

When you fluently read this code, it is not really easy to notice the options parameter for flatMap, you only see Stream.flatMap, but default flatMap behaviour is different. In addition, there are no clear documentation about what does switch option means. On the site it is written

if the order of concatenation is not important for us, we can use the switch option.

And it doesn't describes this concept.

Actually, i thinks that the switch option changes the behaviour dramatically enough to extract it to the separate operator with it's own documentation and example, which i also provided in this PR.

dilame avatar Jun 12 '24 09:06 dilame

@tim-smart what should we do? I am kind of in favour of accepting this given the semantic specificity

mikearnaldi avatar Jun 17 '24 12:06 mikearnaldi

@tim-smart what should we do? I am kind of in favour of accepting this given the semantic specificity

I think we can add it back as flatMapSwitch (what it was called before we consolidated the apis).

We would then mark the switch option as depreciated and remove it in 4.0?

tim-smart avatar Jun 18 '24 09:06 tim-smart

@dilame can you pls fix the version in since to 3.5 and I'll merge it

mikearnaldi avatar Jun 22 '24 12:06 mikearnaldi

@mikearnaldi done

dilame avatar Jun 23 '24 21:06 dilame

/rebase

dilame avatar Jul 12 '24 15:07 dilame

@dilame can you pls fix the version in since to 3.5 and I'll merge it

Hi! Just wanted to remind that i changed the version in since that time to 3.5.0 and just now i changed it to 3.6.0 😃

dilame avatar Jul 17 '24 16:07 dilame