DeFuncto.Core 1.0.7

dotnet add package DeFuncto.Core --version 1.0.7
NuGet\Install-Package DeFuncto.Core -Version 1.0.7
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DeFuncto.Core" Version="1.0.7" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DeFuncto.Core --version 1.0.7
#r "nuget: DeFuncto.Core, 1.0.7"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DeFuncto.Core as a Cake Addin
#addin nuget:?package=DeFuncto.Core&version=1.0.7

// Install DeFuncto.Core as a Cake Tool
#tool nuget:?package=DeFuncto.Core&version=1.0.7

DeFuncto

Quality Gate Status

Functional library for C#, aiming to keep the minimum data types for ease of maintenance.

Heavily inspired by language-ext, but keeping it closer to F# most used structures and with a much less ambitious scope, making it easier to keep it up to date with the latest versions of the language.

The approach is to let C# developers to dip a toe in the pool of programming in a safer way. It's meant in a pragmatic and simplistic way and nothing mentioned in this documents should be considered a computer science compendium on how to write mathematically correct software, but a cookbook of recipes to move you closer to that.

Wait, mathematically correct software? Is that even possible?

Indeed, you can write software in a way where invalid states are impossible to represent. Most of the mistakes you can make will just not compile. There's even an operating system microkernel that is proven to be correct to the last line.

So, I can achieve this "correctness" thing with DeFuncto?

No. The data types defined here are structs, which by default have an empty constructor (C# does not allow to remove it) that will, with the notable exception of Option and AsyncOption (where it's done in a bit of a hacky way) screw any hope of correctness.

There IS a way around it, and language-ext does it by implementing the concept of Bottom, commonly represented as _|_, and a term I'll avoid using at all costs in this documentation. Again, this library is not aiming to get you to swim in the deep end, but to have a smooth transition into safer practices. By keeping the implementation to the minimum, we can maximize the time invested in documentation, sharing the motivations and value of the practices promoted here as well as common pitfalls and tricks to maximize the gains.

Does this mean that I should just skip this and go straight away to use F#?

If you want and can, yeah, do. This is for those of us that want to make our C# journey a little bit easier.

Functional Programming as a tool: Making your little dev world safer

The goal is not to make a full introduction to functional programming. When you arrived here I assumed that you already have heard of the word Monad (another word that you can forget right away, I'm not using it again) and/or you might be interested in railway oriented programming. This library aims EXACTLY to give you the tools to do railway oriented programming and nothing else. The idea is that you will end up writing the majority of your programs in a DSL fashion. Defining your work as events that should happen instead of how they happen.

Let's say that your services all return AsyncResult<Something, Error>, this is what a login program would look like (for the hardcore FPers: I am aware that this is using old fashioned dependency-injected services) in your session handler:

public AsyncResult<SessionToken, Error> Login(string name, string password) =>
    from user in userService.FindUser(name)
    from authenticatedUser in cryptoService.Validate(user, password)
    from token in sessionService.TryCreateToken(authenticatedUser)
    select token;

What? That's a query, not a method executing logic.

It's not only executing logic, but doing so asynchronously, this chunk of logic is abstracting away:

  • Error handling
  • Tasks

The first method called could look something like this:

public AsyncResult<User, Error> FindUser(string name)
{
    // Some verbosity that you might grow used to, if you don't, you can always make this return
    // Task<Result<User, Error>> and invoke .Async() in the caller.
    return Go().Async();

    async Task<Result<User, Error>> Go()
    {
        var possibleUser = await db.Users.FirstOrDefaultAsync(u => u.Name == name);
        return possibleUser is not null
            ? Result<User, Error>.Ok(user)
            : Result<User, Error>.Error(new Error.EntityNotFound($"User named {name} was not found in the database"));
    }
}

Then, the data type takes care of consuming the user in the next method or circuit breaking in case of an error.

But I don't like magic! I want to see my control flow.

This is not magic, if you change the type returned from FindUser this will stop compiling, wether you return something different than User on the Ok case or something that is not an Error on the Error side. The control flow itself happens internally in the data structure just like it happens in the CLI when you do an if else, except that this is a "conditional" that you have to work REALLY hard to type wrong and have it compile.

It's all about having the compiler hold your hand for as long as possible. Want to know more? Dive into the docs.

Documentation

  1. Fundamentals
  2. DeFuncto.Core
  3. Example of a railway oriented API ASP.NET Core 6
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on DeFuncto.Core:

Package Downloads
DeFuncto.Assertions

Assertions for DeFuncto data types. Assertions fail by throwing an exceptions, which is acknowledged by virtually every popular .NET testing library as a way to fail a test. Not yet localized, assertions fail messages are always in English.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.7 838 12/7/2023
1.0.6 111 12/7/2023
1.0.5 133 12/7/2023
1.0.4 990 1/4/2023
1.0.3 1,133 6/16/2022
1.0.2 677 5/14/2022
1.0.1 630 5/14/2022
1.0.0 666 5/14/2022
0.3.1 697 3/11/2022
0.3.0 1,318 2/9/2022
0.2.15 475 12/31/2021
0.2.14 365 12/24/2021
0.2.13 352 12/16/2021
0.2.12 665 11/5/2021
0.2.11 478 10/26/2021
0.2.10 455 9/23/2021
0.2.9 443 9/23/2021
0.2.8 481 9/20/2021
0.2.7 476 7/28/2021
0.2.6 446 7/22/2021
0.2.5 441 7/16/2021
0.2.4 468 7/16/2021
0.2.3 496 7/13/2021
0.2.2 524 7/9/2021
0.2.1 313 7/8/2021
0.2.0 339 7/8/2021
0.1.4 349 7/8/2021
0.1.3 299 7/8/2021
0.1.2 337 7/6/2021
0.1.1 279 7/6/2021
0.1.0 292 7/5/2021