Architecture – Victor Laskin's Blog http://vitiy.info Programming, architecture and design (С++, QT, .Net/WPF, Android, iOS, NoSQL, distributed systems, mobile development, image processing, etc...) Fri, 06 May 2016 07:05:26 +0000 en-US hourly 1 https://wordpress.org/?v=5.4.2 Encapsulation of asynchronous behaviour in distributed system of scripted autotests http://vitiy.info/encapsulation-of-asynchronous-behaviour-in-distributed-system-of-scripted-autotests/ http://vitiy.info/encapsulation-of-asynchronous-behaviour-in-distributed-system-of-scripted-autotests/#comments Fri, 06 May 2016 07:01:02 +0000 http://vitiy.info/?p=677 This is an example how to create continuation-like monadic behaviour in C++11 (encapsulate async execution) which is used for specific example: writing asynchronous scripts for system of distributed autotests.

Async scenarions for distributed autotests

I needed to add autotests into continuous integration of client-side multiplatform product. Basic way to build autotesting system is to grab one of well-known frameworks (especially if we are talking about web solutions) and test product locally. Local testing environment simulates clicks buttons inside UI and gets the results right away. This is simple and good way except the case when you have truly cross-platform solution (win, mac, web, iOS, android, etc), custom rich UI framework and you want to perform tests on various kinds of systems at same time.

So I came up with remote distributed scheme for autotests. And inside this post there are some ways to make this scheme shine.

This post contains 3 main points:

  1. what is distributed system of autotests and why the one would need it (advantages / disadvantages)
  2. how to implement asynchronous scenarios of distributed autotests using continuation monadic style in C++11/14 (how to encapsulate asynchronous execution and do this the most compact way)
  3. how to integrate ChaiScript scripting into such system to make it more flexible

PART 1 – DISTRIBUTED SYSTEM OF AUTOTESTS

If you are interested only in ways of encapsulation of async interfaces in C++ you could skip this chapter and move on to PART 2.

Let’s build server which will control clients via sending events through separate web-socket connection. It is like performing tests of car when you use remote control. Next diagram shows main structure differences:

Distributed scheme for autotesting

Let’s discuss advantages at first:

Cover a lot of devices

In such scheme we could launch clients at any device (as we don’t need to setup local testing environment any more). Also it’s possible to run tests on clients under debugger and see what happens.

Write once – run on device park

We could launch tests on nightly builds using all available range of devices. When new test is written it will work on all devices (except case when test uses some platform specific aspect like push notifications, etc). When new device is added into the zoo there is almost zero overhead on setup of testing environment.

Analyze results

Compare test runs

We could export statistics from all tests into one server side storage and analyze all variety of test cases inside one analytical system. In my case it’s ElasticSearch + Kibana, but this could be any tools/storages you like to work with. Also the one could use autotests as profiling system: you could compare performance results measured during same tests (using different devices or different versions of target application).

Fast write, Fast run

Once again you need to write test only once to support all variety of platforms, operating systems, devices, etc. This is huge gain in time. Also when there is no need in custom setup of testing environment on device we could analyse more cases or spend more time writing new tests. Developers could run tests right on their builds without no need to upload them into some testing environment.

Finally – More stable CI

Performing tests on large zoo of devices, analysing not only green lights from tests but fine performance measurements, increased speed of test development and autotests integration – all this leads to more stable continuous integration.

Disadvantages

Are there any disadvantages? First one is that you have to spend some time implementing such system. There are no boxed solutions as far as I know. But actually this is not the main problem. On application side it’s enough to create simple interface for accepting external commands received through socket. It could be only UI control commands (like click at x,y coords or is this element visible requests), or it could be some complex interaction with inner application model. Any way this is simple request-answer interface, which could be extended with periodic performance reports, sending last chains of inner events or even passing crash log reports to server.

What really is the problem: how we should write tests when test target is separated from test itself – how to write asynchronious tests?

For example, instead of general way when you deal with local tests and need to push some interface button you just need to call some method like button1.click() and thats all. But when you are dealing with distributed scheme you need to send some message to client – “push button1” and wait for answer. And we need to take into account that client might not even answer or our ui button might be hidden already and message could fail to execute.

finite state machine

To solve this first idea is to implement test on server side as finite state machine (link). Let’s assume test has a state which could be represented as some simple enumeration (or item from some set). Each state has listeners for client’s answers. And by each async operation we jump from one state to another. For example, for “click button” case we have two states – first: we send message and switch to second state, second: if we receive answer that button was successfully clicked we move on to next action.

If we have simple test of linear continuous actions we could just keep state as int and increment it performing each ‘step’ from current state to next one.

STEP("start",
      send("tests.ui.click element", {{"id", bLogin}});
      state++;
     );
 
STEP("tests.ui.click element",
     if (answer->isOk())
     {
         state++;
         // .... next action here ....
     } else 
     { 
         // try something else
     }
     );

Everything could be implemented in such manner, but the problem is that if your tests are not so trivial the code will become unreadable mess of state jumps. Also there will be a problem to extract functionality into separate methods because state logic overlaps each other – finishing handler for last action inside some function block should move on to next state which is outside of scope.  You might look for ways to organise this structure and solve such ‘overlap’ problems but there is a better solution to solve this at once.

PART 2 – C++14 CORE FOR WRITING ASYNCHRONOUS TESTS

IT’S POSSIBLE TO WRITE ASYNCHRONOUS CODE IN SYNCHRONIOUS MANNER 

In ideal world I just want to keep writing the code of my test using old ‘synchronous‘ way as it is more simple, readable, etc. But I want it to work async way. To achieve this we need all power of C++11/14 because this will look like continuation monad in C++. What are continuations you could read here.

I want to write code using general sequential notation – but implicitly this code will produce a lot of functional handlers and totally encapsulate whole state machine inside. Yes, this is possible using modern C++!

Warm up example – simple login test:

// THIS IS ASYNCHRONIOUS!
    
client->getCurrentView()->assertValue("Start view:", "login");
auto tbEmail = client->getElement("login", "tbEmail")->assertOk();
client->setTextInTextbox(tbEmail, email);
auto tbPsw = client->getElement("login", "tbPassword")->assertOk();
client->setTextInTextbox(tbPsw, password);
auto bLogin = client->getElement("login", "bLogin");
bLogin->assertOk();
client->clickElement(bLogin);
    
client->getCurrentView()->makePeriodic(300)->successOnValue("main");

This seems like normal local test but in reality under the hood this code creates state machine with message handlers which will be executed asynchroniously. Not only this is much shorter than defining states and handles manually, but also this is general way of doing things which is familiar for any auto tester.

The problem is that not all things could be transferred totally unchanged. Cycles, conditions and so on can not be written in such clean way except we introduce some preprocessing or DSL to make changes into asynchronous form. But let’s go step by step.

IMPLEMENTATION DETAILS

First big help here is auto keyword. When we execute request method like getElement in previous example the result is actually not a value, but a future. And as we need as compact syntax as possible and a lot of additional customisations, here will fit custom implementation. (There are a lot of ways to implement this – so any specific ways are optional and you could tune them as you like)

Here is part of such asynchronous value which is not yet acquired:

template <typename T>
class ATRequestValue : public std::enable_shared_from_this<ATRequestValue<T>> {
public:
    
    std::shared_ptr<T> value;        // main value - is empty at start
    
    ATTestState state;               // state of test when request has to be made

    std::function<void(Ptr)> request;                       // make request
    std::function<decltype(value)(MVMessage)> response;     // parse response
    MVMessage answer;                                       // client's answer [optional]
    //....

Main fields here: value – pointer to value which will be filled when answer from client will be received by server. state – corresponding state of test.  request – function which will send actual request to client. response – function with fill parse answer from server.

And so getElement function in previous code piece is not actually performing some actins but creates such ATRequestValue and fills it with corresponding request/response handlers as lamda functions:

auto getElement(const ValueProvider<string>& prefix, const ValueProvider<string>& name){
        return addRequest(std::make_shared<ATId>(test,
            "tests.ui.get element",
            [=](ATIdPtr value){
                 test->send("tests.ui.get element", {{"prefix", prefix()}, {"name", name()}}, value->delay);
            },
            [=](MVMessage msg){
                 return std::make_shared<id>(toID(msg->getString("id")));
            }
        ));
}

In this example we try to find some UI element by name and some prefix (which is also string), and result is some identifier of type id.

Function addRequest is something like this:

/// Add custom request (async stage) into chain
    template<typename T>
    T addRequest(T request)
    {
        // add item to current scope
        scopes.currentScope->addItem(request->name, [=](){
            jumpTo(request); 
            return true;
        });
        
        // add to list of requests
        requests.push_back(make_at_variant(request));
        return request;
    }

Before we discuss scopes, jumpTo, etc – let’s first talk why arguments of getElement are not just strings, but ValueProvider<string>. We could have kept them as strings if all parameters had been predefined before test. We can’t do that because in reality the most of inputs are computed depending on previous results. Thats why we need value providers – functors which will return (provide) some value of predefined type.

// Provide value through evaluation of inner function
template <typename T>
class ValueProvider {
private:
    std::function<T()> f;
public:
    ValueProvider(const std::function<T()>& f) : f(f) {}
    ValueProvider(T value) : f([value](){ return value; }) {}
    
    // construct from any functor
    template <typename F>
    ValueProvider(F f) : f([f](){ return f(); }) {}
    
    // get operator
    T operator()() const { return f(); }
};

Now we could pass lamda as parameter to getElement which will be executed later – for example:

auto bLogin = client->getElement("login", [](){ 
    // here could be complex logic
    return "bLog"s + "in"s; 
});

Now let’s go back to place where getElement is called. Details on how exactly we form request and read response are not so important – what matters is how to make a chain of such calls. This is the place where we need scopes, elements, requests and jumps between them.

Let’s look at first simple case when we have only one scope (simple test with no branches or cycles). In such case we just need basic jump from one request to another (and gather them inside one scope’s storage to keep them alive).

template <typename T>
void jumpTo(std::shared_ptr<ATRequestValue<T>> value)
{
    test->state = value->state;
    test->state++; // just increment state - simple case
    value->request(value);
}

In simple case to perform jump we need just increment test’s state and perform request of next RequestValue. To finish the magic we just need to assemble() things together into one state machine.

// Final assemble
void assemble(){     
    ATTestState s = 1;
    for (auto request : requests)
         addHandlersForRequest(s, request);
}

/// Main constructor of stages
template <typename T>
void addHandlersForRequest(ATTestState& state, std::shared_ptr<ATRequestValue<T>> value)
{
     value->state = state;
     
     // go to next stage   
     state++;
        
     // add answer
     test->actions[state].set(value->name, [value, this](MVMessage msg){
            value->answer = msg;
            value->value = value->response(msg);
           
            scopes.runNextItemInScope();
        });
        
}

I’m skipping here the variadic part – ATRequestValue<T> could contain different types of values and so the list of requests should be able to hold variadic types – but may be this will be the topic of separate post.

In trivial case when we have only one scope running next item could be pretty simple:

bool runNextItemInScope(){
    scope->position++;
    scope->children[scope->position].run();
}

And this enough to implement simple sequential chains without any branching. But we need more.

SCOPES AND BRANCHING

First problem arises when we want to add first conditional branch into our test’s logic. When we write something like:

auto text = getElementText(editBox1);
if (text.get() == "5"){
    auto element = getElement("main", "button1");
    client->clickElement(element);
}

This will not work because condition will be executed synchronously and text will not yet be received. So this code will crash. The solution is to create async_if implementation which will accept predicate and evaluate it at right moment when the text will be received. Also we need scopes here. They could be implemented as simple lists of run functions, but with some additional enter / exit handlers.

/// Item inside scope
class ATScopeItem {
public:
    string name;                        /// for debugging
    std::function<bool()> run;          /// run item - returns false if there is nothing to run
};

// type of scope
enum class ATScopeType { normal, cycle };

/// Async scope
class ATScope {
public:
    ATScopeType scopeType;
    ATScope() : position(-1), 
       scopeType(ATScopeType::normal), 
       enter([this](){ position = -1; return !isEmpty(); }), 
       exit([](){ return false; }) {}

    vector<ATScopeItem> children;             ///< the list of scope items
    
    int position;                             ///< current position in scope
    
    std::function<bool()> enter;              ///< on scope enter
    std::function<bool()> exit;               ///< on scope exit
    
    
    void addItem(string name, std::function<bool()> item){
        children.push_back({name, item});
    }
    
    bool isEmpty() { return (children.size() == 0); }
};

Optional stuff here – names for scope elements (for debugging). Also there are scope types – we will need them later.

Enter and exit functions return boolean values – when true is returned it means we had some asynchronious action called inside and should wait for result. If false is returned we could continue execution and move to next item in scope without waiting.

Also we need some structure which will contain all scopes and organise movement between them. We could use some tree or stack here.

// Stack of scopes
class ATScopeStack {
public:
    
    ATScopePtr currentScope;  ///< pointer to current scope

    // main push/pop operations 
    void pushScope(ATScopePtr scope) { scopes.push(scope); currentScope = scope; }
    void pop(){ scopes.pop(); currentScope = scopes.top(); }
    
    bool enterScope(ATScopePtr scope){
        scope->position = -1;
        if (currentScope != scope)
            pushScope(scope);
        if (scope->enter())
            return runNextItemInScope();
        return false;
    }
    
    bool isRootScope(){ return (scopes.size() == 1); }
    
    // call run for next element (recursive, could go through stack of scopes)
    bool runNextItemInScope(){
        
        auto scope = currentScope;
        
        while (true)
        {
            // if we have more items in current scope
            if (scope->position < (int)scope->children.size() - 1)
            {
                scope->position++;
                if (!scope->children[scope->position].run())
                {
                    continue;
                }
                else
                {
                    return true;
                }
            }
            else
            {
                if (scope->exit())
                    return true; // exit() called some block
                
                if (isRootScope())
                    return false; // do nothing
                
                pop();
                scope = currentScope;
            }
        }
        return false;
    }
    
