Skip to content

Breaking change: OptionAsync await + Producer.merge

Compare
Choose a tag to compare
@louthy louthy released this 05 Feb 20:45
· 54 commits to main since this release

This is a fixes release.

OptionAsync

I have brought forward a change to OptionAsync that I was saving for v5: the removal of the async-awaiter. You can't now await an OptionAsync. The resulting value wasn't clear, and honestly the async/await machinery is really quite shonky outside of using it for Tasks.

I have made the OptionAsync implementation aware of nullable references, and so you can now await the Value property instead:

    public Task<A?> Value

That will reproduce the same behaviour as before. You can still await the ToOption() method, which returns a Task<Option<A>>, if you want to do matching on the underlying option. Or call the various Match* methods.

This release fixes the following issues:

Producer.merge error handling

Producer merging was silently ignoring errors. They now exit and return the first error and shutdown other producers they were merged with. Merged producers also listen for cancellation correctly now.

Finally, you can only merge produces with a bound value of Unit. This is to stop the silent dropping of their return value as well as the need to provide a final (bound) value for merged producers, which doesn't really make sense. That also means the + operator can't work any more because it can't be defined for the Producer<..., A> type. So you must use Producer.merge.

This fixes an issue mentioned in: #1177

repeatM doesn't cause a stack-overflow

Certain elements of the Pipes capability of language-ext are direct ports from the Haskell Pipes library, which uses recursion everywhere. repeatM was causing a stack-overflow on usage, this is now fixed.

Example usage:

public static Effect<Runtime, Unit> effect =>
    Producer.repeatM(Time<Runtime>.nowUTC) | writeLine<DateTime>(); 

static Consumer<Runtime, X, Unit> writeLine<X>() =>
    from x in awaiting<X>()
    from _ in Console<Runtime>.writeLine($"{x}")
    from r in writeLine<X>()
    select r;

repeat improvements

Removed the Repeat case from the Pipes DSL which simplifies it and brings it closer to the Haskell version. Updated the repeat combinator function to use the same Enumerate case that yieldAll uses. This has benefits that it doesn't spread out when composed with other Proxy types. This is should mean it's easier to pick bits of the expression to repeat, rather than the whole effect being repeated due to the spread.

Trampoline

Added trampolining functionality. It's relatively light at the moment, I am considering approaches to enable genuine recursion in the effects system. Don't rely on this, it may be removed if it doesn't prove useful and almost certainly will have API changes if it stays.