Object-Oriented .Net primitives. A port of cactoos library by Yegor Bugayenko, author of the "Elegant Objects" books.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github rename iText.IsBlank to IsWhitespace Mar 16, 2018
tools ci: pin cake version Mar 6, 2018
Yaapii.Atoms.sln feat: add opencover reports Jan 11, 2018


Build status codecov PRs Welcome Commitizen friendly EO principles respected here


Object-Oriented Primitives for .NET. This is a .NET port of the java library Cactoos by Yegor Bugayenko.

It follows all the rules suggested in the two "Elegant Objects" books.

Table Of Contents


The interfaces are:

//Function with input and output
public interface IFunc<In, Out>
    Out Invoke(In input);

//Function with output only
public interface IFunc<Out>
    Out Invoke();

//Function with two inputs and one output
public interface IFunc<In1, In2, Out>
    Out Invoke(In1 input1, In2 input2);

//Function with input only
public interface IAction<In>
    void Invoke(In input);

Execute functions

var i = new FuncOf<int, int>(
                (number) => number++
            ).Invoke(1); //i will be 2

Cache function output

var url = new Url("https://www.google.de");
var f = new StickyFunc<Url, IText>((u) =>
            new TextOf(
                new InputOf(u))

var html = f.Invoke(); //will load the page content from the web
var html = f.Invoke(); //will load the page content from internal cache

Retry a function

new RetryFunc<int, int>(
    input =>
        if (new Random().NextDouble() > input)
            throw new ArgumentException("May happen");
        return 0;
).Invoke(0.3d); //will try 100.000 times to get a random number under 0.3

Repeat a function

var count = 0;
new RepeatedFunc<int, int>(
        input => input++,
    ).Invoke(count); //will return 3

Use a fallback if a function fails

new FuncWithFallback<string, string>(
    name =>
        throw new Exception("Failure");
    ex => "Never mind, " + name
).Invoke("Miro"); //will be "Never mind, Miro"
  • And more

IO Input / Output

The IInput and IOutput interfaces:

public interface IInput
    Stream Stream();       

public interface IOutput
    Stream Stream();

Input Stream of a file

new InputOf(
        new Uri(@"file:///c:\secret-content-inside.txt")
    ).Stream(); //returns a readable stream of the file

Output Stream to a file

new OutputTo(
        new Uri(@"file:///c:\secret-content-inside.txt")
    ).Stream(); //returns a readable stream of the file

Output Stream of Console

new ConsoleOutput().Stream(); //Default console output
new ConsoleErrorOutput().Stream(); //Console error output

Read file content as string

var fileContent = 
    new TextOf(
        new InputOf(
                new Uri(@"file:///c:\secret-content-inside.txt")
    ).AsString(); //reads the content and gives it as text

Read Url page as string

new TextOf(
    new InputOf(
        new Url("https://www.google.de"))
).AsString(); //gives the content html of the google start page

Read a file and use a fallback if fails

new TextOf(
    new InputWithFallback(
        new InputOf(
            new Uri(Path.GetFullPath("/this-file-does-not-exist.txt")) //file to read
        new InputOf(new TextOf("Alternative text!")) //fallback to use
    ).AsString(); //will be "Alternative Text!"

Get the length of a file

long length =
    new LengthOf(
        new InputOf(
                new Uri(@"file:///c:\great-content-inside.txt")
            )).Value(); //will be the number of bytes in the file
  • Write to file, url, byte arrays, streams

Copy all you are reading from a Stream to a output stream

new LengthOf(
    new TeeInput(
        "Welcome to the world of c:!", 
        new OutputTo(new Uri(@"file:///c:\greeting.txt")))
    ).Value();  //will write "Welcome to the world of c:!" to the file c:\greeting.txt. 
                //This happens because TeeInput puts every byte that is read to the specified output. 
                //When calling Value(), every byte is read to count the content.

Copy input/output 1:1 while reading or writing

var inPath = Path.GetFullPath(@"file:///c:\input-file.txt");
var outPath = Path.GetFullPath(@"file:///c:\output-file.txt");

new LengthOf(
    new TeeInput(
        new InputOf(new Uri(inPath)),
        new OutputTo(new Uri(outPath))
    )).Value(); //since LengthOf will read all the content when calling Value(), all that has been read will be copied to the output path.

//Alternative: Copy to Console output
new LengthOf(
    new TeeInput(
        new InputOf(new Uri(inPath)),
        new ConsoleOutput()
    )).Value(); //will dump the read content to output

Cache what you have read

    new TextOf(
        new StickyInput(
            new InputOf(new Url("http://www.google.de"))));

var html1 = input.AsString(); //will read the url from the web
var html2 = input.AsString(); //will return from the cache


Lists use the IEnumerable and IEnumerator interfaces from C#:

public interface IEnumerable<out T> : IEnumerable
    IEnumerator<T> GetEnumerator();

public interface IEnumerator<out T> : IEnumerator, IDisposable
    T Current { get; }

Filter lists

new Filtered<string>(
    new List<string>() { "A", "B", "C" },
    (input) => input != "B"); //will be a list with "A" and "C" inside

Get an item from a list

new ItemAt<int>(
        new EnumerableOf<int>(1, 2, 3),
    ).Value(); //will be 3 (Zero based)

//To get the first item simply do not specify a position:
new ItemAt<int>(
        new EnumerableOf<int>(1, 2, 3)
    ).Value(); //will be 1

//To get an item with a fallback if it isn't there:
String fallback = "fallback";
                new ItemAt<string>(
                    new EnumerableOf<string>(), //empty list,
                    12, //position 12 which does not exist
                ).Value(); //will be "fallback"

Sort lists

//Default sorting is forward
new Sorted<int>(
    new EnumerableOf<int>(3, 2, 10, 44, -6, 0)
); //items will be sorted to -6, 0, 2, 3, 10, 44

//Use another comparator for sorting
new Sorted<string>(
    IReverseComparer<string>.Default, //comparator is from C#.NET library
    new EnumerableOf<string>(
        "a", "c", "hello", "dude", "Friend"
); //will be sorted to hello, Friend, dude, c, a

Count items in lists

var l = new LengthOf<int>(
            new EnumerableOf<int>(1, 2, 3, 4, 5)
        ).Value(); //will be 5

Map items in a list to another type

IText greeting = 
    new ItemAt<IText>(
        new Mapped<String, IText>(
            new EnumerableOf<string>("hello", "world", "damn"),
            input => new UpperText(new TextOf(input)) //is applied to every item and will make a uppertext of it
    ).Value(); //will be "HELLO"
// Mapping items of a list to another type using index of items
new Mapped<string,string>(
    new List<string>() {"One", "Two", Three"},
    (input, index) => $"{input}={index+1}");
// Returns a IEnumerable<string> with Content {"One=1", "Two=2", Three=3"}

Create cycling lists

//here is a list with 3 items and you call the 7th item. The cycled list will not fail but start over when it reaches the end.
new ItemAt<string>(
    new Cycled<string>( //make a cycled list of the enumerable with 3 items
        new EnumerableOf<string>(
            "one", "two", "three"
    ).Value(); //will be "two"

Join lists together

new LengthOf(
    new Joined<string>(
        new EnumerableOf<string>("hello", "world", "Miro"),
        new EnumerableOf<string>("how", "are", "you"),
        new EnumerableOf<string>("what's", "up")
).Value(); //will be 8

Limit lists

new SumOfInts(
    new Limited<int>(
        new EnumerableOf<int>(0, 1, 2, 3, 4),
    )).Value(); //will be 3 (0 + 1 + 2)

Cache list contents

//this snippet has an endless list, which then is limited to the size. Every time someone calls the list, size increases and the list would grow. But StickyEnumerable prevents that and always returns the same list.
int size = 2;
var list =
   new StickyEnumerable<int>(
       new Limited<int>(
           new Endless<int>(1),
           new ScalarOf<int>(() => Interlocked.Increment(ref size))

new LengthOf(list).Value(); //will be 2
new LengthOf(list).Value(); //will be 2
  • and more


The IScalar interface looks like this:

public interface IScalar<T>
    T Value();

A scalar is an object which can encapsulate objects and functions that return objects. It enables you to let a function appear as its return value. This is very useful to keep constructors code-free but also keep your overall object count low.

Also, scalars can be used to perform logical operations like And, Or, Not and more on function results or objects.

Encapsulate objects

var sc1 = new ScalarOf<string>("this brave string");
string str = sc.Value(); //returns the string

var sc2 = new ScalarOf<IEnumerable<int>>(
            new EnumerableOf<int>(1,2,3,4,5));
IEnumerable<int> lst = sc2.Value(); //returns the list

Encapsulate functions

var sc =
    new ScalarOf<string>(
        () =>
        new TextOf(
            new InputOf(
                new Url("http://www.ars-technica.com")

string html = sc.Value(); //will fetch the html from the url and return it as a string

Cache function results

var sc =
   new StickyScalar<string>(
       () =>
       new TextOf(
           new InputOf(
               new Url("http://www.ars-technica.com")

string html = sc.Value(); //will fetch the html from the url and return it as a string
string html2 = sc.Value(); //will return the html from the cache

Logical And

var result = 
    new And<True>(
        () => true,
        () => false,
        () => true).Value(); //will be false

var number = 3;
new And<True>(
    () => true, //function that returns true
    () => number == 4 //function that returns false
).Value(); //will be false

//you can also pass scalars into AND, and more.

Logical ternary

new Ternary<bool, int>(
    new True(), //condition is true
    6, //if true
    16 //if false
).Value(); //will be 6

new Ternary<int, int>(
    5, //input to test
    input => input > 3, //condition
    input => input = 8, //return if condition true
    input => input = 2 //return if condition false
).Value(); //will be 8

And more...

  • Negative
  • Max
  • Min
  • Or


The IText interface looks like this:

public interface IText : IEquatable<IText>
    String AsString();

Transform text

//Lower a text
new LowerText(
    new TextOf("HelLo!")).AsString(); //will be "hello!"

//upper a text
new UpperText(
    new TextOf("Hello!")).AsString(); //will be "HELLO!"

Reverse text

new ReversedText(
    new TextOf("Hello!")).AsString(); //"!olleH"

Trim text

new TrimmedText(
    new TextOf("  Hello!   \t ")
    ).AsString(); // "Hello!"

new TrimmedLeftText(
    new TextOf("  Hello!   \t ")
    ).AsString(); // "Hello!   \t "

new TrimmedRightText(
    new TextOf("  Hello!   \t ")
    ).AsString(); // "  Hello!"

Split text

IEnumerable<Text> splitted = 
    new SplitText(
        "Hello world!", "\\s+"

Replace text

new ReplacedText(
    new TextOf("Hello!"),
    "ello",     // what to replace
    "i"         // replacement
).AsString();   // "Hi!"

Join texts

new JoinedText(
    " ", 
).AsString();// "hello world"

Format texts with arguments

new FormattedText(
        "{0} Formatted {1}", 1, "text"
    ).AsString(); // "1 Formatted text"

Convert from and to text

//text from a string with encoding
var content = "Greetings, Mr.Freeman!";
new TextOf(

//text from a input with default encoding
var content = "Hello, my precious coding friend! with default charset";
new TextOf(
    new InputOf(content)

//text from a StringReader
String source = "Hello, Dude!";
new TextOf(
    new StringReader(source),

//text from a char array
new TextOf(
    'O', ' ', 'q', 'u', 'e', ' ', 's', 'e', 'r', 'a',
    ' ', 'q', 'u', 'e', ' ', 's', 'e', 'r', 'a'

//text from a byte array
byte[] bytes = new byte[] { (byte)0xCA, (byte)0xFE };
new TextOf(bytes);

//text from a StringBuilder
String starts = "Name it, ";
String ends = "then it exists!";
        new TextOf(
            new StringBuilder(starts).Append(ends)

//text from an exception
new TextOf(
    new IOException("It doesn't work at all")

LinQ Analogy

Standard Query Operators

LinQ Yaapii.Atoms
Aggregate Not available yet
All And<T>
Any Or<T>
var arr = new int[]{ 1, 2, 3, 4 }; 
var enumerable = new EnumerableOf<int>(arr);
var avg = new AvgOf(1, 2, 3, 4).AsFloat(); //avg = 2.5
Cast Not available yet
var joined = new Joined<string>(
  new EnumerableOf<string>("dies", "ist"),
  new EnumerableOf<string>("ein", "Test")
).Value(); //joined = {"dies", "ist", "ein", "Test"}
var b = new Contains<string>(
  new EnumerableOf<string>("Hello", "my", "cat", "is", "missing"),
  (str) => str == "cat"
).Value()); //b = true
var length = new LengthOf<int>(
  new EnumerableOf<int>(1, 2, 3, 4, 5)
).Value(); //length will be 5
DefaultIfEmpty Not available yet
var dis = new Distinct<int>(
  new EnumerableOf<int>(1, 2, 3),
  new EnumerableOf<int>(10, 2, 30)
).Value() // dis = {1, 2, 3, 10, 30}
//actual with bug
var itm = new ItemAt<int>(
  new EnumerableOf<int>(0,2,5),
).Value() //itm = 2
var itm = new ItemAt<string>(
  new EnumerableOf<string>(),
).Value() // itm = "fallback"
new EnmuerableOf<int>()
Except Not available yet
var list = new EnumerableO<int>(1, 2, 3);
 var first = new ItemAt<int>(list).Value();
 // first = 1
var itm = new ItemAt<string>(
  new EnumerableOf<string>(),
).Value() // itm = "fallback"
var list = new List[];
new Each<int>(
  (i) => lst[i] = i,
).Invoke(); //eachlist = {0,1,2}
GroupBy Not available yet
GroupJoin Not available yet
Intersect Not available yet
Join Not available yet
var last = new ItemAt<int>(
  new Reversed<int>(
    new EnumerableOf(5, 6 ,7 ,8)
).Value() // last = 8
var itm = new ItemAt<string>(
  new Reversed<string>(
    new EnumerableOf<string>()
).Value() // itm = "fallback"
LongCount Not available yet*
var max = new MaxOf(22, 2.5, 35.8).AsDouble(); //max = 35.8; .AsInt() = 35
var max = new MaxOf(22, 2.5, 35.8).AsDouble(); //max = 2.5; .AsInt() = 2
OfType Not available yet
var sorted = new Sorted<int>(
  new EnumerableOf<int>(3, 2, 10, 44, -6, 0)
) //sorted = {-6, 0, 2, 3, 10, 44
var sorted = new Sorted<string>(
  new EnumerableOf<string>("a", "c", "hello", "dude", "Friend")
) //sorted = {hello, Friend, dude, c, a}
Range Not available yet
var repeated = new Repeated<int>(10,5) // repeated = {10, 10, 10, 10, 10}
 var reversed = new Reversed<int>(EnumerableOf(2,3,4)); //reversed = {4,3,2}
var selected = Mapped<string,string>(
  new List<string>() {"One", "Two", Three"},
  (tStr, index) => $"{tStr}={index+1}"
)// selected = {"One=1", "Two=2", Three=3"}
SelectMany Not available yet
SequenceEqual Not available yet
Single Not available yet
SingleOrDefault Not available yet
var skipped = new Skipped<string>(
  new EnumerableOf<string>("one", "two", "three", "four"),
) // skipped = {three, four}
SkipWhile Not available yet
var sum = new SumOf(
  1.5F, 2.5F, 3.5F
).AsFloat() //sum = 7.5
var lmt = new Limited<int>(
  new EnumerableOf<int>(0, 1, 2, 3, 4),
)//lmt = {0, 1, 2}
TakeWhile Not available yet
ThenBy Not available yet
ThenByDescending Not available yet
ToArray Not available yet
var dic = new MapOf(
  new Enumerable<KeyValuePair<string,string>>(
    new KyValuePair<string,string>("key","value"),
    new KyValuePair<string,string>("key2", "value2")
) // dic = {{key, value}{key2, value2}}
var list = new CollectionOf<int>(
  new EnumerableOf<int>(1,2,3,4)
ToLookup Not available yet
var enu = new Distinct<int>(
  new Joined<int>(
    new EnumerableOf<int>(1,2,3,4),
    new EnumerableOf<int>(3,4,5,6)
).Value(); //enu ={1,2,3,4,5,6}
var newFiltered = new Filtered<string>(
  new List<string>() { "A", "B", "C" },
  (input) => input != "B"
); //newFiltered contains A & C
Zip Not available yet