    std::vector<ATScopePtr> allScopes;     ///< all scopes as list
private:
    std::stack<ATScopePtr> scopes;    ///< current state of scope stack
};

Function enterScope here also returns boolean so it could stop synchronous execution and wait for next result in asynchronous chain.  Now our main function runNextItemInScope which goes to next item becomes slightly more complicated – it’s a cycle which will call elements in current scope one by one until any of them signal that we have to wait by returning true from it’s run(). When there are no more items in scope we pop upper scope from scope stack and continue execution there using same pattern. And finally when scope has no parent (stack has only 1 item) we just stop.

It’s great that in such scheme we could implement not only “if” branch but cycles too. But let’s start with async_if:

auto async_if(std::function<bool()> condition, std::function<void()> thenBody, std::function<void()> elseBody){
        
        // then
        auto thenScope = make<ATScope>();
        scopes.pushScope(thenScope);
        scopes.allScopes.push_back(thenScope);
        thenBody();
        scopes.pop();
        
        // else
        auto elseScope = make<ATScope>();
        scopes.pushScope(elseScope);
        scopes.allScopes.push_back(elseScope);
        elseBody();
        scopes.pop();
        
        // create scope item
        scopes.currentScope->addItem("async_if", [=](){
            if (condition())
                return scopes.enterScope(thenScope);
            else
                return scopes.enterScope(elseScope);
        });
    }

So this function actually executes both then/else branches right away! But this execution only creates functional handlers which will be called later. We pass both branches and predication as parameters here. Thanks to C++11’s lambda syntax it’s possible to write such code:

auto text = getElementText(editBox1);
async_if([=]()( return (text.get() == "5"); )
    [=](){
        // more async logic
        auto element = getElement("main", "button1");
        client->clickElement(element);
    },[=](){
        // do something else async way
    }
);

I have to admit this is not so pretty as simple if and this is very sad. Of course this is much better than writing async handlers straightforward way, but this still is not perfect. Optional way is to make some preprocessing eliminating boilerplate functional wrapping, or even make some DSL for autotests. Using additional scripting overlay may ease the pain a bit (will be discussed at part 3).

WHILE / CONTINUE

Same way we could define while cycle.

auto async_while(std::function<bool()> condition, std::function<void()> body){
        // body
        auto scope = make<ATScope>();
        scope->scopeType = ATScopeType::cycle;
        scopes.pushScope(scope);
        scopes.allScopes.push_back(scope);
        body();
        scopes.pop();
        
        thenScope->exit = [=](){
            if (condition())
                return scopes.enterScope(scope);
            return false;
        };
        
        // create scope item
        scopes.currentScope->addItem("async_while", [=](){
            if (condition())
                return this->scopes.enterScope(scope);
            return false;
        });
    }

Here we set custom exit procedure which checks condition and reenters scope if it was not satisfied.  Usage example could be the following:

async_while([](){ return true; }, [](){
    client->clickElement(someButton).setDelay(2000);
});

We could also introduce continue operator. This is the place where we need to know the type of scope. Logic is simple – we go up through scope stack until we find cycle scope, and then we reenter that scope.

auto async_continue(){
        // create scope item
        scopes.currentScope->addItem("async_continue", [=](){
            
            // we go back to first cycle scope
            while (scopes.currentScope->scopeType != ATScopeType::cycle)
            {
                scopes.pop();
                
                if (scopes.isRootScope())
                    return false; // do nothing
            }
            
            return scopes.enterScope(scopes.currentScope);
        });
}

Now we could have any kind of nested structure like async_continue inside async_if which is inside async_while.

FOREACH

Async foreach is a bit tricky as you have to iterate over something which is not yet obtained. But whole trick is that you have to use data provider instead of data itself. Provider is a function which gives array – and you could access it by index or iterator. There are a lot of freedom here so I put here only basic start example for some vector and indexed access:

template <typename T>
auto async_foreach(ValueProvider<vector<T>> listProvider, std::function<void(ValueProvider<T>)> body){
        
        // we create new provider for element of list
        std::shared_ptr<int> index = make_shared<int>(0);
        ValueProvider<T> elementProvider([=](){
            return listProvider()[*index];
        });
        
        // body
        auto scope = make<ATScope>();
        scope->scopeType = ATScopeType::cycle;
        scopes.pushScope(scope);
        scopes.allScopes.push_back(scope);
        body(elementProvider);
        scopes.pop();
        
        scope->enter = [=](){
            thenScope->position = -1;
            if (listProvider().size() == 0) return false;
            *index = 0;
            return !scope->isEmpty();
        };
        
        scope->exit = [=](){
            *index += 1;
            if ((*index >= listProvider().size()) || (scope->isEmpty()))
                return false;
            scope->position = -1;
            return scopes.runNextItemInScope();
        };
        
        // create scope item
        scopes.currentScope->addItem("async_foreach", [=](){
            return this->scopes.enterScope(scope);
        });
        
    }

Here we redefine both enter/exit handlers to create an iterator. Cycle body is called with parameter which is a value provider once again.

Usage example:

global tabs = getElementChildren(barWithTabs);
 async_foreach(
      provideVectorId([](){ return tabs.get(); }),
      [](auto x){
           auto tab = checkElement(x);
           touchElement(tab, 5.0, 5.0).setDelay(1000);
      });

This sample clicks all tabs inside some menu bar.

INSERT ANY SYNCHRONIOUS ACTION INTO CHAIN – ASYNC_DO

There are a lot of cases when between asynchronous requests we need to perform some synchronous actions (like printing something to log). Of course it cannot be written general way because in that case it will be executed at test’s assemble time when we only set handlers and yet have no data. As one way to solve this we add additional function – async_do.

auto async_do(std::function<void()> body){
        
        // create scope item
        scopes.currentScope->addItem("async_do", [=](){
            body();
            return false;
        });
         
}

So we just wrap functional body into scope element and insert it into scope. We could introduce here a lot more of helper functions such as async_set or async_copy. They could also assign the result to some variable or do something else.

Usage example of async_do could be found in part 3.

EXTENDING ASYNC VALUES

Second way to perform synchronous actions is to insert some functional checks right inside request values.

First one to add is special assert which check that async request went well:

bTotalPrice = getElement("", "bTotalPrice").assertOk("Something went wrong");

// or we could check some value
auto text = getElementText(bTotalPrice).assertNotEqual("$0", "Balance should not be equal to zero in this test");

// or we could even check some functional condition
text.assertCondition("Balance should be in USD", [](auto x){
    return (x.get().find("$") != string::npos); 
});

// or we could just do something after value was received
text.andDo([](){ log("Data was received"); });

To implement such functions we only need to create array of functional checks inside ATRequestValue and add such methods as:

/// Assert that value is equal to given value
Ptr assertValue(string message, T shouldBeValue){
        checks.emplace_back([this, shouldBeValue, message](){
            if (*value != shouldBeValue) 
                 test->fail(message + " expected: " + request_value_to_string(shouldBeValue) + " got: " + request_value_to_string(*value));
        });
        return this->shared_from_this();
}

I use fluent interface pattern here – this is optional of course.

You can find usage examples of such checks in part 3.

Also we could add function waitFor(interval, condition) which will make periodic requests until provided functional condition will be fulfilled.

I think you already got a lot of ideas how to expand this approach. So let’s move on to the last chapter.

PART 3 – INTEGRATION OF SCRIPTING LANGUAGE INSIDE C++

Final step to make our life sweet enough is addition of some scripting language. Advantages?

  • there will be ability to add new tests without rebuilding server (actually we even could not restart it)
  • we could write new tests faster
  • whole thing becomes more flexible
  • automation testers feel more comfortable as it’s not C++ (yes, that’s a plus 🙂 )

ChaiScript

Here comes our new hero – ChaiScript. At first I was thinking about lua, but after reading ChaiScript’s docs I decided that language has more that enough flexibility to cover autotests needs. Main advantage of ChaiScript is that it is made for C++ integration and so the one could expect very fast way to add the scripting into the app. ChaiScript is relatively new but mature enough. It has relatively good documentation.

It took me only one day to integrate it into testing environment.

Whole ‘scripting part’ implementation at the moment is just 300 lines of code. And it gave the ability to write all asynchronous tests completely inside separate script files.

Base syntax of ChaiScript is very similar to C++ or JS. In simple case there are only two points the one should change to make C++ test work as script:

// Lambda functions have different declaration
[](){ ... }  

// is replaced with 
fun(){ ... }   

// And -> operator is replaced with .
value.get() // not value->get()

Actually syntax for lambdas is even a bit better as too much square brackets may make things less readable.

Example of test:

// This is script

def start(){

    getCurrentView().assertValue("Start view:", "main");

    async_while(fun(){ return true; }, fun(){

        auto plotter = getElement("main", "plotter").assertOk("Can't find main plotter");
        
        // replot if plot button is visible
        auto bPlot = getElement(plotter, "bPlot");
        global isPlotBtnVisible = getElementVisibility(bPlot);
        async_if(fun(){ return isPlotBtnVisible.get(); },
                 fun(){ clickElement(bPlot); }, 
                 fun(){});

        // select min or max value (random) by clicking on it
        auto bExtremum = getElement(plotter, provide(fun(){ return (random(2) == 0) ? "bMax" : "bMin"; })).assertOk("Can't find min/max button");
        clickElement(bExtremum);

        // get selected value
        auto bSelectedValue = getElement(plotter, "bValue").assertOk("Can't find selected value");
        global valueText = getElementText(bSelectedValue).logValue("Value:").assertCondition("Not zero:", fun(x){ return (x.get().size() > 0); });
        async_do(fun(){
            // here we strip $ sign, convert text into double and print it to log
            auto b = replaceInString(valueText.get(), "\$", "");
            auto balance = to_double(b);
            log("Balance: " + to_string(balance));
        });

        // wait 3 secs
        getCurrentView().setDelay(3000).assertValue("Current view is still:", "main");
    });

};

This is test which every 3 seconds selects min or max value on some plotter, performs some checks and prints it to log. I hope now you can feel the benefits of encapsulation of async requests.

As for interface implementation between scripting and C++ – it is pretty simple. Not only you could export functions and object methods to ChaiScript, but you could also export custom type conversions, complex types and so on. I will not provide implementation details here as it will make the post too big, but you could get the idea from this cheatsheet.

One minor disadvantage: as far as I know there is no default parameter capture modes for lambda functions inside ChaiScript at the moment. If you work with a lot of small functions this could be an improvement to have syntax like fun[=](){ …. } which is not available at the moment. Or even make is as default behaviour. I hope @lefticus will add this in future.

Anyway, ChaiScript seems like a nice solution for me at the moment.

SHORT CONCLUSION

Encapsulation of async execution using modern C++ gives ability to create distributed solutions. This post shown how such technique could be used for creation of custom system of distributed autotests. Scripting could be added into such systems to increase flexibility.

]]>
http://vitiy.info/encapsulation-of-asynchronous-behaviour-in-distributed-system-of-scripted-autotests/feed/ 3
Immutable serialisable data structures in C++11 http://vitiy.info/immutable-data-and-serialisation-in-cpp11/ http://vitiy.info/immutable-data-and-serialisation-in-cpp11/#comments Mon, 29 Jun 2015 11:18:03 +0000 http://vitiy.info/?p=575 immutablecppcaption

As C++ is very flexible language there are a lot of ways to construct immutable-like data structures from functional programming style. For example, this nice presentation by Kelvin Henney contains one of the ways. Here I will present my way which is slightly different.

At the same time my approach also solves another problem of serialisation of such immutable structures. I use JSON format at the moment, but the approach is not limited to this format only.

Unlike my previous posts I will start from the results this time.

I suppose you are familiar with general concept of immutability. If you are not – please read some minimal introduction to immutable data concept in functional programming.

FIRST PART – USAGE

ATM I have structure declarations simular to this:

class EventData : public IImmutable {
  public:
    const int id;
    const string title;
    const double rating;

    SERIALIZE_JSON(EventData, id, title, rating);
};

using Event = EventData::Ptr;

Data fields of class are declared as const. And that’s what should be done to be sure that data will not be changed. Note, that I don’t change fields to functions, I don’t hide them below some getters or doing some other tricky stuff. I just mark fields const.

Next – SERIALIZE_JSON. This is macro which contains all the magic. Unfortunately we can’t at the moment achieve introspection without macro declaration. So this is black magic again. I promise next post will not contain macros 🙂

The last step is sharing immutable data through smart pointer to decrease data copy overhead introduced by functional-style data processing. And I use such pointers implicitly. For example: plain data object is named as EventData and pointer to such data is named just Event. This is arguable moment – it’s not necessary to follow this notation.

About the price of using shared_ptr there is nice video from NDC conference – The real price of Shared Pointers in C++ by Nicolai M. Josuttis.

Before presenting some usage examples let’s make data a bit more realistic:

class ScheduleItemData : public IImmutable {
     public:
            const time_t start;
            const time_t finish;
            SERIALIZE_JSON(ScheduleItemData, start, finish);
};
        
using ScheduleItem = ScheduleItemData::Ptr;
        
        
class EventData : public IImmutable {
        public:
            const int id;
            const string title;
            const double rating;
            const vector<ScheduleItem> schedule;
            const vector<int> tags;
            
            SERIALIZE_JSON(EventData, id, title, rating, schedule, tags);
};      
        
using Event = EventData::Ptr;

This is description of some event which has id, title, rating, some schedule as pairs of start/finish linux-times, and vector of integer tags. All this just to show nested immutable structures and const vectors as parts of serialisable data.

Note that you can still add some methods into this class. Marking them const will be good idea.

IMMUTABILITY

Ok, it’s time for action! Structure creation is simple:

Event event = EventData(136, "Nice event", 4.88, {ScheduleItemData(1111,2222), ScheduleItemData(3333,4444)}, {45,323,55});

Using new C++ initialisation syntax we can not only form immutable structure the simple way, but also declare all nested collections. All constructors are generated automatically by same black-magic macro.

Important: immutable data does not have empty constructor! You can only create ‘filled’ data state. This is good feature as now it’s very problematic to get corrupted unfully-constructed state. It’s all or nothing. And of course you still could have empty shared_ptr which could contain no immutable data at all.

When you add new field into data structure all places where data was created explicitly will stop to compile. It might seem as bad, but actually this is very good restriction. Now you can’t forget to modify your object construction according new design.

As you can guess all fields could be accessed general way. But any modification will be prevented by compiler.

immutability

To modify immutable data we need to create new copy of data with modified field. So it’s not modification, but the construction of new object. Same macro is generating all such constructors:

Screenshot 2015-06-27 23.09.39

Note: type is auto-derived using decltype from C++11.

To get the idea how to use such immutable data in functional way using C++11 you can read several posts: post1 post2 post3 (and, probably, more are coming).

SERIALIZATION

Just two methods: toJSON() / fromJSON() are enough to handle all serialisation/deserialisation needs:

// serialisation
string json = event->toJSON();

// deserialisation
Event eventCopy = EventData::fromJSON(json);

Output:

{"id":136,"title":"Nice event","rating":4.880000,"schedule":[{"start":1111,"finish":2222},{"start":3333,"finish":4444}],"tags":[45,323,55]}

Sweet and simple. And note that we can (de)serialise nested structures / arrays.

Serialisation part is optional – if you only need immutability you don’t have to include this part. Implementation of immutability is not using any serialisation implicitly.

SECOND PART – IMPLEMENTATION

Under the hood there is fusion of macro-magic and C++11 features like decltype. I’ll try to express the main ideas how it was implemented instead of just copying of whole code. If you not trying to implement the given approach yourself you could even skip this and believe me that it works.

The next part will be a bit ugly. Be sure you are 16+ before reading this.

caution

