All Projects → DevTeam → Immutype

DevTeam / Immutype

Licence: MIT license
Immutability is easy!

Programming Languages

C#
18002 projects
kotlin
9241 projects
Batchfile
5799 projects

Projects that are alternatives of or similar to Immutype

php-validation-dsl
A DSL for validating data in a functional fashion
Stars: ✭ 47 (+80.77%)
Mutual labels:  functional, immutability
Chaos
The Chaos Programming Language
Stars: ✭ 171 (+557.69%)
Mutual labels:  functional, immutability
Eslint Plugin Functional
ESLint rules to disable mutation and promote fp in JavaScript and TypeScript.
Stars: ✭ 282 (+984.62%)
Mutual labels:  functional, immutability
Phunctional
⚡️ λ PHP functional library focused on simplicity and performance
Stars: ✭ 243 (+834.62%)
Mutual labels:  functional, immutability
Immutable Tuple
Immutable finite list objects with constant-time equality testing (===) and no memory leaks.
Stars: ✭ 29 (+11.54%)
Mutual labels:  functional, immutability
dotvariant
A type-safe and space-efficient sum type for C# (comparable to discriminated unions in C or C++)
Stars: ✭ 52 (+100%)
Mutual labels:  functional, csharp-sourcegenerator
justuse
Just use() code from anywhere - a functional import alternative with advanced features like inline version checks, autoreload, module globals injection before import and more.
Stars: ✭ 49 (+88.46%)
Mutual labels:  functional
immutable-cursor
👊 Immutable cursors incorporating the Immutable.js interface over a Clojure-inspired atom
Stars: ✭ 58 (+123.08%)
Mutual labels:  immutability
pyfuncol
Functional collections extension functions for Python
Stars: ✭ 32 (+23.08%)
Mutual labels:  functional
ParsecSharp
The faster monadic parser combinator library for C#
Stars: ✭ 23 (-11.54%)
Mutual labels:  functional
dart maybe
No more null check with an dart equivalent of Maybe (Haskel, Elm) / Option (F#).
Stars: ✭ 20 (-23.08%)
Mutual labels:  functional
PartialFunctions.jl
A small package to simplify partial function application
Stars: ✭ 34 (+30.77%)
Mutual labels:  functional
futils
Utilities for generic functional programming
Stars: ✭ 21 (-19.23%)
Mutual labels:  functional
sublime-coconut
Coconut syntax highlighting for Sublime Text and VSCode.
Stars: ✭ 18 (-30.77%)
Mutual labels:  functional
fn
A functional web framework
Stars: ✭ 34 (+30.77%)
Mutual labels:  functional
SAFE-Stack.github.io
Website for Saturn + Azure + Fable + Elmish aka SAFE-Stack
Stars: ✭ 17 (-34.62%)
Mutual labels:  functional
ugo
Simple and expressive toolbox written in Go
Stars: ✭ 27 (+3.85%)
Mutual labels:  functional
swift-di-explorations
Functional DI explorations in Swift
Stars: ✭ 28 (+7.69%)
Mutual labels:  functional
babl
JSON templating on steroids
Stars: ✭ 29 (+11.54%)
Mutual labels:  functional
pipe
Pipe operator for nim.
Stars: ✭ 51 (+96.15%)
Mutual labels:  functional

Immutype

NuGet License

Immutype is .NET code generator creating extension methods for records, structures, and classes marked by the attribute [Immutype.Target] to efficiently operate with instances of these types like with immutable ones.

For instance, for the type Foo for the constructor parameter values of type IEnumerable<int> following extension methods are generated:

  • Foo WithValues(this Foo it, params int[] values) - to replace values by the new ones using a method with variable number of arguments
  • Foo WithValues(this Foo it, IEnumerable<int> values) - to replace values by the new ones
  • Foo AddValues(this Foo it, params int[] values) - to add values using a method with variable number of arguments
  • Foo AddValues(this Foo it, IEnumerable<int> values) - to add values
  • Foo RemoveValues(this Foo it, params int[] values) - to remove values using a method with variable number of arguments
  • Foo RemoveValues(this Foo it, IEnumerable<int> values) - to remove values
  • Foo ClearValues(this Foo it) - to clear all values

For the type Foo for the constructor parameter value of other types, like int, with default value 99 following extension methods are generated:

  • Foo WithValue(this Foo it, int value) - to replace a value by the new one
  • Foo WithDefaultValue(this Foo it) - to replace a value by the default value 99

The extensions methods above are generating automatically for each public or internal type, like Foo marked by the attribute [Immutype.Target] in the static class named as FooExtensions. This generated class FooExtensions is static, has the same accessibility level and the same namespace like a target class Foo. Each generated static extension method has two attributes:

  • [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] - to improve performance
  • [Pure] - to indicate that this method is pure, that is, it does not make any visible state changes

Immutype supports nullable reference and value types and the following list of enumerable types:

  • Arrays
  • IEnumerable<T>
  • List<T>
  • IList<T>
  • IReadOnlyCollection<T>
  • IReadOnlyList<T>
  • ICollection<T>
  • HashSet<T>
  • ISet<T>
  • Queue<T>
  • Stack<T>
  • IReadOnlyCollection<T>
  • IReadOnlyList<T>
  • IReadOnlySet<T>
  • ImmutableList<T>
  • IImmutableList<T>
  • ImmutableArray<T>
  • ImmutableQueue<T>
  • IImmutableQueue<T>
  • ImmutableStack<T>
  • IImmutableStack<T>

Immutype supports IIncrementalGenerator as well as ISourceGenerator so it works quite effective.

NuGet package

NuGet

  • Package Manager

    Install-Package Immutype
    
  • .NET CLI

    dotnet add package Immutype
    

Development environment requirements

Supported frameworks

Usage Scenarios

Sample scenario

[Immutype.Target]
internal record Person(
    string Name,
    bool HasPassport = true,
    int Age = 0,
    ImmutableArray<Person> Friends = default);

public class SampleScenario
{
    public void Run()
    {
        var john = new Person("John", false, 15)
            .AddFriends(
                new Person("David").WithAge(16),
                new Person("James").WithAge(17)
                    .WithFriends(new Person("Tyler").WithAge(16)));
            
        john.Friends.Length.ShouldBe(2);

        john = john.WithAge(16).WithDefaultHasPassport();
        john.Age.ShouldBe(16);
        john.HasPassport.ShouldBeTrue();

        john = john.AddFriends(
            new Person("Daniel").WithAge(17),
            new Person("Sophia").WithAge(18));
        
        john.Friends.Length.ShouldBe(4);
            
        john = john.RemoveFriends(new Person("David").WithAge(16));

        john.Friends.Length.ShouldBe(3);
    }
}

Array

[Immutype.Target]
internal readonly record struct Person(string Name, int Age = 0, params Person[] Friends);

public class Array
{ 
    public void Run()
    {
        var john = new Person("John")
            .WithAge(15)
            .AddFriends(new Person("David").WithAge(16))
            .AddFriends(
                new Person("James"),
                new Person("Daniel").WithAge(17));
        
        john.Friends.Length.ShouldBe(3);
    }
}

Applying defaults

[Immutype.Target]
internal readonly record struct Person(string Name = "John", int Age = 17);

public class ApplyingDefaults
{
    public void Run()
    {
        var john = new Person("David", 15)
            .WithDefaultAge()
            .WithDefaultName();
        
        john.Name.ShouldBe("John");
        john.Age.ShouldBe(17);
    }
}

Clearing

[Immutype.Target]
internal readonly record struct Person(
    string Name,
    int Age = 0,
    params Person[] Friends);

public class Clearing
{
    public void Run()
    {
        var john = new Person("John",15, new Person("David").WithAge(16))
            .AddFriends(new Person("James"));

        john = john.ClearFriends();
        
        john.Friends.Length.ShouldBe(0);
    }
}

Immutable collection

[Immutype.Target]
internal readonly struct Person
{
    public readonly string Name;
    public readonly int Age;
    public readonly IImmutableList<Person> Friends;

    public Person(
        string name,
        int age = 0,
        IImmutableList<Person>? friends = default)
    {
        Name = name;
        Age = age;
        Friends = friends ?? ImmutableList<Person>.Empty;
    }
};

public class ImmutableCollection
{
    public void Run()
    {
        var john = new Person("John",15)
            .WithFriends(
                new Person("David").WithAge(16),
                new Person("James").WithAge(17))
            .AddFriends(
                new Person("David").WithAge(22));
        
        john.Friends.Count.ShouldBe(3);
    }
}

Removing

[Immutype.Target]
internal readonly record struct Person(
    string Name,
    int Age = 0,
    params Person[] Friends);

public class Removing
{
    public void Run()
    {
        var john = new Person("John",15, new Person("David").WithAge(16))
            .AddFriends(new Person("James"));

        john = john.RemoveFriends(new Person("James"));
        
        john.Friends.Length.ShouldBe(1);
    }
}

Generic types

It is possible to use generic types including any generic constraints.

[Immutype.Target]
internal record Person<TAge>(string Name, TAge Age = default, IEnumerable<Person<TAge>>? Friends = default) 
    where TAge : struct;

public class GenericTypes
{ 
    public void Run()
    {
        var john = new Person<int>("John")
            .WithAge(15)
            .WithFriends(new Person<int>("David").WithAge(16))
            .AddFriends(
                new Person<int>("James"),
                new Person<int>("Daniel").WithAge(17));
        
        john.Friends?.Count().ShouldBe(3);
    }
}

Nullable collection

[Immutype.Target]
internal record Person(
    string Name,
    int? Age = default,
    ICollection<Person>? Friends = default);

public class NullableCollection
{
    public void Run()
    {
        var john = new Person("John",15)
            .AddFriends(
                new Person("David").WithAge(16),
                new Person("James").WithAge(17)
                    .WithFriends(new Person("Tyler").WithAge(16)));
        
        john.Friends?.Count.ShouldBe(2);
    }
}

Set

[Immutype.Target]
internal record Person(
    string Name,
    int Age = 0,
    ISet<Person>? Friends = default);

public class Set
{
    public void Run()
    {
        var john = new Person("John",15)
            .AddFriends(
                new Person("David").WithAge(16),
                new Person("David").WithAge(16),
                new Person("James").WithAge(17)
                    .WithFriends(new Person("Tyler").WithAge(16)));
        
        john.Friends?.Count.ShouldBe(2);
    }
}

Record with constructor

[Immutype.Target]
internal record Person
{
    public Person(
        string name,
        int? age = default,
        ICollection<Person>? friends = default)
    {
        Name = name;
        Age = age;
        Friends = friends;
    }

    public string Name { get; }

    public int? Age { get; }

    public ICollection<Person>? Friends { get; }

    public void Deconstruct(
        out string name,
        out int? age,
        out ICollection<Person>? friends)
    {
        name = Name;
        age = Age;
        friends = Friends;
    }
}

public class RecordWithConstructor
{
    public void Run()
    {
        var john = new Person("John",15)
            .WithFriends(
                new Person("David").WithAge(16),
                new Person("James").WithAge(17)
                    .WithFriends(new Person("Tyler").WithAge(16)));
        
        john.Friends?.Count.ShouldBe(2);
    }
}

Explicit constructor choice

[Immutype.Target]
internal readonly struct Person
{
    public readonly string Name;
    public readonly int Age;
    public readonly IImmutableList<Person> Friends;

    // You can explicitly select a constructor by marking it with the [Immutype.Target] attribute
    [Immutype.Target]
    public Person(
        string name,
        int age = 0,
        IImmutableList<Person>? friends = default)
    {
        Name = name;
        Age = age;
        Friends = friends ?? ImmutableList<Person>.Empty;
    }
    
    public Person(
        string name,
        int age,
        IImmutableList<Person>? friends,
        int someArg = 99)
    {
        Name = name;
        Age = age;
        Friends = friends ?? ImmutableList<Person>.Empty;
    }
};

public class ExplicitConstructorChoice
{
    public void Run()
    {
        var john = new Person("John",15)
            .WithFriends(
                new Person("David").WithAge(16),
                new Person("James").WithAge(17))
            .AddFriends(
                new Person("David").WithAge(22));
        
        john.Friends.Count.ShouldBe(3);
    }
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].