Releases: polyadic/funcky
Funcky 3.5.0 | Funcky.Async 1.4.0 | Funcky.Xunit 2.1.0 | Funcky.Analyzers 1.4.0
This update is mainly to update to .NET 9 but also has several smaller improvements.
.NET 9
Thanks to the new [OverloadResolutionPriority]
attribute, we've been able finally fix
the ambiguous call errors when using DictionaryExtensions.GetValueOrNone
:
Dictionary<string, string> favouriteFoods = new();
Option<int> tausFavouriteFood = favouriteFoods.GetValueOrNone("Tau");
// ^^^^^^^^^^^^^^
// This used to produce a `error CS0121: The call is ambiguous between ...` error
// and now simply works 🎉
In good old fashion, we've also added new parse extensions:
ParseExtensions.ParseAssemblyNameInfoOrNone
ParseExtensions.ParseTypeNameOrNone
Policy for EOL Target Frameworks
We've explicitly written down our policy for how we deal
with older / EOL target frameworks.
In short: EOL target frameworks are supported by Funcky until the next major version.
However, we may no longer test Funcky against those target frameworks, so we
can't guarantee that everything works smoothly.
New APIs
In Funcky 3.0 we've changed CycleRange
and RepeatRange
to return an IBuffer
to enable us to memoize the collection, preventing unnecessary enumeration. This however
is unpractical for uses where you want to cycle an already materialized collection.
This release adds two new methods to accommodate that use case:
CycleMaterialized
and RepeatMaterialized
.
For convenient downcasting of Option<T>
, Result<T>
and Either<TLeft, T>
values, we've added a new
DownCast
class:
Option<object> option = Option.Some("hello world");
Option<string> downcasted = DownCast<string>.From(option);
Funcky.XUnit
Funcky.XUnit
has been updated to the latest version (2.9.3) of xUnit.net.
Due to changes in xUnit we've had to change the exception type thrown by our FunctionalAssert
methods
from AssertActualExpectedException
to XunitException
.
Funcky.Analyzers
The new analyzer rule λ1009
prevents you from accidentally default
-instantiating
Either
, Result
and EitherOrBoth
.
Funcky.Async
The PowerSet
and WithPrevious
extensions now correctly pass along the cancellation token.
Funcky 3.4.0 | Funcky.Async 1.3.0 | Funcky.XUnit 2.0.2
This update is mainly to update to .NET 8 but also has several smaller improvements.
Native AOT
Both Funcky and Funcky.Async have been annotated to be compatible with Native AOT.
The only exception is OptionJsonSerializer
which is not compatible with Native AOT.
.NET 8
We use the new C#12 and .NET features in the code, and expose new features through our API.
- .NET 8 added new overloads to their
TryParse
APIs. These changes are reflected in Funcky'sParseOrNone
APIs.ParseByteOrNone
overloads withReadOnlySpan<byte>
andstring?
ParseSByteOrNone
overloads withReadOnlySpan<byte>
ParseSingleOrNone
overloads withReadOnlySpan<byte>
ParseDoubleOrNone
overloads withReadOnlySpan<byte>
ParseDecimalOrNone
overloads withReadOnlySpan<byte>
ParseInt16OrNone
overloads withReadOnlySpan<byte>
ParseInt32OrNone
overloads withReadOnlySpan<byte>
ParseInt64OrNone
overloads withReadOnlySpan<byte>
ParseUInt16OrNone
overloads withReadOnlySpan<byte>
ParseUInt32OrNone
overloads withReadOnlySpan<byte>
ParseUInt64OrNone
overloads withReadOnlySpan<byte>
ParseNumberOrNone<TNumber>
overloadsParseOrNone<TParsable>
overloads
String Extensions
We implemented a few of the IEnumerable extensions which are very useful on strings.
Chunk
onstring
.SlidingWindow
onstring
.
Monads
- Implemented
UpCast
for the mondsOption
,Either
,Result
andSystem.Lazy
. - Implemented
InspectEmpty
onIEnumerable
andIAsyncEnumerable
- Implemented
ToAsyncEnumerable
extension onOption
IEnumerator
MoveNextOrNone
extension onIEnumerator<T>
Consistency
FindIndexOrNone
andFindLastIndexOrNone
extensions onList
What's Changed
- Add
MoveNextOrNone
extension forIEnumerator
by @bash in #739 - Add
ToAsyncEnumerable
extension forOption
by @bash in #741 - Implemented Chunk and SlidingWindow on string by @FreeApophis in #744
- Update Out-of-date Cartesian Product Docs by @bash in #747
- Implement Generic ParseOrNone extensions. by @FreeApophis in #745
- Disable UseWithArgumentNamesAnalyzer in Expression Trees by @bash in #751
- Implement
UpCast<T>.From(...)
by @bash in #756 - Update SDK to .NET 8 by @bash in #764
- Use
IsTargetFrameworkCompatible
Instead of Listing Frameworks Manually by @bash in #767 - Rename Parseable → Parsable by @bash in #769
- Use Primary Constructors by @bash in #768
- Forgotten to set TargetFramework to .net 8 by @FreeApophis in #770
- Use collection property count access by @FreeApophis in #771
- Avoid ToAsyncEnumerable when not really necessary by @FreeApophis in #772
- Use PolySharp by @FreeApophis in #774
- Use collection expressions by @FreeApophis in #775
- Declare Funcky.XUnit incompatibility with xunit 2.5 and 2.6 releases by @FreeApophis in #778
- Implement InspectEmpty on IEnumerable. by @FreeApophis in #776
- Add missing ParseExtensions.ParseCharOrNone by @FreeApophis in #780
- Implements FindIndexOrNone and FindLastIndexOrNone on List by @FreeApophis in #781
- Add .mailmap by @bash in #786
- Mention dual licensing in readme by @bash in #787
- Mark Funcky and Funcky.Async as AOT compatible by @bash in #784
Full Changelog: 3.3.0...3.4.0
Funcky 3.3.0 | Funcky.Analyzers 1.3.0 | Funcky.Xunit 2.0.1
This is a relatively minor release focusing on convenience for our monads Option
, Either
and Result
.
GetOrElse
and OrElse
for all
We've added GetOrElse
and OrElse
to Either
and Result
bringing them on par with Option
.
The corresponding analyzer now also correctly suggests using these methods instead of Match
for Result
and Either
.
Inspect
for the error case
All three alternative monads Option
, Either
and Result
now support inspecting the «error» case:
Option.InspectNone
- executes a side effect only when the option isNone
.Either.InspectLeft
- executes a side effect only when the either is on theLeft
side.Result.InspectError
- executes a side effect only when the result is anError
.
These methods are particularly useful for logging warnings/errors.
Funcky 3.2.0 | Funcky.Async 1.2.0
List Pattern for Option
We've added support for C# 11's List Patterns to Option<T>
.
This means that you can use regular switch
expressions / statements to match on options:
var greeting = person switch
{
{ FirstName: var firstName, LastName: [var lastName] } => $"Hello {firstName} {lastName}",
{ FirstName: var firstName } => $"Hi {firstName}",
};
record Person(string FirstName, Option<string> LastName);
Discard
The new Discard.__
field provides a short-hand for Unit.Value
to be used with switch
expressions.
using static Funcky.Discard;
return __ switch
{
_ when user.IsFrenchAdmin() => "le sécret",
_ when user.IsAdmin() => "secret",
_ => "(redacted)",
};
Retry with Exception
We've added overloads to the Retry
and RetryAsync
functions that allow retrying a function
as long as an exception is thrown.
Example from IoRetrier
:
// Retries an action until the file is no longer in use.
Task RetryWhileFileIsInUseAsync(IRetryPolicy policy, Action action)
=> RetryAsync(ActionToUnit(action), exception => exception is IOException && exception.HResult == FileInUseHResult, policy);
Funcky 3.1.0 | Funcky.Async 1.1.0 | Funcky.Analyzers 1.2.0
New APIs
- ✨
OptionExtensions.ToNullable
✨ StreamExtenions.ReadByteOrNone
- New overloads for
ElementAtOrNone
that take anIndex
. - New overload for
JoinToString
that takes anIEnumerable<string>
.
.NET 7
- .NET 7 added new overloads to their
TryParse
APIs. These changes
are reflected in Funcky'sParseOrNone
APIs. - The
ParseOrNone
methods include the new[StringSyntax]
attribute from .NET 7.
Analyzers
The new Option.Match
analyzer suggests simpler alternatives over custom Match
es including
the all-new ToNullable
extension.
Funcky 3.0.0 | Funcky.Async 1.0.0 | Funcky.XUnit 2.0.0
There's a handy Migration Guide available.
New APIs
Result.GetOrThrow
EnumerableExtensions.GetNonEnumeratedCountOrNone
PriorityQueue
PriorityQueueExtensions.DequeueOrNone
PeekOrNone
Traversable
The new Traverse
and Sequence
extension methods allow you to
«swap» the inner and outer monad (e.g. Result<Option<T>>
-> Option<Result<T>>
)
Memoize
The new Memoize
extension function returns an IBuffer
/ IAsyncBuffer
.
This new type represents ownership over the underlying enumerator (and is therefore IDisposable
).
CycleRange
and RepeatRange
have also been changed to return an IBuffer
.
ParseExtensions
The parse extensions have been improved with the goal of aligning more with the BCL.
Many of the changes are breaking.
- The functions now use BCL type names instead of C# type names
(e.g.ParseIntOrNone
has been renamed toParse
) - The parameter names and nullability have been changed to align with the BCL.
- Added
HttpHeadersNonValidatedExtensions
IReadOnlyList
/ IReadOnlyCollection
Funcky now communicates materialization in the IEnumerable<T>
extensions by returning
IReadOnlyList
or IReadOnlyCollection
. This reduces «multiple enumeration» warnings.
Materialize
Chunk
Partition
Shuffle
SlidingWindow
Split
Transpose
Sequence.Return
Disallowing null
Values
Our Option<T>
type has always disallowed null
values.
This has been extended to our other monads: Result<T>
, Either<L, R>
and Reader<E, R>
.
Breaking Changes
Option.None()
has been changed to a property. There's an automatic fix available for this.- Our
Match
functions now differentiate betweenFunc
andAction
.
TheAction
overloads have been renamed toSwitch
. - The return type of
EnumerableExtensions.ForEach
has been changed toUnit
. - Many parameter names and generic type names have been renamed in an attempt to unify naming across Funcky.
- All
Action
extensions have been moved to a new classActionExtensions
. EitherOrBoth
has been moved to theFuncky
namespace.- The retry policies have been moved to the
Funcky.RetryPolicies
namespace. Partition
returns a customPartitions
struct instead of a tuple.
Obsoleted APIs Removed
APIs that have been obsoleted during 2.x have been removed:
ObjectExtensions.ToEnumerable
Funcky.GenericConstraints.RequireClass
andRequireStruct
- All
Try*
APIs (TryGetValue
,TryParse*
, etc.). These APIs use theOrNone
suffix instead. Sequence.Generate
has been superceded bySequence.Successors
CartesianProduct
JSON Converter
We have removed the implicit System.Text.Json
converter for Option<T>
.
This means that you'll have to register the OptionJsonConverter
yourself.
Moved to Funcky.Async
All APIs related to IAsyncEnumerable
and Task
have been moved to the new Funcky.Async
package:
AsyncEnumerableExtensions
Functional.RetryAsync
->AsyncFunctional.RetryAsync
Option<Task>
andOption<ValueTask>
awaiters
Funcky.Async
AsyncSequence
This class exposes all of the same factory functions as Sequence
, but for IAsyncEnumerable
:
Return
Successors
Concat
Cycle
CycleRange
FromNullable
RepeatRange
New IAsyncEnumerable
extensions
We've worked hard towards the goal of parity between our extensions for IEnumerable
and IAsyncEnumerable
:
AdjacentGroupBy
AnyOrElse
AverageOrNoneAsync
/MaxOrNoneAsync
/MinOrNoneAsync
Chunk
ConcatToStringAsync
ExclusiveScan
InclusiveScan
Inspect
Interleave
Intersperse
JoinToStringAsync
MaterializeAsync
Memoize
Merge
NoneAsync
PartitionAsync
PowerSet
Sequence
/SequenceAsync
/Traverse
/TraverseAsync
ShuffleAsync
SlidingWindow
Split
Transpose
WhereNotNull
WithIndex
/WithLast
/WithPrevious
/WithFirst
ZipLongest
Funcky.Xunit
- Breaking: The
Is
prefix has been dropped from assertion methods for consistency with
XUnit's naming scheme for assertion methods.
Funcky 2.7.1
Deprecations
Option.None<T>()
: We originally introduced theOption.None<T>
method as a future proof replacement toOption<T>.None
for use in method groups,
because Funcky 3 changesOption<T>.None
to a property. This turned out to be confusing to users especially because both method are always suggested in autocomplete.
Funcky 2.7.0 | Funcky.XUnit 1.0.0 | Funcky.Analyzers 1.1.0
This release is the last non-breaking release for Funcky before 3.0.
Deprecations
EnumerableExtensions.CartesianProduct
will be removed in Funcky 3.- To align our naming with that of the BCL, the
ParseOrNone
methods
that return a type that has a keyword in C#int
,long
, etc. use the name of the BCL type instead.
Example:ParseIntOrNone
becomesParseInt32OrNone
.
The old methods will be removed in Funcky 3. - In preparation for Funcky 3 we deprecated
Option<T>.None
when used as method group. UseOption.None<T>
instead.
New ParseOrNone
extensions
With the help of a source generator we have added a lot of new ParseOrNone methods for various types from the BCL:
- Unsigned integer types
DateOnly
,TimeOnly
Version
- Support for
ReadOnlySpan<T>
as input - ... and more
Convenience for Either
and Result
- Added implicit conversions for
Either
andResult
. - Implement
Inspect
forEither
andResult
. - Added
Partition
forIEnumerable<Either>
andIEnumerable<Result>
. - Added
ToString
onEither
andResult
. - Implement
ToEither
onOption
.
IEnumerable<T>
extensions
AnyOrElse
- Prefix sum:
InclusiveScan
andExclusiveScan
Analyzers
This release adds two new analyzer rules:
- λ1003: Warning when certain methods, such as
Match
are used without argument labels - λ1004: Warning that suggests
.ConcatToString()
over.JoinToString("")
Both of these warnings come with corresponding code fixes.
Funcky.Xunit
- Breaking: Funcky.Xunit now uses the
Funcky
namespace, instead ofFuncky.Xunit
. - Add assertion methods for testing
Either
:FunctionalAssert.IsLeft
andFunctionalAssert.IsRight
.
Funcky 2.6.0 | Funcky.Analyzers 1.0.0
Analyzers
This release comes with a new package Funcky.Analyzers
, which we'll use
to guide users to a better Funcky experience.
New extensions
- Add extensions
DequeueOrNone
andPeekOrNone
onQueue
andConcurrentQueue
. - Add extension
ConcatToString
as an alias forstring.Concat
. - Add overload to
WhereSelect
with no parameter. - Add methods to convert from
Either
toOption
: #439LeftOrNone
: Returns the left value orNone
if the either value was right.RightOrNone
: Returns the right value orNone
if the either value was left.
- Extension functions for
System.Range
to allow the generations ofIEnumerable<T>
s from Range-Syntax:foreach(var i in 1..5) { } // negative numbers are not supported from x in 5..2 from y in 1..3 select (x, y)
Improvements to Sequence
Sequence.Return
now accepts multiple parameters:Sequence.Return(1, 2, 3)
⚠️ Sequence.Generate
has been deprecated in favour of the newly addedSequence.Successors
function
which includes the first element (seed) in the generated sequence.
Improvements to Option
- Add
Option.FromBoolean
to create anOption<T>
from a boolean.
Improvements to Result
The behaviour of the Result.Error
constructor has been changed regarding exceptions
with an already set stack trace. The original stack trace is now preserved.
Previously this resulted in the stacktrace being replaced (.NET < 5.0) or an error (.NET ≥ 5.0).
Improvements to Either
- Add
Either.Flip
to swaps left with right.
Tooling
- Funcky automatically adds global usings for the most important namespaces of funcky
when theFunckyImplicitUsings
property is set. This requires .NET SDK ≥ 6.0 and C# ≥ 10.0. - Funcky now supports trimming for self-contained deployments.
Option<T>
now works with the new System.Text.Json source generation.- The
Funcky
package now supports Source Link and deterministic builds. - The symbols package is now finally working again.
2.5.0
Reader Monad
This release includes the Reader
monad including a bunch of factory methods
and convenience extensions.
public static Reader<Enviroment, IEnumerable<string>> DefaultLayout(IEnumerable<DateTime> month)
=> from colorizedMonthName in ColorizedMonthName(month)
from weekDayLine in WeekDayLine()
from weeksInMonth in month
.GroupBy(GetWeekOfYear)
.Select(FormatWeek)
.Sequence()
select BuildDefaultLayout(colorizedMonthName, weekDayLine, weeksInMonth);
Improved Action
Extensions
Funcky now supports Curry
, Uncurry
and Flip
for Action
s too.
This release also adds the inversion of ActionToUnit
: UnitToAction
More Extensions for IEnumerable<T>
Intersperse
: Adds a given item in between all items of an enumerable.JoinToString
: Alias forstring.Join
.WithPrevious
: Similar toWithFirst/Last/Index
but with the predecessor of each item.ForEach
: Add an overload toForEach
that accepts aUnit
-returningFunc
.
Additional Factory Methods
EitherOrBoth.FromOptions
creates anEitherOrBoth
from two options.Lazy.FromFunc
creates aLazy<T>
from aFunc
.
This is sugar over theLazy<T>
constructor, with the additional benefit of supporting type inference.Lazy.Return
creates aLazy<T>
from a value.
This is sugar over theLazy<T>
constructor, with the additional benefit of supporting type inference.
Documentation Improvements
This release comes with a few small documentation improvements.
Funcky users will now also see the [Pure]
attributes which were previously not emitted.