Also I had some additional limitation which absence could make life a bit more easy – i could not use constexpr. I use immutable data inside cross-platform solutions and one of my targets is Windows desktop. I don’t know why Microsoft Visual Studio 2015 still does not like constexpr but it’s support is not yet completed. So don’t be surprised why i’m using couple of old-school macro technics to make functional stuff work in more comfort way.

At first we need macro which applies macro to each of macro parameter.

#define SERIALIZE_PRIVATE_DUP1(M,NAME,A) M(NAME,A)
#define SERIALIZE_PRIVATE_DUP2(M,NAME,A,B) M(NAME,A) M(NAME,B)
#define SERIALIZE_PRIVATE_DUP3(M,NAME,A,B,C) M(NAME,A) SERIALIZE_PRIVATE_DUP2(M,NAME,B,C)
#define SERIALIZE_PRIVATE_DUP4(M,NAME,A,B,C,D) M(NAME,A) SERIALIZE_PRIVATE_DUP3(M,NAME,B,C,D)
#define SERIALIZE_PRIVATE_DUP5(M,NAME,A,B,C,D,E) M(NAME,A) SERIALIZE_PRIVATE_DUP4(M,NAME,B,C,D,E)
#define SERIALIZE_PRIVATE_DUP6(M,NAME,A,B,C,D,E,F) M(NAME,A) SERIALIZE_PRIVATE_DUP5(M,NAME,B,C,D,E,F)
#define SERIALIZE_PRIVATE_DUP7(M,NAME,A,B,C,D,E,F,G) M(NAME,A) SERIALIZE_PRIVATE_DUP6(M,NAME,B,C,D,E,F,G)
#define SERIALIZE_PRIVATE_DUP8(M,NAME,A,B,C,D,E,F,G,H) M(NAME,A) SERIALIZE_PRIVATE_DUP7(M,NAME,B,C,D,E,F,G,H)
#define SERIALIZE_PRIVATE_DUP9(M,NAME,A,B,C,D,E,F,G,H,I) M(NAME,A) SERIALIZE_PRIVATE_DUP8(M,NAME,B,C,D,E,F,G,H,I)
#define SERIALIZE_PRIVATE_DUP10(ME,NAME,A,B,C,D,E,F,G,H,I,K) ME(NAME,A) SERIALIZE_PRIVATE_DUP9(ME,NAME,B,C,D,E,F,G,H,I,K)
#define SERIALIZE_PRIVATE_DUP11(ME,NAME,A,B,C,D,E,F,G,H,I,K,L) ME(NAME,A) SERIALIZE_PRIVATE_DUP10(ME,NAME,B,C,D,E,F,G,H,I,K,L)
#define SERIALIZE_PRIVATE_DUP12(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M) ME(NAME,A) SERIALIZE_PRIVATE_DUP11(ME,NAME,B,C,D,E,F,G,H,I,K,L,M)
#define SERIALIZE_PRIVATE_DUP13(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N) ME(NAME,A) SERIALIZE_PRIVATE_DUP12(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N)
#define SERIALIZE_PRIVATE_DUP14(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O) ME(NAME,A) SERIALIZE_PRIVATE_DUP13(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O)
#define SERIALIZE_PRIVATE_DUP15(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O,P) ME(NAME,A) SERIALIZE_PRIVATE_DUP14(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O,P)
#define SERIALIZE_PRIVATE_DUP16(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R) ME(NAME,A) SERIALIZE_PRIVATE_DUP15(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R)
#define SERIALIZE_PRIVATE_DUP17(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S) ME(NAME,A) SERIALIZE_PRIVATE_DUP16(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S)
#define SERIALIZE_PRIVATE_DUP18(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T) ME(NAME,A) SERIALIZE_PRIVATE_DUP17(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T)
#define SERIALIZE_PRIVATE_DUP19(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,Q) ME(NAME,A) SERIALIZE_PRIVATE_DUP18(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,Q)
#define SERIALIZE_PRIVATE_DUP20(ME,NAME,A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,Q,Y) ME(NAME,A) SERIALIZE_PRIVATE_DUP19(ME,NAME,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,Q,Y)


#define SERIALIZE_PRIVATE_EXPAND(x) x
#define SERIALIZE_PRIVATE_DUPCALL(N,M,NAME,...) SERIALIZE_PRIVATE_DUP ## N (M,NAME,__VA_ARGS__)

// counter of macro arguments + actual call
#define SERIALIZE_PRIVATE_VA_NARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, N, ...) N
#define SERIALIZE_PRIVATE_VA_NARGS(...) SERIALIZE_PRIVATE_EXPAND(SERIALIZE_PRIVATE_VA_NARGS_IMPL(__VA_ARGS__, 20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1))
#define SERIALIZE_PRIVATE_VARARG_IMPL2(M,NAME,base, count, ...) SERIALIZE_PRIVATE_EXPAND(base##count(M,NAME,__VA_ARGS__))
#define SERIALIZE_PRIVATE_VARARG_IMPL(M,NAME,base, count, ...) SERIALIZE_PRIVATE_EXPAND(SERIALIZE_PRIVATE_VARARG_IMPL2(M,NAME,base, count, __VA_ARGS__))
#define SERIALIZE_PRIVATE_VARARG(M,NAME,base, ...) SERIALIZE_PRIVATE_EXPAND(SERIALIZE_PRIVATE_VARARG_IMPL(M,NAME, base, SERIALIZE_PRIVATE_VA_NARGS(__VA_ARGS__), __VA_ARGS__))

#define SERIALIZE_PRIVATE_DUPAUTO(M,NAME,...) SERIALIZE_PRIVATE_EXPAND(SERIALIZE_PRIVATE_VARARG(M,NAME,SERIALIZE_PRIVATE_DUP, __VA_ARGS__))

This is very ugly, but it works (clang, gcc, VS). As you might guess this specific version could handle up to 20 arguments only.

I will split the whole macro to blocks and to improve readability I will skip ‘\’ sign here which is at the end of each line in multiline macro. Also in each block ‘helper’ macros will be placed below to show content together.

Main constructor:

// Main constructor 
NAME(SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLEDECL,NAME,__VA_ARGS__) int finisher = 0) :    
SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLEPARAM,NAME,__VA_ARGS__)IImmutable(){}   


#define SERIALIZE_PRIVATE_CTORIMMUTABLEDECL(NAME,VAL) decltype(VAL) VAL,
#define SERIALIZE_PRIVATE_CTORIMMUTABLEPARAM(NAME,VAL) VAL(VAL),

NAME – is name of class. VA_ARGS is the list of all fields. So macro is expanded in something like this – NAME(decltype(a) a, decltype(b) b,int finisher=0) : a(a), b(b), IImmutable(){} . Here IImmutable is some base class (optional), which could be empty. Also I use finisher to solve last comma problem – may be there is some more clean solution for this.

So other part of magic here is using decltype from C++11.

Additional copy constructors:

// copy constructors
         
NAME(NAME&& other) noexcept :   
SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLECOPY,NAME,__VA_ARGS__)IImmutable() 
{}                                                                                                          
NAME(const NAME& other) noexcept :
SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLECOPY,NAME,__VA_ARGS__)IImmutable(){}


#define SERIALIZE_PRIVATE_CTORIMMUTABLECOPY(NAME,VAL) VAL(other.VAL),

Note that we can’t move immutable data. Move semantics modify the source object and immutable objects can’t be modified.

The last constructor is from std::tuple. We need it for modification / serialisation methods.

// Constructor from tuple
NAME(std::tuple< SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLEDECLTYPENONCONST,NAME,__VA_ARGS__) int> vars) : SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORFROMTUPLE,NAME,__VA_ARGS__)IImmutable() {}   

#define SERIALIZE_PRIVATE_CTORIMMUTABLEDECLTYPENONCONST(NAME,VAL) typename std::remove_const<decltype(VAL)>::type,
   
#define SERIALIZE_PRIVATE_CTORFROMTUPLE(NAME,VAL) VAL(std::get<SERIALIZE_PRIVATE_GETINDEX(NAME,VAL)>(vars)),

The tricky part here is that to construct from tuple we need to know index of each field inside tuple. To get such index we need C++14’s constexpr with no C++11 limitations (increment inside constexpr). Or we can use __COUNTER__ macro to create additional static fields which contain indexes.

// Index of each field inside class:
static const int _index_offset = __COUNTER__;       
SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_FIELDINDEX,NAME,__VA_ARGS__)     
      
#define SERIALIZE_PRIVATE_FIELDINDEX(NAME,VAL) static const int _index_of_##VAL = __COUNTER__ - _index_offset - 1;

Note that __COUNTER__ macro is global so we need to generate additional offset field to store initial value and solve the difference for each index.

Generation of ‘set_’ methods:

// Generation of set_ methods
SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CLONEANDSET2,NAME,__VA_ARGS__) 

// Convert data into std::tuple
std::tuple< SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLEDECLTYPENONCONST,NAME,__VA_ARGS__) int> toTuple() const noexcept {
    return make_tuple(SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_CTORIMMUTABLEVAL,NAME,__VA_ARGS__) 0);    
} 

#define SERIALIZE_PRIVATE_CLONEANDSET2(NAME,VAL) NAME::Ptr set_##VAL(decltype(VAL) VAL) const noexcept {   
    auto t = toTuple();
    std::get<SERIALIZE_PRIVATE_GETINDEX(NAME,VAL)>(t) = VAL;
    return std::make_shared<NAME>(NAME(t));                       
}

Unfortunately tuple also has finisher as int type to solve ‘comma’ problem. May be i’ll find a way to make it possible without it.

To make shorter declaration of holding pointers:

// Short smart-pointer declaration
typedef std::shared_ptr<NAME> Ptr;

Additional overload of compare operator:

// compare operator overload
bool operator== (const NAME& other) const noexcept {
    SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_COMPAREIMMUTABLE,NAME,__VA_ARGS__) return true; 
    return false;
}

#define SERIALIZE_PRIVATE_COMPAREIMMUTABLE(NAME,VAL) if (other.VAL==VAL)

This overload could be changed according to business logic. For example you could compare only id fields.

Whole serialisation part of macro is quite short:

// JSON serialisation is done using my own old lib 		
string toJSON() const noexcept {
    JSON::MVJSONWriter w;
    w.begin();                        
    SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_APPENDTOJSON,NAME,__VA_ARGS__)     
    w.end();                           
    return w.result;              
}                            

static NAME fromJSON(string json)
{                                   
   JSON::MVJSONReader reader(json);            
   return fromJSON(reader.root); 
}                                                                        
               
static NAME fromJSON(JSON::MVJSONNode* node)
{            
    return NAME( make_tuple(SERIALIZE_PRIVATE_DUPAUTO(SERIALIZE_PRIVATE_FROMJSON,NAME,__VA_ARGS__) 0));     
}                                                                                  


#define SERIALIZE_PRIVATE_APPENDTOJSON(NAME,VAL) w.add(#VAL,VAL);
#define SERIALIZE_PRIVATE_FROMJSON(NAME,VAL) node->getValue<decltype(VAL)>(#VAL),

Here I use my old lib for parsing JSON (described here). But you can use any JSON decoder you like. The only restriction is that you have to write wrappers so your lib could read/write values through single entry point. Here I will show an example implementation how to distinguish vector and non vector types.

JSON writer is using simple overloading / template specialisation:

template< typename T >
inline string toString(const T& value);
        
template< typename T >
inline string toString(const vector<T>& value);

Couple of implementations (for example):

template< typename T >
inline string MVJSONWriter::toString(const T& value)
{
        // default overload is for string-like types!
        return "\"" + value + "\"";        
}
   
template< typename T >
inline string MVJSONWriter::toString(const vector<T>& value)
{
        string result = "[";
        for (auto item : value)
            result += ((result != "[") ? "," : "") + item->toJSON();
        result += "]";
        return result;
}
    
template<>
inline string MVJSONWriter::toString(const vector<int>& value)
{
        string result = "[";
        for (auto item : value)
            result += ((result != "[") ? "," : "") + std::to_string(item);
        result += "]";
        return result;
}

So all type variations are hidden inside JSON writing/reading section.

Reader has a bit more complicated form of overloading because we have to overload only output type. To make this possible we have some dummy parameter, std::enable_if and simple type trait for vector detection.

template <typename T> struct is_vector { static const bool value = false; };
template <typename T> struct is_vector< std::vector<T> > { static const bool value = true; };
template <typename T> struct is_vector< const std::vector<T> > { static const bool value = true; };

// inside reader class:
    
template<class T>
inline T getValue(const string& name, typename enable_if<!is_vector<T>::value, T>::type* = nullptr);
    
template<class T>
inline T getValue(const string& name, typename enable_if<is_vector<T>::value, T>::type* = nullptr);

Some overloads:

template<class T>
inline T
MVJSONNode::getValue(const string& name, typename enable_if<!is_vector<T>::value, T>::type*)
{
        MVJSONValue* value = getField(name);
        if (value == NULL) return "";
        return value->stringValue;
}
    
template<class T>
inline T
MVJSONNode::getValue(const string& name, typename enable_if<is_vector<T>::value, T>::type*)
{
        typename std::remove_const<T>::type result;
        MVJSONValue* value = getField(name);
        if (value == NULL) return result;
        for (auto item : value->arrayValue)
        {
            result.push_back(remove_pointer<decltype(std::declval<T>().at(0).get())>::type::fromJSON(item->objValue));
        }
        return result;
}
    
    
template<>
inline const vector<int>
MVJSONNode::getValue(const string& name, typename enable_if<is_vector<const vector<int>>::value, const vector<int>>::type*)
{
        vector<int> result;
        MVJSONValue* value = getField(name);
        if (value == NULL) return result;
        for (auto item : value->arrayValue)
        {
            result.push_back((int)item->intValue);
        }
        return result;
}

So you need to specify overloads for all your trivial types and containers. In practice this is not so compact but anyway you should do it only once.

CONCLUSION

Once again, all this ugly implementation detail is written only once and is located on low level of architecture. Upper business layer just uses this utility as black box and should not be aware of inner implementation.

Anyway the main idea of this post was to show how compact declaration of immutable data could be in C++11, and that you don’t have to write more boilerplate code for each business class declaration.

Any comments are welcome.

UPDATE: I put some source code on github as 2 gists:

My old JSON lib – https://gist.github.com/VictorLaskin/1fb078d7f4ac78857f48

Declaration – https://gist.github.com/VictorLaskin/48d1336e8b6eea16414b

Please, treat this code like just an example.

]]>
http://vitiy.info/immutable-data-and-serialisation-in-cpp11/feed/ 4
Templates as first-class citizens in C++11 http://vitiy.info/templates-as-first-class-citizens-in-cpp11/ http://vitiy.info/templates-as-first-class-citizens-in-cpp11/#comments Wed, 04 Mar 2015 15:22:29 +0000 http://vitiy.info/?p=524 templates as citizens

C++11 treats functions as first-class citizens and this gives us ability to construct a lot of nice things as design patterns borrowed from functional languages. Meanwhile C++ has very powerful template metaprogramming. This post is aimed to make templated functions closer to first-class citizens, and to construct some simplicity and beauty which you can get from it.

