GithubHelp home page GithubHelp logo

ja-rek / suckless.assert Goto Github PK

View Code? Open in Web Editor NEW
2.0 1.0 1.0 90 KB

A library for expressing side effects by creating a contract for beginning value (arguments). This technique can be referred to as ”design by contract,” ”defense programming,” or ”guard methods”. The Suckless Assert is much faster and simpler than other similar libraries that support fluent API and can get a field/property name by the lambda expression.

License: MIT License

C# 100.00%

suckless.assert's Introduction

Suckless Assert

Build Status Build status Build status

Library for expressing side effects by creating a contract for beginning value (arguments). This technique can be referred to as "design by contract", "defense programming" or "guard methods". The Suckless Assert is much faster and simpler than other similar libraries that support fluent API and can get field/property name by the lambda expression.

Instalation

CLI Command
PM Install-Package Suckless.Assert
dotnet add package Suckless.Assert
paket add Suckless.Assert

After that use: using static Suckless.Asserts.Assertions;

Requirements

Netstandard2.0, C# 7.2 or higher.

Compare The API

The Suckless Assert:

    Assert(anyValue).NotEmpty();

Others:

    Guard.Argument(anyValue).NotNull().NotEmpty();
    Guard.That(anyValue).IsNotNull().IsNotEmpty();

With lambda.

    Assert(() => anyValue).NotEmpty();

Others:

    Guard.That(() => anyValue).IsNotNull().IsNotEmpty();
    anyValue.ThrowIf(() => anyValue).Null().OrIf.Empty();

The API Conception

The Suckless Assert accepted the conventions "Always assert not null first". For example when you "assert" that any field/property is not empty then the value cannot be null as well. Wherefore in this situation, it will throw an ArgumentNullException or ArgumentOutOfRange. So you don't need to "assert not null" explicitly. This is avoiding strange behaves like throwing any internal exception of the library like ApplicationException("If you want to use extension method NotEmpty() the argument of assertion cannot be null") which have just to push you to assert first "not null". For example Assert(value).NotNul().NotEmpty();.

    Assert(anyValue).NotEmpty();
    //Throws ArguemntOutOfRange with the message "The value: string cannot be empty."
    //or ArgumentNullExcpetion with the message "The value: string cannot be null."

The name of an argument you can get by use lambda or string parameter.

    Assert(() => name).NotEmpty();
    Assert(anyValue, nameof(name)).NotEmpty();
    //Now it will generate message like that: "The name: string cannot be empty."

Allow null.

    AllowNull.Assert(anyValue).NotEmpty();
    //Not throwing ArgumentNullException.

Change message.

    Assert(anyValue).NotEmpty("Custom message");

Assign value straight to the field.

    var name = Assert(anyValue).NotEmpty().Value;

Fluent API

    Assert(name).Count(5,20).NotEqual("My Name");

If you want to assert only "not null" use the optional method or consider option/maybe type instead of.

    AssertNotNull(anyValue);

Compare Performance

Method Mean Error StdDev
DawnGuard 15.146 ns 0.3262 ns 0.4354 ns
CodeGuardAssert 37.658 ns 0.9533 ns 2.7045 ns
SucklessAssert 5.432 ns 0.0303 ns 0.0269 ns
Method Mean Error StdDev
DawnGuardValueType 4.837 ns 0.0206 ns 0.0161 ns
CodeGuardAssertValueType 30.061 ns 0.0766 ns 0.0640 ns
SucklessAssertValueType 1.883 ns 0.0088 ns 0.0073 ns
Method Mean Error StdDev
DawnGuardLambda 150,222.522 ns 546.0984 ns 510.8208 ns
ArgumentAssertionsLambda 14,605.021 ns 35.5085 ns 27.7227 ns
CodeGuardLambda 1,648.504 ns 6.9454 ns 6.4968 ns
SucklessAssertLambda 1,502.484 ns 3.0418 ns 2.8453 ns
Method Mean Error StdDev
CodeGuardAssertLambdaNestedProperty 183,439.747 ns 631.5918 ns 590.7913 ns
SucklessAssertLambdaNestedProperty 3,539.126 ns 7.6255 ns 6.7598 ns

Why you should care about it.? Because the "assertions" can be everywhere and you should be aware of performance issues that it can cause. Of Course, if the performance is important for you.

Why It's Faster

Let's look to the IL code of Metadata<TValue> and check what realy is going on there.

.class public sequential ansi sealed beforefieldinit Suckless.Asserts.Metadata`1<TValue>
        extends [netstandard]System.ValueType
{
        .custom instance void System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
                01 00 00 00
        )
        .custom instance void [netstandard]System.ObsoleteAttribute::.ctor(string, bool) = (
                01 00 52 54 79 70 65 73 20 77 69 74 68 20 65 6d
                62 65 64 64 65 64 20 72 65 66 65 72 65 6e 63 65
                73 20 61 72 65 20 6e 6f 74 20 73 75 70 70 6f 72
                74 65 64 20 69 6e 20 74 68 69 73 20 76 65 72 73
                69 6f 6e 20 6f 66 20 79 6f 75 72 20 63 6f 6d 70
                69 6c 65 72 2e 01 00 00
        )
        .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
                01 00 00 00
        )

This is what is intresting for as.

.custom instance void System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
                01 00 00 00
        )

The attribute of a compiler indicates that a structure is "byref-like". So it means that the compiler just tells the CLR that this is the ref struct which can live only on the stack it will never place on a heap. Thanks to this, we reduce the pressure of the GC.

Hence, a metadata structure is passed by reference to the extension methods, it's mean that the value will be not copied in memory.

    public static partial class Assertions
    {
        public static ref readonly Metadata<string> Empty(in this Metadata<string> metadata, string message = null)
        {

The next move was avoiding compiling an expression.

    Get(Expression<Func<TValue>> expression)
    {
        var value = expression.Compile().Invoke();
    }

Instead, I use "ConstantExpression" which is more tricky but gives big performance boost. MetadataFactory

The performance boost you can see here:

Method Mean Error StdDev
CompileAndInvokeExpresssion 159,328.0012 ns 2,888.5969 ns 2,701.9953 ns
ConstantExpression 1,418.8669 ns 21.1379 ns 19.7724 ns

The last go was to minimize the number of instances and generic types. The code is a compromise between principle DRY and writing "fast code". So just keep it in mind.

How To Add Own Assert

Just write your own extension method like that:

    public static ref readonly Metadata<int> LuckyNumber(in this Metadata<int> metadata)
    {
        if (metadata.Value != 69)
        {
            throw Exception($"The {metadata.Name} contains {metadata.Value} but should contain 69.");
        }

        return ref metadata;
    }

suckless.assert's People

Contributors

ja-rek avatar

Stargazers

Stanislav Trifan avatar Justin Hachemeister avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.