Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 17, 2025

Overview

This PR provides a comprehensive evaluation of the proposed WebStreams implementation (from the issue) as an alternative to the current asPipes implementation. The evaluation includes performance benchmarks, feature comparison, semantic alignment analysis, and automated tests.

Key Findings

Performance: Current Implementation is 6-10x Faster

Automated benchmarks show the current implementation significantly outperforms the WebStreams alternative:

  • Single value operations: ~6-10x faster
  • The WebStreams approach has overhead from stream creation and reader management

Semantic Alignment: Different Design Goals

The project's stated goal is to "model the semantics of the proposed |> pipeline operator." The F# pipeline operator works with single values, not arrays:

// F# style: value |> transform1 |> transform2

// Current implementation ✅ (matches F# semantics)
const { pipe, asPipe } = createAsPipes();
const inc = asPipe(x => x + 1);
const p = pipe(5);
p | inc | inc;
await p.run(); // 6 (single value)

// WebStreams alternative ❌ (array-based, different paradigm)
const $ = pipe();
$(x => x + 1) | $(x => x + 1);
await $.run([5]); // [7] (array)

The WebStreams approach serves a different use case (batch stream processing) rather than modeling the F# pipeline operator.

Feature Comparison

The current implementation has critical features absent from the WebStreams alternative:

Feature Current WebStreams
Higher-order composition (pipes returning pipes)
Parameterized functions (add(10)) ⚠️ Closures only
Object method integration (asPipe(Math))
Single value processing ❌ Array-only
Async generator support ✅ Via stream.js

Recommendation

Keep the current implementation. While the WebStreams alternative is an interesting exploration of native Web APIs, it:

  1. Doesn't align with the project's stated goals (modeling F# pipeline operator semantics)
  2. Underperforms by 6-10x in typical usage scenarios
  3. Lacks critical features like higher-order composition and object integration
  4. Serves a different use case (batch stream processing vs single-value pipelines)

Deliverables

This PR adds comprehensive evaluation documentation and tests:

  1. EVALUATION-README.md - Navigation guide for the evaluation
  2. EVALUATION-SUMMARY.md - Executive summary with quick comparison table
  3. EVALUATION.md - Detailed technical analysis with architecture considerations
  4. webstreams-evaluation.test.js - 17 automated tests validating the comparison

Testing

All tests pass (65 total):

  • ✅ 48 original tests (no regression)
  • ✅ 17 new evaluation tests (performance, features, semantics)

Possible Future Enhancement

If batch processing becomes a priority, the evaluation suggests adding an optional batch mode to the current implementation rather than replacing it:

const { pipe, asPipe, batch } = createAsPipes();

// Current: single value (keep as primary)
const p1 = pipe(5) | inc | double;
await p1.run(); // 12

// Optional: batch processing (new enhancement)
const p2 = batch([1,2,3,4,5]) | inc | double;
await p2.run(); // [4, 6, 8, 10, 12]

This would preserve the F# pipeline semantics while adding batch capability when needed.

Conclusion

The WebStreams implementation is educationally interesting and demonstrates creative use of Web APIs, but it fundamentally serves a different purpose than asPipes. The current implementation better achieves the project's goal of modeling F# pipeline operator semantics with superior performance and features.

Original prompt

This section details on the original issue you should resolve

<issue_title>Micro alternative using streams</issue_title>
<issue_description>This is not as robust as yours but thought the implementation of using WebStreams was interesting enough to share:

function pipe() {
  const pipeline = new Set();
  const builder = (fn) => {
    const unit = {
      toStream: () => new TransformStream({
        transform: async (data, cont) => cont.enqueue(await fn(data)),
      }),
      [Symbol.toPrimitive]: () => (pipeline.add(unit), 0),
    };
    return unit;
  };
  builder.run = (items) => {
    let stream = new ReadableStream({
      start: (controller) => {
        for (const item of items) controller.enqueue(item);
        controller.close();
      },
    })
    pipeline.forEach((unit) => stream = stream.pipeThrough(unit.toStream()));
    return Array.fromAsync(stream);
  };
  return builder;
}

{
  const $ = pipe();
  $(x => x + 1)
    | $(x => x + 1)
    | $(x => x + 1)
    | $(x => x + 1)
    | $(x => x + 1);
  console.log(await $.run([0, 10, 20, 30, 50]));
  console.log(await $.run([100, 110, 120, 130, 150]));
}
```</issue_description>

<agent_instructions>could you evaluate this and see if this could be a better alternative to our current implementation?</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

Fixes #15


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Add micro alternative using WebStreams Evaluation: WebStreams alternative implementation analysis Oct 17, 2025
Copilot AI requested a review from irony October 17, 2025 08:25
Copilot finished work on behalf of irony October 17, 2025 08:25
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.

Micro alternative using streams

2 participants