Also here will be implementation for currying of such functions! If you don’t know what currying is – just remember std::bind.

And to make it shine we’ll add piping. (This article will improve some ideas from post about functional piping ). This step is optional and you can replace such piping with commas and function calls.

TEMPLATE TO SIMPLE FUNCTOR

Ok, let’s start from very simple template function.

template <typename T>
void print(T t)
{
    cout << t << endl;
}

I will use different styles of code colouring here to indicate difference between example code and inner implementation which is similar for all cases.

To pass it to some function we need to wrap it into functor:

class tfn_print { 
public: 
   template <typename... Args> 
   auto operator()(Args&&... args) const ->decltype(print(std::forward<Args>(args)...))  
   { 
       return print(std::forward<Args>(args)...); 
   } 
}

Here operator() is overloaded to pass all arguments to print template. As we will modify this functor to cover all cases, the list of arguments is provided using variadic templates. Note: you can define all functions inside such wrappers from the start, but there is way to do it through macro:

#define make_citizen(X) class tfn_##X { public: template <typename... Args> auto operator()(Args&&... args) const ->decltype(X(std::forward<Args>(args)...))  { return X(std::forward<Args>(args)...); } }

make_citizen(print);

This small macro creates class from templated function.

Important note for macro haters. Yes, macros should be avoided when you can substitute them using variadic templates and other new stuff. But still there are some cases when you can’t do that. So when you have couple of very small obvious macro definitions which will make your code considerably smaller, more readable and maintainable – use it. Such cases are rare and when it happens C++ committee should look upon it and add some means into the language itself to fix it.

Example:  

// testing print...
{
    tfn_print print;
    print(5);
    print("hello");
}

We redefined print in smaller scope as instance of object. Now we can use it as function and pass as argument to another function. Note that the same function is used with arguments of different type – so no need to create distinct functors.

Next we will create some additional instruments to work with such ‘templated’ functors more effectively.

PASS TUPLE TO FUNCTION AS ARGUMENT LIST

As we will use such ability later – let’s write simple function which will expand std::tuple and feed results into the given function.

// apply tuple to function...
    
namespace fn_detail {
        
        template<int ...>
        struct int_sequence {};
        
        template<int N, int ...S>
        struct gen_int_sequence : gen_int_sequence<N-1, N-1, S...> {};
        
        template<int ...S>
        struct gen_int_sequence<0, S...> {
            typedef int_sequence<S...> type;
        };
        
        template <typename F, typename... Args, int... S>
        inline auto fn_tuple_apply(int_sequence<S...>, const F& f, const std::tuple<Args...>& params) -> decltype( f((std::get<S>(params))...) )
        {
            return f((std::get<S>(params))...);
        }
        
}
    
template <typename F, typename... Args> 
inline auto fn_tuple_apply(const F& f, const std::tuple<Args...>& params) -> decltype( f(std::declval<Args>()...) )
{
    return fn_detail::fn_tuple_apply(typename fn_detail::gen_int_sequence<sizeof...(Args)>::type(), f, params);
}

In C++14 this could be done a bit shorter using std::integer_sequence, but at the moment I’m forced to use just C++11 ( to compile things for Android for example). The sequence of integer indices S is constructed through template recursion, and than is passed as additional argument for unpacking. This is just one of possible implementations.

Usage:

auto f = [](int x, int y, int z) { return x + y - z; };
auto params = make_tuple(1,2,3);
auto res = fn_tuple_apply(f, params);
print(res);

// Result: 0

The next step is the idea that you can combine function input parameters into tuple using several steps instead of one std::make_tuple call.

TUPLE CONCATENATION

For concatenation of tuples C++11 has function named std::tuple_cat. To make things more compact we can overload << operator to add new parameter into tuple.

// tuple concatenation via << operator
template<typename... OldArgs, typename NewArg>
tuple<OldArgs...,NewArg> operator<<(const tuple<OldArgs...> & t, const NewArg& arg)
{
    return std::tuple_cat(t, std::make_tuple(arg));
}

Usage:

auto list = make_tuple(1,4);
auto res2 = fn_tuple_apply(f, list << 4); // f(1,4,4)
print(res2);

// Result: 1

FUNCTIONAL PIPELINE 

See post about functional piping to get the idea (we use different implementation for piping here). Anyway, this step is optional and you can replace such piping with commas and function calls, but piping here looks very nice.

First simple overload will provide ability to pipe single argument into function:

// pipe single argument into function via | operator
template<typename T, class F>
auto operator|(T&& param, const F& f) -> decltype(f(param)) 
{
    return f(std::forward<T>(param));
}

Usage:

// Return count of elements as templated operator
template <typename T>
int count(const T& container)
{
    return container.size();
}
    
make_citizen(count);

{
    tfn_count count;
    vector<string> slist = {"one", "two", "three"};
    slist | count | print;
}

// Result: 3

One new sample template function count() is just returning size() of provided collection. We provide the list of three strings into count function and after that pipe the result into print().

This is nice but application seems to be rather limited as functions tend to have more than one argument. Let’s solve this using some curry…

CURRYING

curry

Currying in C++11 is usually made using std::bind, which is flexible and useful for a lot of cases. But we can’t use it for templates. So let’s create some wrapper class which will implement curry and provide the simplest way to work with it inside pipelines.

General way (like in haskell) is to curry from left to right argument – so call f(1,2,3) is equivalent to f(1)(2)(3). But in piping example everything is slightly different –f(1,2,3) is equivalent to 1 | f(2,3). In other words I want to curry both ways – left and right. Yes, std::bind gives ability to specify any order but this is for price of a bit longer syntax that it’s required in general cases. And haskell’s syntax is not so good also, imho. That’s because it’s hard for programmer to identify difference between currying and function call. So here i’m using different syntax (and this decision is optional) where you have separate operators for function call and argument curry.

The next class is called fn_universal as representation of some function which is polymorphic (in sense that it can accept arguments of different types) and can be used with currying and piping. May be this class will be extended further later. You might want to rename it to fn_curryed or something like it.

Of course, to hold arguments we will use tuples. The implementation:

// universal function / extended function wrapper !
template<typename F, typename TPackBefore = std::tuple<>, typename TPackAfter = std::tuple<>>
class fn_universal  {
    private:
        F f;                            ///< main functor
        TPackAfter after;               ///< curryed arguments
        TPackBefore before;             ///< curryed arguments
    public:
        
        fn_universal(F && f) : f(std::forward<F>(f)), after(std::tuple<>()), before(std::tuple<>()) {}
        
        fn_universal(const F & f, const TPackBefore & before, const TPackAfter & after) : f(f), after(after), before(before) {}
        
       
        template <typename... Args>
        auto operator()(Args... args) const -> decltype(
            fn_tuple_apply(f, std::tuple_cat(before, make_tuple(args...), after))
        ) {
            // execute via tuple
            return fn_tuple_apply(f, std::tuple_cat(before, make_tuple(std::forward<Args>(args)...), after));
        }
        
        
        // curry
        
        template <typename T>
        auto curry(T && param) const -> decltype(fn_universal<F,decltype(std::tuple_cat(before, std::make_tuple(param))),TPackAfter>(f, std::tuple_cat(before, std::make_tuple(param)), after))
        {
            return fn_universal<F,decltype(std::tuple_cat(before, std::make_tuple(param))),TPackAfter>(f, std::tuple_cat(before, std::make_tuple(std::forward<T>(param))), after);
        }
        
        
        template <typename T>
        auto curry_right(T && param) const -> decltype(fn_universal<F, TPackBefore, decltype(std::tuple_cat(after, std::make_tuple(param)))>(f, before, std::tuple_cat(after, std::make_tuple(param))))
        {
            return fn_universal<F, TPackBefore, decltype(std::tuple_cat(after, std::make_tuple(param)))>(f, before, std::tuple_cat(after, std::make_tuple(std::forward<T>(param))));
        }
    
};

Note that class is immutable.

The main nice thing about this class: there is no restriction on types or count of arguments. All what is done here is combining provided arguments into two tuples – right and left parameters. And when time comes to execute function we just combine everything into single tuple and feed this tuple into function. So you can curry function which supports variadic number of arguments!

And to provide easy interface for currying I use the following overloads for operators:

// left curry by << operator
template<typename UF, typename Arg>
auto operator<<(const UF & f, Arg && arg) -> decltype(f.template curry<Arg>(std::forward<Arg>(arg)))
{
    return f.template curry<Arg>(std::forward<Arg>(arg));
}
    
// right curry by >> operator
template<typename UF, typename Arg>
auto operator>>(const UF & f, Arg && arg) -> decltype(f.template curry_right<Arg>(std::forward<Arg>(arg)))
{
    return f.template curry_right<Arg>(std::forward<Arg>(arg));
}

Let’s add small builder helper. Also (very optional) I might add definition macro to make examples a bit shorter.

template <typename F>
auto fn_to_universal(F && f) -> fn_universal<F>
{
    return fn_universal<F>(std::forward<F>(f));
}

#define make_universal(NAME, F) make_citizen(F); const auto NAME = fn_to_universal(tfn_##F());

This line is just defining new ‘universal’ function from given template function. You could change this using more convenient way.

EXAMPLES FOR CURRYING

Trivial examples:

// currying....
auto f = [](int x, int y, int z) { return x + y - z; };
auto uf = fn_to_universal(f);
auto uf1 = uf << 1;
auto uf2 = uf1 << 2 << 5;
uf2() | print;
// result: -2

// Piping:
      
1 | (uf << 4 << 6) | print; // 4+6-1 = 9
        
3 | (uf >> 6 >> 7) | print; // 3+6-7 = 2

Note the order of arguments. Not so complicated to read.

Now let’s write couple of template functions to get some realistic examples. This will look like functional operators. I even could mark these functions as inner implementation as they are so common, but to underline that you have the ability to control this behaviour yourself I leave it marked as sample:

// MAP
template <typename T, typename... TArgs, template <typename...>class C, typename F>
auto fn_map(const C<T,TArgs...>& container, const F& f) -> C<decltype(f(std::declval<T>()))>
{
        using resultType = decltype(f(std::declval<T>()));
        C<resultType> result;
        for (const auto& item : container)
            result.push_back(f(item));
        return result;
}
    
// REDUCE (FOLD)
template <typename TResult, typename T, typename... TArgs, template <typename...>class C, typename F>
TResult fn_reduce(const C<T,TArgs...>& container, const TResult& startValue, const F& f)
{
        TResult result = startValue;
        for (const auto& item : container)
            result = f(result, item);
        return result;
}
    
// FILTER
template <typename T, typename... TArgs, template <typename...>class C, typename F>
C<T,TArgs...> fn_filter(const C<T,TArgs...>& container, const F& f)
{
        C<T,TArgs...> result;
        for (const auto& item : container)
            if (f(item))
                result.push_back(item);
        return result;
}

    
make_universal(fmap, fn_map);
make_universal(reduce, fn_reduce);
make_universal(filter, fn_filter);

It’s obvious that such primitives can be reused avoiding a lot of code duplication.

And one minor function – make sum of all arguments:

template <typename T, typename... Args>
T sum_impl(T arg, Args... args)
{
    T result = arg;
    [&result](...){}((result += args, 0)...);
    return result;
}
    
make_universal(sum, sum_impl);

Here could be more trivial implementation and couple of overloads, but to show that you have no limitation with count of arguments I leave it like this.

Also we can modify print to handle any amount of arguments:

template <typename... Args>
void print(Args... args)
{
    (void)(int[]){((cout << args), 0)...}; cout << endl;
}

auto uprint = fn_to_universal(print);

AND NOW: Let’s try this in action:

vector<string> slist = {"one", "two", "three"};

// all strings as one 
slist | (reduce >> string("") >> sum) | (uprint << "All: ");
// All: onetwothree

// sum of elements of array
vector<int>{1,2,3} | (reduce >> 0 >> sum) | (uprint << "Sum: ");
// Sum: 6

// count sum length of all strings in the list
slist | (fmap >> count) | (reduce >> 0 >> sum) | (uprint << "Total: " >> " chars");
// Total: 11 chars

This is quite readable and functional-style code. Not the one we could expect from C++.

So the idea is that now we can write small universal templates and combine them in pipelines as we like. Looks great!

Consider small templates as small universal building blocks.

More examples…

Let’s assume we are working with some business data like collection of users.

template <typename T, typename TName>
bool isNameEqualImpl(const T& obj, const TName& name)
{
    return (obj->name == name);
}
    
make_universal(isName, isNameEqualImpl);
    
template <typename T, typename TId>
bool isIdEqualImpl(const T& obj, const TId& id)
{
    return (obj->id == id);
}
    
make_universal(isId, isIdEqualImpl);
    
template <typename T>
bool isNotNullImpl(const T& t)
{
    return (t != nullptr);
}
    
make_universal(isNotNull, isNotNullImpl);
    
    
template <typename F, typename TKey, typename T, typename... TArgs, template <typename...>class C>
T findOneImpl(const C<T,TArgs...>& container, const F& f, const TKey& key)
{
    for (const auto& item : container)
       if (f(item, key))
           return item;
    return nullptr;
}
    
make_universal(ffind, findOneImpl);

First 3 methods are trivial – checking  that name or id fields are equal to given values and that whole object is not null.

The last one is find method inside container (we assume here that business data items are presented as immutable structures inside smart pointers). Find receives one function as validate functor and key argument to pass to this validator. Let’s see how to use it:

// example data
vector<User> users {make<User>(1, "John", 0), make<User>(2, "Bob", 1), make<User>(3, "Max", 1)};
        
users | (filter >> (isName >> "Bob")) | ucount | uprint; // 1
        
users | (filter >> (isId >> 13)) | ucount | uprint; // 0
        
vector<int>{1,2,6} | (fmap >> (ffind << users << isId)) | (filter >> isNotNull) | ucount | uprint; // 2

Such examples do not require an explanation I suppose!

We can convert user names to xml like this:

string xmlWrapImpl(string name, string item)
{
    return "<" + name + ">" + item + "</" + name + ">";
}
    
make_universal(xmlWrap, xmlWrapImpl);

// Produce XML
users | fmap >> [](User u){ return u->name; } | fmap >> (xmlWrap << "name") | reduce >> string("") >> sum | xmlWrap << "users" | print;

// result: <users><name>John</name><name>Bob</name><name>Max</name></users>

As you can see we can still use lambdas inside expressions.

FUNCTIONAL CHAINS

take-action

Now let’s add one more important element to proposed scheme. I want to be able to compose pipeline of functions, store it under some name and then call it multiple times as single function. In other words i want this:

auto countUsers = chain((fmap >> (ffind << users << isId)) | (filter >> isNotNull) | ucount);
        
vector<int>{1,2,6} | countUsers | (uprint << "count of users: ");

In fact this is simple functional composition (like the one discussed in appendix here ), and it can be implemented with ease in case of general functions. But when we are talking about templates things become a bit more complicated. But this is still possible!

// -------------------- chain of functors --------------------->
    
// The chain of functors ... is actualy just a tuple of functors
template <typename... FNs>
class fn_chain {
private:
        const std::tuple<FNs...> functions;
        
        template <std::size_t I, typename Arg>
        inline typename std::enable_if<I == sizeof...(FNs) - 1, decltype(std::get<I>(functions)(std::declval<Arg>())) >::type
        call(Arg arg) const
        {
            return std::get<I>(functions)(std::forward<Arg>(arg));
        }
        
        template <std::size_t N, std::size_t I, typename Arg>
        struct final_type : final_type<N-1, I+1, decltype(std::get<I>(functions)(std::declval<Arg>())) > {};
        
        template <std::size_t I, typename Arg>
        struct final_type<0, I, Arg> {
            using type = decltype(std::get<I>(functions)(std::declval<Arg>()));
        };
        
        
        template <std::size_t I, typename Arg>
        inline typename std::enable_if<I < sizeof...(FNs) - 1, typename final_type<sizeof...(FNs) - 1 - I, I, Arg>::type >::type
        call(Arg arg) const
        {
            return this->call<I+1>(std::get<I>(functions)(std::forward<Arg>(arg)));
        }
        
public:
        fn_chain() {}
        fn_chain(std::tuple<FNs...> functions) : functions(functions) {}
        
        // add function into chain
        template< typename F >
        inline auto add(const F& f) const -> fn_chain<FNs..., F>
        {
            return fn_chain<FNs..., F>(std::tuple_cat(functions, std::make_tuple(f)));
        }
        
        
        // call whole functional chain
        template <typename Arg>
        inline auto operator()(Arg arg) const -> decltype(this->call<0,Arg>(arg))
        
        {
            return call<0>(std::forward<Arg>(arg));
        }
        
};

How this works? When constructing such chain we just put functors into tuple. Tricky part comes when we need to call the function – we need to construct universal caller without knowing function specifications. This is possible using compile-time recursion and std::decltype/std::declval. Creating dummy arguments we go through whole chain recursively and detect final result type.

And to make it work under GCC i hit one of compiler bugs – inside call method recursion during type detection you need to add ‘this->‘ to make it compile (bug).

And to chain functors into the list we need to overload | operator again:

template<typename... FNs, typename F>
inline auto operator|(fn_chain<FNs...> && chain, F&& f) -> decltype(chain.add(f))
{
    return chain.add(std::forward<F>(f));
}

Now we can use this whole concept like:

// Use functional chain:
auto f1 = [](int x){ return x+3; };
auto f2 = [](int x){ return x*2; };
auto f3 = [](int x) { return (double)x / 2.0; };
auto f4 = [](double x) { return SS::toString(x); };
auto f5 = [](string s) { return "Result: " + s; };
auto testChain = fn_chain<>() | f1 | f2 | f3 | f4 | f5;
// execution:
testChain(3) | print;
        
auto countUsers = fn_chain<>() | (fmap >> (ffind << users << isId)) | (filter >> isNotNull) | ucount;
vector<int>{1,2,6} | countUsers | (uprint << "count of users: ");

Note that we use different types during chain execution.

So now we have the ability to store and combine pipelines as we like. Nice.

FINAL TOUCH – MONADIC PIPING (OPTIONAL)

This part is optional but it fits so well… because here will be very smooth shift to monads. Smooth and easy.

What if we change the direction of piping? Let’s pipe functions into data instead piping data into functions! Of cause, we can’t do this with raw data – we need some object to wrap it and call received functions for us. This object can do some additional manipulations with functions along the way. And yes, thats a kind of monad.

Why we need this kind of stuff? Because we can gain additional control of functional chain evaluation.

As example i’ll use maybe monad – which has very simple logic: if we have nullptr as output from any function in chain – we don’t execute further and report empty state. This is kind of implicit error protection.

Implementation will be a bit extended to support pointer and non-pointer types.

Also, this is not ‘true’ monad as true monadic bind operation requieres functions which return monad as result. But using the following implementation you can apply normal functions without any modifications.

// ------------------ maybe -------------------------->

enum class maybe_state { normal, empty };
    
template <typename T>
typename std::enable_if< std::is_object<decltype(T()) >::value, T>::type
set_empty() { return T(); }
    
template<> int set_empty<int>() { return 0; }
template<> string set_empty<string>() { return ""; }
    
template<typename T>
class maybe {
private:
        const maybe_state state;
        const T x;
        
        template <typename R>
        maybe<R> fromValue(R&& result) const
        {
            return maybe<R>(std::forward<R>(result));
        }
        
        template <typename R>
        maybe<std::shared_ptr<R>> fromValue(std::shared_ptr<R>&& result) const
        {
            if (result == nullptr)
                return maybe<std::shared_ptr<R>>();
            else
                return maybe<std::shared_ptr<R>>(std::forward<std::shared_ptr<R>>(result));
        }
        
       
public:
        // monadic return
        maybe(T&& x) : x(std::forward<T>(x)), state(maybe_state::normal) {}
        maybe() : x(set_empty<T>()), state(maybe_state::empty) {}
        
        // monadic bind
        template <typename F>
        auto operator()(F f) const -> maybe<decltype(f(std::declval<T>()))>
        {
            using ResultType = decltype(f(std::declval<T>()));
            if (state == maybe_state::empty)
                return maybe<ResultType>();
            return fromValue(f(x));
        }
         
        // extract value
        T getOr(T&& anotherValue) const { return (state == maybe_state::empty) ? anotherValue : x; };
};
    
template<typename T, typename F>
inline auto operator|(maybe<T> && monad, F&& f) -> decltype(monad(f))
{
    return monad(std::forward<F>(f));
}
    
    
template<typename T, typename TDefault>
inline T operator||(maybe<T> && monad, TDefault&& t)
{
    return monad.getOr(std::forward<TDefault>(t));
}
    
template <typename T>
maybe<T> just(T&& t)
{
    return maybe<T>(std::forward<T>(t));
}

This class can be extended to handle error messages and so on.

I use the same pipe | operator here because its ‘unix’ meaning is perfectly applicable here.

Examples:

maybe<int>(2) | (ffind << users << isId) | [](User u){ return u->name; } | [](string s){ cout << s << endl; return s; };

// Bob
        
(maybe<int>(6) | (ffind << users << isId) | [](User u){ return u->name; }).getOr("Not found") | (uprint << "User: ");

// User: Not found        

just(vector<int>{1,2,6}) | countUsers | [&](int count){ count | (uprint << "Count: "); return count; };

// Count: 2

So here we execute processing chain on non existing user and nothing bad happens. Also we can pipe our saved chain countUsers into maybe as expected.

I could produce a lot of other examples here, but may be this is nice topic for another post.

CONCLUSION

Using compile-time recursion and type-detection you can create powerful tools for combining templated functional blocks. Using currying and piping together with functional chains gives very flexible instrument to build compact functional-style methods in C++11. Monadic execution could be added to this scheme without any problems.

Full working sample on github:    gist

ps. About templating – i think usage of templates in production should be very minimalistic because template overuse can lead to very unmaintainable code. So when using proposed scheme keep in mind that all blocks should be very small and logically reasonable.

 

]]>
http://vitiy.info/templates-as-first-class-citizens-in-cpp11/feed/ 12
C++11 functional decomposition – easy way to do AOP http://vitiy.info/c11-functional-decomposition-easy-way-to-do-aop/ http://vitiy.info/c11-functional-decomposition-easy-way-to-do-aop/#comments Tue, 03 Feb 2015 11:41:31 +0000 http://vitiy.info/?p=461

This post is about making functional decomposition from perspective of Aspect Oriented Programming using C++11. If you are not familiar with ideas of AOP don’t be afraid – it’s rather simple concept, and by the end of this post you will understand the benefits of it.

You also can treat this post just as example how to use high-order functions in C++11.

In short – AOP tries to perform decomposition of every business function into orthogonal parts called aspects such as security, logging, error handling, etc. The separation of crosscutting concerns. It looks like:

Old picture about AOP

Old picture about AOP

Since C++11 supports high-order functions now we can implement factorization without any additional tools and frameworks (like PostSharp for C#).

You can scroll down to ‘what for’ chapter to check out the result to get more motivated.

PART 1 – TRIVIAL SAMPLE

Let’s start from something simple – one aspect and one function.

Here is simple lambda with trivial computation inside:

auto plus = [](int a, int b) { LOG << a + b << NL; };

I want to add some logging before and after computation. Instead of just adding this boilerplate code into function body let’s go other way. In C++11 we just can write high-order function which will take function as argument and return new function as result:

template <typename ...Args>
std::function<void(Args...)> wrapLog(std::function<void(Args...)> f)
{
    return [f](Args... args){
        LOG << "start" << NL;
        f(args...);
        LOG << "finish" << NL;
    };
}

Here we used std::function, variadic templates and lambda as result. (LOG, NL – my own logging stream and you can just change it with std::cout , std::endl or your another logging lib).

As i hoped to achieve the most simple and compact solution, i expected to use it like this:

auto loggedPlus = wrapLog(plus);

Unfortunately this will not compile. ‘no matching function to call ….’ The reason is that lambda is not std::function and automatic type conversion can’t be done. Of cause we can write something like this:

auto loggedPlus = wrapLog(static_cast<std::function<void(int,int)>>(plus));

This line will compile, but this is ugly… I hope cpp committee will fix this casting issue. Meanwhile, the best solution i found so far is the following:

template <typename Function>
struct function_traits
: public function_traits<decltype(&Function::operator())>
{};
    
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
    typedef ReturnType (*pointer)(Args...);
    typedef std::function<ReturnType(Args...)> function;
};
    
template <typename Function>
typename function_traits<Function>::function
to_function (Function& lambda)
{
    return typename function_traits<Function>::function(lambda);
}

This code is using type traits to convert anonymous lambda into std::function of same type. We can use it like this:

auto loggedPlus = wrapLog(to_function(plus));

Not perfect but much better. Finally we can call functional composition and get the result.

loggedPlus(2,3);

// Result:
// start
// 5
// finish

Note: if we had declared aspect function without variadic template we could compose functions without to_function() conversion, but this would kill the benefit from writing universal aspects discussed further.

PART 2 – REALISTIC EXAMPLE

Introduction is over, let’s start some more real-life coding here. Let’s assume we want to find some user inside database by id. And while doing that we also want log the process duration, check that requesting party is authorised to perform such request (security check), check for database request fail, and, finally, check in local cache for instant results.

And one more thing – i don’t want to rewrite such additional aspects for every function type. So let’s write them using variadic templates and get as universal methods as possible.

Ok, let’s start. I will create some dummy implementation for additional classes like User, etc. Such classes are only for example and actual production classes might be completely different, like user id should not be int, etc.

Sample User class as immutable data:

// Simple immutable data
class UserData {
public:
    const int id;
    const string name;
    UserData(int id, string name) : id(id), name(name) {}
};
    
// Shared pointer to immutable data
using User = std::shared_ptr<UserData>;

Let’s emulate database as simple vector of users and create one method to work with it (find user by id):

vector<User> users {make<User>(1, "John"), make<User>(2, "Bob"), make<User>(3, "Max")};

auto findUser = [&users](int id) -> Maybe<User> {
    for (User user : users) {
        if (user->id == id)
            return user;
    }
    return nullptr;
};

make<> here is just shortcut for make_shared<>, nothing special.

Maybe<> monad

You, probably, noticed that return type of request function contains something called Maybe<T>. This class is inspired by Haskell maybe monad, with one major addition. Instead of just saving Nothing state and Content state, it also might contain Error state.

At first, here is sample type for error description:

/// Error type - int code + description
class Error {
public:
    Error(int code, string message) : code(code), message(message) {}
    Error(const Error& e) : code(e.code), message(e.message) {}

    const int code;
    const string message;
};

Here is minimalistic implementation of Maybe:

template < typename T >
class Maybe {
private:
    const T data;
    const shared_ptr<Error> error;
public:
    Maybe(T data) : data(std::forward<T>(data)), error(nullptr) {}
    Maybe() : data(nullptr), error(nullptr) {}
    Maybe(decltype(nullptr) nothing) : data(nullptr), error(nullptr) {}
    Maybe(Error&& error) : data(nullptr), error(make_shared<Error>(error)) {}
        
    bool isEmpty() { return (data == nullptr); };
    bool hasError() { return (error != nullptr); };
    T operator()(){ return data; };
    shared_ptr<Error> getError(){ return error; };
};
    
template <class T>
Maybe<T> just(T t)
{
    return Maybe<T>(t);
}

Note, that you don’t have to use Maybe<> and here it’s used only for example.

Here we also use the fact that nullptr in C++11 has it’s own type. Maybe has defined constructor from that type producing nothing state. So when you return result from findUser function, there is no need for explicit conversion into Maybe<> – you can just return User or nullptr, and proper constructor will be called.

Operator () returns possible value without any checks, and getError() returns possible error.

Function just() is used for explicit Maybe<T> construction (this is standard name).

Logging aspect

First, let’s rewrite log aspect so it will calculate execution time using std::chrono. Also let’s add new string parameter as name for called function which will be printed to log.

template <typename R, typename ...Args>
std::function<R(Args...)> logged(string name, std::function<R(Args...)> f)
{
        return [f,name](Args... args){
           
            LOG << name << " start" << NL;
            auto start = std::chrono::high_resolution_clock::now();
            
            R result = f(std::forward<Args>(args)...);
            
            auto end = std::chrono::high_resolution_clock::now();
            auto total = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
            LOG << "Elapsed: " << total << "us" << NL;
            
            return result;
        };
}

Note std::forward here for passing arguments more clean way. We don’t need to specify return type as Maybe<R> because we don’t need to perform any specific action like error checking here.

‘Try again’ aspect

What if we have failed to get data (for example, in case of disconnect). Let’s create aspect which will in case of error perform same query one more time to be sure.

// If there was error - try again
template <typename R, typename ...Args>
std::function<Maybe<R>(Args...)> triesTwice(std::function<Maybe<R>(Args...)> f)
{
        return [f](Args... args){
            Maybe<R> result = f(std::forward<Args>(args)...);
            if (result.hasError())
                return f(std::forward<Args>(args)...);
            return result;
        };
}

Maybe<> is used here to identify error state. This method can be extended – we could check error code and decide is there any sense to perform second request (was it network problem or database reported some format error).

Cache aspect

Next thing – let’s add client side cache and check inside it before performing actual server-side request (in functional world this is called memoization). To emulate cache here we can just use std::map:

map<int,User> userCache;

// Use local cache (memoize)
template <typename R, typename C, typename K, typename ...Args>
std::function<Maybe<R>(K,Args...)> cached(C & cache, std::function<Maybe<R>(K,Args...)> f)
{
        return [f,&cache](K key, Args... args){
            // get key as first argument
            
            if (cache.count(key) > 0)
                return just(cache[key]);
            else
            {
                Maybe<R> result = f(std::forward<K>(key), std::forward<Args>(args)...);
                if (!result.hasError())
                    cache.insert(std::pair<int, R>(key, result())); //add to cache
                return result;
            }
        };
}

This function will insert element into cache if it was not there. Here we used that knowledge that cache is std::map, but it can be changed to any key-value container hidden behind some interface.

Second important part, we used only first function argument here as key. If you have complex request where all parameters should act as composite key – what to do? It’s still possible and there are a lot of ways to make it. First way is just to use std::tuple as key (see below). Second way is to create cache class which will allow several key parameters. Third way is to combine arguments into single string cache using variadic templates. Using tuple approach we can rewrite it like this:

map<tuple<int>,User> userCache;

// Use local cache (memoize)
template <typename R, typename C, typename ...Args>
std::function<Maybe<R>(Args...)> cached(C & cache, std::function<Maybe<R>(Args...)> f)
{
        return [f,&cache](Args... args){
            
            // get key as tuple of arguments
            auto key = make_tuple(args...);
            
            if (cache.count(key) > 0)
                return just(cache[key]);
            else
            {
                Maybe<R> result = f(std::forward<Args>(args)...);
                if (!result.hasError())
                    cache.insert(std::pair<decltype(key), R>(key, result())); //add to cache
                return result;
            }
        };
}

Now it’s much more universal.

Security aspect

Never forget about security. Let’s emulate user session with some dummy class –

class Session {
public:
    bool isValid() { return true; }
} session;

Security checking high-order function will have additional parameter – session. Checking will only verify that isValid() field is true:

// Security checking
template <typename R, typename ...Args, typename S>
std::function<Maybe<R>(Args...)> secured(S session, std::function<Maybe<R>(Args...)> f)
{
        // if user is not valid - return nothing
        return [f, &session](Args... args) -> Maybe<R> {
            if (session.isValid())
                return f(std::forward<Args>(args)...);
            else
                return Error(403, "Forbidden");
        };
}

‘Not empty’ aspect

Last thing in this example – let’s treat not found user as error.

// Treat empty state as error
template <typename R, typename ...Args>
std::function<Maybe<R>(Args...)> notEmpty(std::function<Maybe<R>(Args...)> f)
{
        return [f](Args... args) -> Maybe<R> {
            Maybe<R> result = f(std::forward<Args>(args)...);
            if ((!result.hasError()) && (result.isEmpty()))
                return Error(404, "Not Found");
            return result;
        };
}

Im not writing here about error handling aspect, but it’s also can be implemented via same approach. Note that using error propagation inside Maybe<> monad you can avoid using exceptions and define your error processing logic different way.

Multithread lock aspect

template <typename R, typename ...Args>
std::function<R(Args...)> locked(std::mutex& m, std::function<R(Args...)> f)
{
    return [f,&m](Args... args){
        std::unique_lock<std::mutex> lock(m);
        return f(std::forward<Args>(args)...);
    };
}

No comments.

FINALLY

Finally, what for was all this madness?  FOR THIS LINE:

// Aspect factorization

auto findUserFinal = secured(session, notEmpty( cached(userCache, triesTwice( logged("findUser", to_function(findUser))))));

Checking (let’s find user with id 2):

auto user = findUserFinal(2);
LOG << (user.hasError() ? user.getError()->message : user()->name) << NL;

// output:
// 2015-02-02 18:11:52.025 [83151:10571630] findUser start
// 2015-02-02 18:11:52.025 [83151:10571630] Elapsed: 0us
// 2015-02-02 18:11:52.025 [83151:10571630] Bob

Ok, let’s perform tests for several users ( here we will request same user twice and one non-existing user ):

auto testUser = [&](int id) {
    auto user = findUserFinal(id);
    LOG << (user.hasError() ? "ERROR: " + user.getError()->message : "NAME:" + user()->name) << NL;
};

for_each_argument(testUser, 2, 30, 2, 1);

//2015-02-02 18:32:41.283 [83858:10583917] findUser start
//2015-02-02 18:32:41.284 [83858:10583917] Elapsed: 0us
//2015-02-02 18:32:41.284 [83858:10583917] NAME:Bob
//2015-02-02 18:32:41.284 [83858:10583917] findUser start
//2015-02-02 18:32:41.284 [83858:10583917] Elapsed: 0us
// error:
//2015-02-02 18:32:41.284 [83858:10583917] ERROR: Not Found
// from cache:
//2015-02-02 18:32:41.284 [83858:10583917] NAME:Bob
//2015-02-02 18:32:41.284 [83858:10583917] findUser start
//2015-02-02 18:32:41.284 [83858:10583917] Elapsed: 0us
//2015-02-02 18:32:41.284 [83858:10583917] NAME:John

As you can see it’s working as intended. It’s obvious that we got a lot of benefits from such decomposition. Factorisation leads to decoupling of functionality, more modular structure and so on. You gain more focus on actual business logic as result.

We can change order of aspects as we like. And as we made aspect functions rather universal we can reuse them avoiding a lot of code duplication.

Instead of functions we can use more sophisticated functors (with inheritance), and instead of Maybe<> also could be more complex structure to hold some additional info. So whole scheme is extendable.

Note also, that you can pass lambdas as additional aspect parameters.

Working sample to play with: github gist or  ideone

Ps. BONUS:

template <class F, class... Args>
void for_each_argument(F f, Args&&... args) {
    (void)(int[]){(f(forward<Args>(args)), 0)...};
}

 

]]>
http://vitiy.info/c11-functional-decomposition-easy-way-to-do-aop/feed/ 13
Small presentation of my cross-platform engine for mobile and desktop applications http://vitiy.info/small-presentation-of-my-cross-platform-engine-for-mobile-and-desktop-applications/ http://vitiy.info/small-presentation-of-my-cross-platform-engine-for-mobile-and-desktop-applications/#comments Wed, 21 Jan 2015 14:50:39 +0000 http://vitiy.info/?p=444 I made small presentation about my cross-platform engine for mobile and desktop applications. Codename Kobald. Click on image to play it in new window (use arrows and space to move through):

Screenshot 2015-01-21 21.53.14

This is not-so-technical presentation and main info about engine will come later as separate post.

]]>
http://vitiy.info/small-presentation-of-my-cross-platform-engine-for-mobile-and-desktop-applications/feed/ 10
10 ways to not shoot yourself in the foot using C++11 http://vitiy.info/ten-ways-to-not-shoot-yourself-in-the-foot-using-cpp11/ http://vitiy.info/ten-ways-to-not-shoot-yourself-in-the-foot-using-cpp11/#comments Tue, 13 Jan 2015 18:17:06 +0000 http://vitiy.info/?p=425

Within C++, there is a much smaller and cleaner language struggling to get out (Stroustrup)

The following text could be modified – current rev.1.0

Very often i hear from java/erlang/etc people that C++ is so bad that it is very unwise to use so-old-school language now, when we have more ‘safe’ higher level languages. Everybody heard about foot-shooting using C++.  What about C++11?

Bjarne said that C++11 feels like whole new language and, at first, i did not take it seriously as modifications looked more as minor additions (especially for boost users). Now i changed my mind – using new features combined together can transform your way of coding into new form. I’m talking not about adding new features to your code, but about changing your coding style.

How not to shoot yourself in the foot? Here is the list of my rules to make the C++ coding life sweet and easy. This is simple convention to follow and can be adopted very fast. Not only it gives more stable implementation but also more clean and understandable design.

This convention is composition of Scott Meyers rules, Functional programming ideas and reducing-complexity ideology by Steve McConnell.

This convention adds minor overhead to implementation so when you really need to optimise minor parts of your code you can skip some rules. Also there are some cases when you can skip the rules as they will produce less maintainable solutions (see descriptions).

Some rules have strong form – more profit and a bit more overhead. And if you follow strong forms C++ will truly feel like a different language.

All this is discussable as its only my own solution and can be corrected and improved. You are welcome to add some comments below.

RULES

Rule 1 – Use RAII and smart pointers only! (Strong: use only std::shared_ptr and RAII) 

Memory management is one of most referenced problems of C++ – working with raw pointers is like dancing with blades. To solve this automatically we have two approaches: GC from java/C# or Objective-C’s reference counting. I prefer reference counting as more controllable solution – so use smart pointers everywhere (or no pointers at all using RAII).

Strong version: use shared_ptr for every pointer to prevent mistakes with passing of ownership. This makes additional copy overhead but this is the prices for safety. Only when you need to optimise some bottlenecks you can bypass them.

You have to keep shared pointer specific in mind. First problem with reference counting is situation when there is ownership cycle between two classes. This situation could be reproduced inside special data structures only and should not happen at normal conditions. Typically if you have such pointer ring this is indication of bad design. Second problem is how not to keep some data as zombie. To avoid this you just need not to store pointers to data inside long living objects (as cache or something). So don’t treat smart pointers as some magic – logic for shared_ptr is quite simple.

Last thing – remember that in multithread environment only composition of immutable data/thread-safe data and shared pointers can lead to safe implementation.

Rule 2 – Use const where its possible (Strong: use immutable data only)

Making things const can reduce entropy inside your code. If method requires input parameter as const – mark it so. If method does not affect class – mark it const. If class field can be marked const – do so. This not only gives compiler more space for optimisations, but reduces the chance to make some unwanted modifications to zero.

Common mistakes when working with modified object state can be prevented using approach from functional programming – make whole your data immutable. This even solves problems with concurrent access from different threads.

By immutable data class i mean class with const fields (which are inited during creation) and no default empty constructor.

class UserData {
public:
    const int id;
    const int value;
    const string name;

    UserData(const int id, const int value, const string name) : id(id), value(value), name(name) {}
};

Such declaration can be generated by macro which can contain copy constructors, serializators/deserializators, etc. Note that move semantics is not applicable to immutable structures as move modifies source object and immutable object can’t be modified.

You can have shared_ptr as container for your immutable data to save space and resources while passing data through processing chain. You can even wrap all business classes into shared pointers and accept convention that your data classes are wrapped by default.

using User = std::shared_ptr<UserData>;

If you are familiar with convention where you put Ptr at end of smart pointer class names to make codes understand that its pointer, you would argue here that this will reduce readability. But actually if you do it for whole business domain it will on the contrary make thing more compact and understandable when you work with functional processing.

There are some cases where some algorithms can be expressed in a lot more compact way when some variable inside is mutable. Even if you decided to go that way for readability or speed make sure to cover this part with tests with additional caution.

Rule 3 – Use make_shared() instead of ‘new‘ for shared pointers

To get rid of new/delete notation completely use make_shared for smart pointers. About benefits of make_shared relating to memory allocation you can read in documentation.

As make_shared requires class type as template parameter one can add some sugar as optional step:

template <class T, class... P>
inline auto make(P&&... args) -> T 
{
    return std::make_shared<typename T::element_type>(std::forward<P>(args)...);
}
    
template <class T, class... P>
inline void make(shared_ptr<T> & sharedValue, P&&... args)
{
    sharedValue = make<shared_ptr<T> >(std::forward<P>(args)...);
}

And init objects like:

make(a,10);
make(b,{50,10,35});

Note that you should have no destruction functions.

Rule 4 – Use for(const auto& x :X) instead of old school cycles (Strong: use indexed cycles in simple pure functions only)

Instead of old indexed ‘for’ cycles use C++11 foreach approach: for(const auto& x :X). When you have no explicit cycle index you can make no range mistakes. And this notation has more readable form. Instead of auto you can use class name if this is needed for improving readability. Also note optional keyword const here and, of course, you can skip & sign here. For more details read Scott Meyers.

Your custom collections can be extended to support for(:) with ease:

/// Custom iterator for c++11 cycles
    class Iterator {
        T* data;
        int position;
    public:
        Iterator(T* _data, int _position):data(_data),position(_position) {}
        
        T& operator*() { return data[position]; }
        Iterator& operator++() { ++position; return *this; }
        bool operator!=(const Iterator& it) const { return position != it.position; }
    };

    Iterator begin() { return { items, 0 }; }
    Iterator end()   { return { items, mCount }; }
    
    /// Custom iterator for c++11 cycles (Const version)
    class IteratorConst {
        T* data;
        int position;
    public:
        IteratorConst(T* _data, int _position):data(_data),position(_position) {}
        
        const T& operator*() const { return data[position]; }
        IteratorConst& operator++() { ++position; return *this; }
        bool operator!=(const IteratorConst& it) const { return position != it.position; }
    };
    
    IteratorConst begin() const { return { items, 0 }; }
    IteratorConst end()   const { return { items, mCount }; }

Strong version: all algorithms which require some indexed cycles should be implemented as low level functions and should be called in functional style. Like map(), filter(), reduce(), etc. This step requires a bit functional approach as you have to separate iteration algorithm and cycle body. Body should remain in business domain while cycle iteration itself must be moved to low utility level. Next rule is linked to this.

Rule 5 – Use functional approach to work with your data

First, if you are not yet familiar with functional programming read some books on it – like Thinking Functional (books even could be not related directly to C++). You don’t have to master functional programming, but only get basic foundation principles and understanding of benefits of functional data processing in modern concurrent environments. My position is that you have to combine old OOP paradigm and FP to get the best parts from both of them.

C++11 has std::function, lambdas, closures, etc. Use it! Forget about pointer to functions. Forget about structures you pass to events. Forget about that old stuff which looked more like workarounds. Yes, C++11 will not bring so minimalistic functional code to have fun with, but its enough to implement all the stuff. And even more – you can create your own container class extension methods to work with arrays to make things a lot more compact and shiny. For example, here is the code to get square images from collection:

return images.filter([](Image image){ return (image->isSquare()); }).notDeleted();

Or you can add each() method to the list class to call function for each element:

/// calls function for each element
inline MVList<T> each(std::function<void(T)> f) const
{
    if (mCount == 0) return *this;
    for (int i = 0; i < mCount; i++)
        f(items[i]);
    return *this;
}

Here i used old indexed cycle to show that this iteration can be encapsulated. When working with such collection you can call only functional-style methods and don’t know nothing about how exactly iteration is made inside. This reduces complexity.

If you are not familiar with lambdas there is one point to know about: you have to control the way you do closures. If you have experience with JS you probably got situations when lambda is inside lambda inside lambda and so on and pass data through this madness. Such unreadable and not maintainable situation should be avoided as much as large number of inner cycles.

Data processing with FP leads to a lot of copy constructing overhead. Good idea is to use shared  pointers to immutable data here.

Last thing here: there are cases when FP is not so suitable. Don’t try to use functional paradigm as hummer everywhere.

Rule 6 – Use auto to compact code and prevent type casting mistakes

But use it with care. First when i hear about auto i thought its a bad thing, because it would produce unreadable code. And it seemed a bit of violation of strong typing. But in practice it appeared quite usable, because there are a lot of cases where you understand what type you have. Often the name of your variable is almost the same as the name of class.

Rare cases when you have a lot of autos grouped together and you feel readability can suffer from it – don’t use it.

Unexpectedly, auto can reveal some type casting issues. This is an additional benefit. You can read Scott Meyers latest book about it to get details.

Rule 7 – Use uniform initalization instead of ‘=’

There are pros and cons inside Scott Meyers book for so called uniform initialisation, but i see it as one of steps forward. It contains strict checks and has more flexible notation. When needed you can define constructors from std::initializer_list to get more code beauty.

MVList<int> set{5, 129, 14, 130, 33, 132};

Initialisation is looking more logical with immutable structures when in fact you can’t reassign them using ‘=’ as they are untouchable.

Rule 8 – Use nullptr instead of NULL and don’t forget to check pointers

Looks like the simplest rule in list? No. Here should be discussed one important linked problem to care about. When you work with shared pointers and the result of your function can contain nullptr elements you can get crash when try to access null-pointer data. How to avoid this?

First, you can add notNull() method to list class to filter ‘not null’ elements inside your processing chain. But this will not cover all cases. Unfortunately, old way to check things ( if (a != nullptr) { … } ) is still alive and in large range of cases is the most compact way to go. The problem is that functional approach from math is not so compatible with if-branches. Structures like Either in FP are not perfect imho. So this is the place to add some modifications to this list.

Rule 9 – Use templates instead of MACRO when its possible (Strong: use functional factorization instead of template hell)

As C++11 has variadic templates now – so you can cover a lot more cases where previously we had to use macros.

But there is important thing about template programming! Every time you want to use generics think twice if its the only way to make decomposition? One of the most hated things about C++ is its complexity. You might read couple of books like Alexandrescu’s and feel some kind of new flexibility using templates everywhere. But in practice when you use more than one template argument things become less maintainable. I suggest use templates only when you can’t implement your task without them. Best solution would be pure factorization in functional style, but its not possible in large set of cases (even in math). If you have to use generics do it the way so you can fully encapsulate composite structure and keep template arguments to minimum (preferably only one argument). Also class should have obvious purpose for being templated (nice example is object collection of specific type). Remember that your fellow programmers don’t have to make guesses and WTFs looking at code. So avoid overtemplating.

Rule 10 – MINOR RULES

  • Use features from std lib (threads, etc) instead of third party libs
  • Write your classes to avoid destrutors (Rule of zero)
  • Use “using” instead of “typedef” to improve readability (and it can be templated)
  • Use scoped enums to improve readability and to create more type safe code
  • Use =delete; for obsolete and unwanted functions
  • Use override/final

Conclusion

Using new features of C++11 together plus changing your habits and way of thinking to more functional way, gives you whole new C++ perspective. Keeping in mind the advantages of C++ as fast cross-platform solution, and that quite simple convention rules can shift it close to functional languages in terms of stability, makes C++11 good player on market. So now its more your choice to shoot yourself in the foot or not if you have nice C++11 gun.

PS. Im not talking here that C++11 is the best. No no no. But it is definitely not ugly monster as the most people think now. Especially if you wash it a bit.

This list can be extended and modified as my vision might be changed. If you have some suggestions feel free to comment.

]]>
http://vitiy.info/ten-ways-to-not-shoot-yourself-in-the-foot-using-cpp11/feed/ 2
Writing custom protocol for nanomsg http://vitiy.info/writing-custom-protocol-for-nanomsg/ http://vitiy.info/writing-custom-protocol-for-nanomsg/#comments Tue, 09 Dec 2014 11:24:04 +0000 http://vitiy.info/?p=397 Custom protocol for nanomsg

Nanomsg is next version of ZeroMQ lib, providing smart cross-platform sockets for implementation of distributed architectures. Here you can find basic examples of included protocols (communication patterns). Lib is simple (written in pure C) and does not have any dependencies like boost. And as this is at least 3rd iteration from same author you can expect some quality/performance here.

This is kind of solution for the hell of writing of your own serious socket server. If you already had such experience you should understand the range of problems which are not so obvious at start. But here we expect to skip all such problems and go straight to processing messages. Lib handles automatic reconnection in case of link disconnects, nonblocking receiving/sending, sockets which can handle large set of clients, etc. All this seems like perfect solution for server-side inner transport of fast distributed architectures.

But i also want to try it outside. The basic communication patterns (PAIR, BUS, REQREP, PUBSUB, PIPELINE, SURVEY) may fit large set of inner server transport schemes, but there are some minor limits in current implementation for client side application. I mean limits of protocols, not the lib itself.

Unfortunately, current version of PUBSUB protocol does filtering on subscriber side. So ‘subscribing clients’ will receive all message flow and this is unbearable for me.

BUS protocol requires full-linked scheme:

nanomsg bus protocol

I expect BUS-like protocol to work in more sparse conditions.

As nanomsg is open-source lib under nice licence (MIT/X11 license) – first thought was to extend some of existing protocols to meet my needs.

Why new protocol?

As i wanted to try these smart sockets for external clients, to meet today’s reality i’m assuming each client has set of devices, which are connected simultaneously to some network service.

At first i aimed to create some complex routing protocol, but than came up with more simple approach: I want to create custom protocol as fusion of BUS and SUB/PUB protocols (here i refer it as SUBBUS).

Scheme:

SUBBUS Protocol Scheme 1

 

Black lines are initial connections. Coloured lines are messages. This scheme contains 2 clients Bob and John. John has 2 devices and Bob is geek, so he has 4 devices simultaneously connected to server node. Each message from client device goes to other devices of same client. You can look at this scheme as two BUS protocols separated by subscription.

This gives ability to perform instant cloud synchronisation, simultaneous operation from multiple devices and other various fun stuff.

Possible inner structure (there can other ways):

  • Each node has the list of subscriptions (socket option as list of strings) i.e. /users/john/ or /chats/chat15/.
  • Subscription filtering is done on sending side (This is important if you have large number of clients – each of them don’t have to receive all messages. Not only for saving bandwidth but also for security reasons.) So client should somehow send his subscription list to server (subscription forwarding). In case of reconnect this information should be also resent again. While subscriptions were not sent client should receive nothing.
  • Each message should contain routing prefix (header) i.e. /users/john/ or /chats/chat15/
  • Each node should have tree of connected client subscriptions which contains pipe lists as leafs. Sending operation uses this tree to send to subscribed range of clients.
  • Each message from client node should be transmitted to other nodes within same subscription (forwarding). This is done before server side processing and aimed to speed up message propagation between devices. Some optional filters can be added here.
  • [Optional] SSL-like encryption for each pipe
  • All this stuff should be as simple as possible

Its not too complicated to start writing your own protocol for nanomsg. The only problem is that lib is written in pure C – so you must be a bit ready for it. Go to src/protocols folder. It contains all protocols sources you can explore. Mostly they simply implement the list of given methods, which are described inside src/protocol.h:

/*  To be implemented by individual socket types. */
struct nn_sockbase_vfptr {

    /*  Ask socket to stop. */
    void (*stop) (struct nn_sockbase *self);

    /*  Deallocate the socket. */
    void (*destroy) (struct nn_sockbase *self);

    /*  Management of pipes. 'add' registers a new pipe. The pipe cannot be used
        to send to or to be received from at the moment. 'rm' unregisters the
        pipe. The pipe should not be used after this call as it may already be
        deallocated. 'in' informs the socket that pipe is readable. 'out'
        informs it that it is writable. */
    int (*add) (struct nn_sockbase *self, struct nn_pipe *pipe);
    void (*rm) (struct nn_sockbase *self, struct nn_pipe *pipe);
    void (*in) (struct nn_sockbase *self, struct nn_pipe *pipe);
    void (*out) (struct nn_sockbase *self, struct nn_pipe *pipe);

    /*  Return any combination of event flags defined above, thus specifying
        whether the socket should be readable, writable, both or none. */
    int (*events) (struct nn_sockbase *self);

    /*  Send a message to the socket. Returns -EAGAIN if it cannot be done at
        the moment or zero in case of success. */
    int (*send) (struct nn_sockbase *self, struct nn_msg *msg);

    /*  Receive a message from the socket. Returns -EAGAIN if it cannot be done
        at the moment or zero in case of success. */
    int (*recv) (struct nn_sockbase *self, struct nn_msg *msg);

    /*  Set a protocol specific option. */
    int (*setopt) (struct nn_sockbase *self, int level, int option,
        const void *optval, size_t optvallen);

    /*  Retrieve a protocol specific option. */
    int (*getopt) (struct nn_sockbase *self, int level, int option,
        void *optval, size_t *optvallen);
};

So you can just clone some protocol as base foundation for your own – i took bus folder and cloned it to subbus. I renamed everything inside from ‘bus’ to ‘subbus’ using find/replace. In root src folder there is bus.h file which contains only list of consts for protocol access. You also need to clone it under your new protocol name (subbus.h in my case). Next steps are to add new protocol to makefile and socket types list.

Add to makefile.am:

NANOMSG_PROTOCOLS = \
    $(PROTOCOLS_BUS) \
    $(PROTOCOLS_SUBBUS) \ .....

PROTOCOLS_SUBBUS = \
    src/protocols/subbus/subbus.h \
    src/protocols/subbus/subbus.c \
    src/protocols/subbus/xsubbus.h \
    src/protocols/subbus/xsubbus.c

Add protocol to /core/symbol.c

{NN_BUS, "NN_BUS", NN_NS_PROTOCOL,
        NN_TYPE_NONE, NN_UNIT_NONE},
{NN_SUBBUS, "NN_SUBBUS", NN_NS_PROTOCOL,
        NN_TYPE_NONE, NN_UNIT_NONE},

Add protocol’s socket types into supported list inside /core/global.c (don’t forget includes):

/*  Plug in individual socktypes. */
  
...
    nn_global_add_socktype (nn_bus_socktype);
    nn_global_add_socktype (nn_xbus_socktype);
    nn_global_add_socktype (nn_subbus_socktype);
    nn_global_add_socktype (nn_xsubbus_socktype);

After that i grabbed one of examples for bus protocol from here and changed socket creation part:

#include "../nanomsg/src/subbus.h"

int node (const int argc, const char **argv)
{
  int sock = nn_socket (AF_SP, NN_SUBBUS);
  if (sock < 0)
  {
    printf ("nn_socket failed with error code %d\n", nn_errno ());
    if (errno == EINVAL) printf("%s\n", "Unknown protocol");
  }

...

After that sample should compile and work. If you failed to add your protocol copy to socket types list you will get Unknown protocol error.

Here is complete Dockerfile i use to build&run simple test. It gets latest nanomsg from github, modifies sources to include new protocol, copies protocol source from host, builds the lib and protocol test.

# THIS DOCKERFILE COMPILES Custom Nanomsg protocol + sample under Ubuntu
 
FROM ubuntu

MAINTAINER Victor Laskin "victor.laskin@gmail.com"

# Install compilation tools

RUN apt-get update && apt-get install -y \
    automake \
    build-essential \
    wget \
    p7zip-full \
    bash \
    curl \
    git \
    sed \
    libtool

# Get latest Nanomsg build from github

RUN mkdir /nanomsg && cd nanomsg
WORKDIR /nanomsg

RUN git clone https://github.com/nanomsg/nanomsg.git && ls


# Modify nanomsg files to register new protocol

RUN cd nanomsg && sed -i '/include "..\/bus.h"/a #include "..\/subbus.h"' src/core/symbol.c && \
	sed -i '/"NN_BUS", NN_NS_PROTOCOL,/a NN_TYPE_NONE, NN_UNIT_NONE}, \n\
    {NN_SUBBUS, "NN_SUBBUS", NN_NS_PROTOCOL,' src/core/symbol.c && \
	cat src/core/symbol.c && \
	sed -i '/#include "..\/protocols\/bus\/xbus.h"/a #include "..\/protocols\/subbus\/subbus.h" \n\#include "..\/protocols\/subbus\/xsubbus.h"' src/core/global.c && \
	sed -i '/nn_global_add_socktype (nn_xbus_socktype);/a nn_global_add_socktype (nn_subbus_socktype); \n\
    nn_global_add_socktype (nn_xsubbus_socktype);' src/core/global.c && \
	cat src/core/global.c | grep nn_global_add_socktype

# Modify Makefile.am 

RUN cd nanomsg && sed -i '/xbus.c/a \\n\
PROTOCOLS_SUBBUS = \\\n\
    src/protocols/subbus/subbus.h \\\n\
    src/protocols/subbus/subbus.c \\\n\
    src/protocols/subbus/xsubbus.h \\\n\
    src/protocols/subbus/xsubbus.c \n\
    \\
    ' Makefile.am && \
    sed -i '/$(PROTOCOLS_BUS)/a $(PROTOCOLS_SUBBUS) \\\
    ' Makefile.am && cat Makefile.am 


# This is temporal fix - DISABLE STATS
RUN sed -i '/nn_global_submit_statistics ();/i if (0)' nanomsg/src/core/global.c

# Get custom protocol source (copy from host)

RUN mkdir nanomsg/src/protocols/subbus
COPY subbus.h /nanomsg/nanomsg/src/
COPY subbus/*.c /nanomsg/nanomsg/src/protocols/subbus/
COPY subbus/*.h /nanomsg/nanomsg/src/protocols/subbus/

# Build nanomsg lib

RUN cd nanomsg && ./autogen.sh && ./configure && make && ls .libs

# Get and build custom protocol test

RUN mkdir test
COPY testsubbus.c /nanomsg/test/
COPY test.sh /nanomsg/test/
RUN cd test && ls && gcc -pthread testsubbus.c ../nanomsg/.libs/libnanomsg.a -o testbus -lanl && ls

# Set port and entry point

EXPOSE 1234 1235 1236 1237 1238 1239 1240
ENTRYPOINT cd /nanomsg/test/ && ./test.sh

Note: the lib is still beta (0.5-beta, released on November 14th, 2014) so you could expect something yet not polished there. Inside script you could find the line which disables statistics as it has some blocking bug at the moment but i expect it to be fixed very soon as the fix was pulled already.

Docker is optional way to build this, of course, and you can modify this Dockerfile to simple client script. Don’t forget to change the name of your protocol.

Modifications i made

I will not paste here the cuts of source code as it will make the post too messy. This is plain old C so even simple things tend to be a bit longer there. So i will note some main steps of my implementation. Keep in mind that thats only my approach and everything can be done another way. 

I modified nn_xsubbus_setopt to set subscriptions (i use linked list to store the list of local subscriptions).

I have two trees to speed up all process of communication routing. First tree contains descriptions of client subscriptions by pipe id (nn_pipe*). Also it contains the flag if this node’s subscriptions were sent to this pipe for first time. To make this tree more balanced i use some hash of pointer to pipe as binary tree key.

This tree is used in nn_xsubbus_addnn_xsubbus_rmnn_xsubbus_out functions to synchronise subscription lists. nn_xsubbus_add is called when new pipe is connected and there we add new leaf into the tree. nn_xsubbus_out tells that pipe is writable so we can send our list of subscriptions to other side (if we have not already done it). nn_xsubbus_rm – pipe was removed.

Second tree is used for main sending operation and gives the list of pipes by subscription string key. As starting point i took triple tree where each node contains actual list of connected pipes. nn_xsubbus_send method splits header from each message and sends it to corresponding tree part.

When new message arrives inside nn_xsubbus_recv there is check of header, and if it starts from special mark of the list of subscriptions – we add this list into the second tree. If message is ‘normal’ there is sending to other pipes of same subscription (message forwarding as BUS protocol wants).

Note, that trees should work as persistent trees in multithread environment. I prefer some non locking structures here. Current implementation does not clean up chains of disconnected leafs (just removes the pipes) to achieve this simple way. Some tree rebalancing algorithm would be nice to add in future.

As test i slightly modified bus test sample to set subscription from argv[2] as socket option and prepend message by current subscription.

./testbus node0 / tcp://127.0.0.1:1234 & node0=$!
./testbus node1 /USER/JOHN/ tcp://127.0.0.1:1235 tcp://127.0.0.1:1234 & node1=$!
./testbus node2 /USER/BOB/ tcp://127.0.0.1:1236 tcp://127.0.0.1:1234 & node2=$!
./testbus node3 /USER/JOHN/ tcp://127.0.0.1:1237 tcp://127.0.0.1:1234 & node3=$!
./testbus node4 /USER/BOB/ tcp://127.0.0.1:1238 tcp://127.0.0.1:1234 & node4=$!
./testbus node5 /USER/BOB/ tcp://127.0.0.1:1239 tcp://127.0.0.1:1234 & node5=$!
./testbus node6 /USER/BOB/ tcp://127.0.0.1:1240 tcp://127.0.0.1:1234 & node6=$!

Here is the part of test output (for Bob):

node5: RECEIVED '/USER/BOB/=node2 18' 20 FROM BUS
node4: RECEIVED '/USER/BOB/=node2 18' 20 FROM BUS
node6: RECEIVED '/USER/BOB/=node2 18' 20 FROM BUS
node2: RECEIVED '/USER/BOB/=node5 18' 20 FROM BUS
node5: RECEIVED '/USER/BOB/=node6 18' 20 FROM BUS
node4: RECEIVED '/USER/BOB/=node5 18' 20 FROM BUS
node6: RECEIVED '/USER/BOB/=node5 18' 20 FROM BUS
node2: RECEIVED '/USER/BOB/=node6 18' 20 FROM BUS
node5: RECEIVED '/USER/BOB/=node4 18' 20 FROM BUS
node2: RECEIVED '/USER/BOB/=node4 18' 20 FROM BUS
node4: RECEIVED '/USER/BOB/=node6 18' 20 FROM BUS
node6: RECEIVED '/USER/BOB/=node4 18' 20 FROM BUS

As you can see there is bus between node2, node4, node5, node6.

I will post the sources here after i perform some tests with large set of clients, some stress tests and so on.

]]>
http://vitiy.info/writing-custom-protocol-for-nanomsg/feed/ 5
How to make simple CQRS implementation without Event Sourcing http://vitiy.info/how-to-make-simple-cqrs-implementation-without-event-sourcing/ http://vitiy.info/how-to-make-simple-cqrs-implementation-without-event-sourcing/#comments Thu, 06 Nov 2014 13:45:47 +0000 http://vitiy.info/?p=347 Here I will try to describe the concept of CQRS without event sourcing based on some other principle instead. The concept to organise your data and messages to create scalable and reliable CQRS/Messaging-based architecture without additional complexity from event store.

CQRS - MVC

At first here is small introduction on what SQRS is. I suppose you are familiar with MVC model and use it on daily basis. And i suppose you understand benefits of separation your code into separate modules.

CQRS – Command-Query Responsibility Segregation. CQRS just separates model into 2 separate parts – READS model and WRITES model. They also can be referenced as Query model and Command model.

You might find some more complex definitions all over the internet, but actually all other patterns are additional. Just separating model into queries and commands makes it CQRS. Segregation must be clean so commands can’t query data.

More links to read about CQRS: Clarified CQRS / The list of SQRS resources

MESSAGING

The most natural addition to CQRS is eventual model (but even this is not obligation). When you send command you expect to dive into asynchronous world because processing could take some time on server. And beside ‘async’ lets remember some other words – distributed systems, cloud synchronisation, sharing, eventual consistency, concurrent access. Even if you think that now nothing from this list is close to your application’s field – very soon it will be there.

So i say yes to messaging: you can add persistent queues of messages into CQRS scheme.

CQRS Events queues scheme

Serialized commands go into message queues to different locations – it can be local cache or several services on server side. Message queues can have local journaling to prevent message loss. For example, if you send data to server and there was no connection – the messages will be stored locally. And finally when you restart the application the queue will be reexecuted.

Cache db / reporting database (this could be some key-value storage or just memory cache inside client application) is primary source for query interface. When you pass some command for execution you can inform cache simultaneously (also through event queue) that you have some changes coming.

EVENT SOURCING – CQRS/ES

The most documents about SQRS refer to Event Sourcing as must-have feature in additional to SQRS. I don’t think so. This concept fits well into eventual model, but if we affect ‘client state’ of application (ui, inner cache, etc) only through event listener – its not yet Event Sourcing. Even more – “event sourcing is a completely orthogonal concept to CQRS” (source). Definition is the following:

Storing all the changes (events) to the system, rather than just its current state.

So this is method of storing business data as sequence of modification events. For some cases its very useful as you can restore object state at any point in history but generally its not must-have feature. This is actually the problem of how to store your business data. And decision use it or not comes from business domain. There is considerable overhead from using it as you have to restore final state for each object every time, you need more storage to keep all events and processing inside query model will be more complex to maintain. Often you need to make snapshots to make it run fast enough.

At first you think that event sourcing is simple and easy model – but in most cases it is ugly way (imho). When you interact with objets in real world you don’t need whole history on each of them. Only one exception is finance transaction list from your credit card – but its rare case. The most of your objects don’t require stored events of modification as separate instances (we still can store this information in some logs).

There was some discussion on distributed podcast telling CQRS might bring +30% of developing time and sure this is critical if there are no really large benefits from it. BUT, Imho, all this talks are more about EVENT SOURCING. Implementation of basic CQRS is not so complicated (and you event don’t have to use messaging), but the switch to ‘data combined from events’ concept is much more complex for your developers to handle. So the idea is to replace event sourcing principle with some other simple concept to make life easy.

But what instead of event sourcing? Im going to present some solution here but first lets review what problems we are going to solve. I see now (2014) that basic scheme of interaction for client-server application is evolving to this:

Evolution of client-server scheme

Now, instead of simple client-server pair, we have several client devices with ability to sync data and several nodes of distributed server system.

Here we can make one more crucial decision – decide where your system stands in CAP theorem – AP or CP. This is a business choice. And you can still do CQRS in full CP way, but i think today Eventual consistent systems are more attractive. So here we are talking about them. Note that on server side of cluster still can be CP parts – like etcd syncing of cluster configuration or MongoDb sharded cluster.

I will go even further – lets assume we have 2 datacenters and replicate data between them (you can just create 2 droplets in digital ocean to emulate this situation without any effort). Lets assume you have mongo cluster as storage in each of them to hold your data.

CQRS_Cross_DC

After submitting some command we need to pass it as message through various channels to local cache, server 1 and server 2. As we do this asynchronously the following problems may arise here:

  • Message loss
  • Message duplication
  • Message reorder
  • Concurrent access conflicts

These are common problems when you are talking about messaging. Lets introduce additional requirements:

  1. After offline work the changes should be synchronised with servers and other clients
  2. Multiple clients should be notified the fastest possible way
  3. Messages from client should go to server side through 2 different routes simultaneously
  4. Local cache should receive some updates immediately and if command will fail on server side additional notification message should cancel it properly

You can imagine the set of problems which may arise here if you handle database updates the usual way. Plus, you have to keep in mind the following picture – in real world situation might get worse…

messagingasitbocomes

Pretty scary… Lets introduce some concept which will handle most of declared problems implicitly.

DATA SEGREGATION BY RESPONSIBILITY or SIGNED-DOCUMENTS MESSAGING CONCEPT for CQRS

The next part is a concept which may be not new but i failed to find it as common knowledge related to CQRS.

As solution we need to use some messaging principle similar to event sourcing (and combine it with messaging transport layer based on ZeroMQ, NanoMsg or similar).

Event sourcing principle – each object is composition of modification events.

Alternative principle – each object is composition of immutable parts exclusively signed (owned) by specified users.  Each immutable part has ‘a sign’ – time and user signature indicating ownership. Each message replaces corresponding immutable part completely (and of course there are no delete operations – only is_deleted flag inside structure).

Object contains owned signed parts

Analogy from real life – you represent some business solutions as series of signed documents from various departments. At any moment you can replace one document by another, but you can’t modify document once it was signed. You can send any amount of copies of such documents to anyone without any collision. Missing or reordered docs are also not a problem in such scheme – to perform some action you need the list of actual documents and if some of them are missing  or invalid we can request them again from owner.

signature

In real life we have documents which are signed by several persons. Actually this documents either can be split in separate signed parts or ownership can be transferred from one person to another when first person can no longer access first object. So we have one document – single person responsibility. (Here we talk of document as object part).

This concept is similar to functional programming where you deal with immutable objects. You can also treat sign as revision marker of version control system. If existing sign is newer you can’t overwrite the document by previous version by mistake. So before each database write interaction you are checking signs.

You could also treat parts as svn files. And as you might guess the main problem is how to solve concurrent commits? In ownership scheme you can successfully commit only by grabbing ownership (and sign document with another signature). In simple case you just use the latest validated version of committed document.

In special cases when the group of users can modify the document at the same time (the case you prefer to avoid in real life because this is complex problem how to merge conflict changes in such situation). Here we have 2 subcases:

  • The document is big and modification time is considerable. Imagine google docs here. The simple solution is to have exclusive temporary lock on document. During edit process the lock can be extended. Additionally, the group of users can be notified of changes if its needed.
  • Second case – you have large set of data and set of users who can operate on such data simultaneously. Here you can set additional restrictions for collection updates. At start of modification client must request new cache (this can be done async way) and when you send message with modified version of data it contains sign of previous source cache. Trying to overwrite more recent data will produce error message. Trying to make overwrites based on outdated cache will also produce error message.

If during your business process some objects pass from one user to another you can add additional inner parts to object signed by different users instead of signing whole object data. For example, if your product needs some verification from someone instead of is_verified flag inside main object data you add new part inside object composition: verification + sign.

Whole concept can called: treat your data as composition of signed documents. But keep in mind that signed here are parts of business objects. And they can be very small. Even if its only one integer field, but by business process it should be assigned by different person, there is a sense to separate it into another part to make things clear. Also it make sense in terms of security.

The last thing is additional ‘second-order objects‘ as i call them. Those are the result of some minor map-reduce operations on first-order data. Counters, statistics, summaries, distributions, short representations, views, caches… all such objects are kind of cache. They have no signs (and its logical as it is the result of composition of signed objects).

EVENT MODIFICATIONS / REFACTORING

I think the approach when you are cloning events and make new name to each new version is ugly (like EVENT_MAKE_PURCHASE_V14 -> EVENT_MAKE_PURCHASE_V15, etc). But you have to use such approach only when you are working with event sourcing. If you are not limited to event sourcing you can just make your message handler be aware of possible missing fields (or even add version inside message structure). In other worlds handler should just convert message to the most recent known version in the most common cases.

So there are no additional issues here.

SAGAS

One more term you can often hear when CQRS is mentioned: Saga – business process manager handling reversible transaction chain. Inside saga there is some state machine which controls workflow (in ideal case). This solution provides additional protection from message ordering/missing/duplication problems inside world of messages.

At simple approach saga stays on client side and related messages contain saga’s id to pass messages into it. Its like mini-controller containing internal saga state. In some cases this approach is good, but i prefer to embed state into the message when it is possible to make more functional-style processing. Of course, for some cases you have to check the state transition at server side to prevent exploits.

I think its not so easy to predict if your business processes are sagas or will become sagas in future – but describing them as finite state machine is a good idea. Anyway this is also additional part to CQRS but is not required. And implementation may vary too – you don’t have to create separate class for each saga, you just have to make obvious message chains.

DOCUMENT ORIENTED STORAGE

As you treat your data as composition of documents some NOSQL document-oriented storage is the most natural solution here. And you can contain all signed parts inside one nosql-document. The sings can be stored as expanded form to simplify filter/search operations. As primitive example you could have the following for user:

user:
{
    info: {
        name: "Victor",
        email: "some@mail.com",
        sign: {
            name: "Victor",
            user_id: 783275082375032503872503,
            time: 147812470128927;
            device: "hgio234803223943";  
        }
    },
    roles: {
        role: "writer",
        sign: {
            name: "Jack (Admin 145)",
            user_id: 3284903275037095732,
            time: 173248937248397;
            device: "394324h3uik2432h";  
        }
    }
}

You can see two parts here – user data entered by user and role given by some administrator.

Disadvantages of signed-documents approach

  • A bit more traffic is required (not in comparison to event sourcing, but to general 3-tier)
  • Slightly different view at data storage is required from your developers

Advantages of signed-documents approach

  • Implicit solution for all basic ‘messaging’ problems
  • Simple principle of data management which is close to actual business flow (signed documents)
  • Immutable parts give more consistency and less message implementation chaos
  • Sign validation and responsibility segregation give ability to track user influence and maintain data order (access restrictions from design)
  • High-concurrency access problems are solved with sign locks and cache actualisation settings.
  • After implementation functions related to signing and sign verifications/locks, approach induces minimal additional complexity – splitting your documents into parts gives you only benefits (especially when you can still grab them whole using nosql solution)

SUMMARY – WHAT TO DO

To summarise it all – instead of event sourcing we can use different concept – document-signing approach and the following rules:

  • Split your database objects not into composition of past events, but into composition of signed documents (divide objects by ownership and responsibility).
  • Treat objects parts as immutable record which can only be replaced completely.
  • Send whole signed immutable part inside each message which can affect them.
  • Each immutable part has a sign which contains time/user/sender/lock informations and is used to resolve all message collisions.
  • Extract counters and other second-order data into cache and regenerate it if composition of immutable parts has changed (or upon request).
  • Think of your data as composition of signed business documents.
  • In need of high-concurrent access impose additional sign and cache actualisation requirements.

I could also name this as Data Segregation by Responsibility  – CQRS/DSR. This approach makes CQRS messaging easy.

This document can be modified to reflect my new experience and can be extended with new samples. Any thoughts are welcome in comments.

]]>
http://vitiy.info/how-to-make-simple-cqrs-implementation-without-event-sourcing/feed/ 6