29 September 2013

Thinking about undo/redo

    Hi there, this time I want to share some thought about how one can provide undo/redo support in his application. First of all, let's try to figure out what undo or redo means from programmer's perspective. There can be two approaches. First, the classes responsible for the application or a part of it always have some state (usually this is the set of data members), and undo is just a transition from one state to the previous one, and redo, respectively, from a state to the next one. Do not confuse the next one with something that will happen in the future, because redo only becomes available after at least one undo, so redo itself can be viewed as an undo after another undo. Anyway, everyone knows this part fine, because this is supported by most of the applications, especially by those providing a graphical user interface.
    The other case is when the importance is handed to the actions and not to the objects owning the state, so for example on the Document object the insertion (typing) or deletion of a text can be undoable, but for the same Document the resize operation can be not undoable at all. As you can see, the notion of state is not so relevant here, because having two consecutive states we cannot say for sure (for some cases we can, but this will take some more effort which is redundant) which action or what group of actions is responsible for that transition. So this is the second approach - the action itself may be undoable or not.
    What is interesting, if we think further, the action cannot handle such a big responsibility itself. Let's consider the same example, how can the delete action (button, or a menu item) undo itself? Undo means taking back all the changes that were caused by the action. These changes were caused to the Document, more precisely to the state of Document. It means delete has so much access to Document that it can change its state (some string member for example, or a shape object). To be able to undo these changes, delete action should have similar level of access to another behavior for restoring the Document's state. Thus, we again end up with the notion of state, but there is still a huge difference between two approaches. Let me give some real-world examples before I proceed to details.
    Suppose there is a gallery in the center of a city and masterpieces of famous artists are presented there. And you've been visiting the gallery very often during last 5 years, so you have seen all the works, and there is nothing new for you. But one day there is an announcement of an exhibition of a new young artist. You go and see all his paintings or drawings instead of the old usual ones. But after five days, the exhibition ends and the masterpieces are again hung in their usual places. So this is an example of the first approach. The state (original masterpieces) was saved somewhere in the basement, and then it was restored.
    For the second case, suppose your car is parked near the curb in some 20 meters from the traffic light. Then you drive forward 10 meters, and you remember that you've forgotten something, and you put the gear on rear and drive back these 10 meters and park at the same exact place. So now in terms of position your car is in the same place as before, so we can say that the drive action was undone, but the state of the car is not the same, the oil in the engine was still and now you just turned the ignition off and the oil has not manage to come down yet, the engine is a little warmer, the fuel in the tank is a little lesser, and so on.

Let me give two more examples, software related, and then we can go ahead. For first case - imagine you are filling some online form to send to the immigration services, but the form is too long, so there is a button called 'Save Draft' which saves the current state of the form, and then you can close your browser, come back any time later, log in to the same page and continue from where you stopped. In this example, the state is just the set of values of form fields you are filling (most likely all the fields are unique, so the values cannot be derived from each other). You can say "where is undo here". Undo is when not actually a supported operation for this case, but if you save the draft then continue filling the form, and suddenly the electricity goes off, after that you open the browser and actually the changes are undone to the previous state.
    For the second case - imagine a huge 3d graphical editing tool like Autocad or CorelDraw, and you start stretching some line, but your hand is not accurate enough and you move the mouse a little more than necessary, so the line becomes longer than you need. There are thousands of other objects in the same document you are editing, so you click undo, and the stretch action is undone. It is easier to stretch the single line back, than to store all the thousands of objects to restore the state.
    OK, enough fairy tales, now let's use some programming. If you don't mind I will start with the last two examples. So now I want to support the save draft action for the online form. I think everyone can do that:

class OnlineForm
{
public:
       void load(); // loads the form with the saved data if available
       void saveDraft() const; // saves the current state of the form
       void submit() const; // submits the form data to the server
       void clear(); // clears all the fields of the form
private:
       // form data
       int id;
       int phone;
       string name;
       string address;
       // ... and so on

};

saveDraft can save the filled data in an .xml file, for example, or in a database, and load will read and fill the form from the same place. Now if we want to support undo we need to be able to save the state as many times as needed and store these snapshots separately. And if we know the snapshot corresponding to current state, then undo is only a call to load with the previous snapshot, and redo is a call to load with the next snapshot provided as an argument. It is, of course, preferable to have two member functions getSnapshot and setSnapshot (or, which is more conventional, getState and setState) which will respectively retrieve and set the state of the form. Besides this, we better encapsulate the state into another class, this will keep things more decoupled and the function prototypes more brief. Let's call this class FormData. As I already mentioned load should be replaced by setState, which will accept an instance of FormData, so that the original source of our data (.xml, database, etc.) is not hard-coded in the OnlineForm class, but is defined as a serialization/deserialization of FormData. This will also make it easy to change the source, simply introducing a new serializer class for FormData.
    Also, we don't need saveDraft() anymore, we need getState() which will return the current state of the form within a FormData instance. So now our code will look like this:

struct FormData
{
       // form data
       int id;
       int phone;
       string name;
       string address;
       // ... and so on
};

class OnlineForm
{
public:
       FormData getState() const; // replaces saveDraft with
                                  // a better functionality
       void setState(const FormData& newState); // restores the state
       void submit() const; // submits the form data to the server
       void clear(); // clears all the fields of the form
private:
       FormData state;
};

    To support undo and redo for the OnlineForm, we need to have some convention on what we assume an undoable action. It can be a single character append in a textbox, or it can be a single field update (textbox, checkbox, combobox, etc.), or it can even be an update of a group of related fields (Personal info, job details, address, payment method, etc.). After each of this conventional action(s) we will call the getState and store the state in some place, and we always should keep track of the current state.

class OnlineForm
{
public:
       FormData getState() const
       {
              return states[currentStateIndex];
       }

       void setFirstName(const string& name)
       {
              FormData newState = getState();
              newState.name = name;
              setState(newState);
       }

       void undo()
       {
              if (currentStateIndex > 0)
              {
                     --currentStateIndex;
                     // probably, we should have some function call here,
                     // to refresh the form view, so that the correct data
                     // appears in the fields. And the "correct" data is
                     // the one retrieved by getState() call.
              } else {
                     // We are in the initial step and cannot undo,
                     // we can throw an exception, or for a better UX
                     // we can just disable undo button at all when
                     // this condition (else case) becomes effective.
              }
       }
       void redo(); // almost the same code as for undo().

private:
       void setState(const FormData& newState)
       {
              states.push_back(newState);
              ++currentStateIndex;
       }

       vector<FormData> states;
       int currentStateIndex;

};

I moved setState() declaration to the private section, because any intervention from outside would break the undo logic, now each separate action, like setFirstName will call setState. So generally, we have the undo/redo logic working, but within a bad implementation, most likely we should have an interface with undo() and redo() pure virtual functions, and it can be a generic one of the state object type - in our example FormData. Also, the OnlineForm itself may not be responsible for storing the states - instances of FormData, so we may need the third class responsible for the storage. If you remember this comes to the memento pattern described in GOF Design Patterns book. One more good thing we can do, make undo/redo accept an integer of how many steps we want to go back/forth. So there are many details which mainly depend on the exact application we write. But the general idea is the one already described:
  • have a strictly defined state, which most likely does not contain all the data members of the class in the question (in our example state does not have currentStateIndex, etc.);
  • after each undoable step, make another snapshot of your object, i.e., store a new instance of state;
  • track the current state in your list of states so that you can go back and forth whenever needed (needed here means, for example, pressing undo/redo button on the UI).
So what bad things can arise here, what are the pitfalls of this approach? Suppose the state does not consist of some primitive objects like int or string (string also can be dangerous, the reason is coming soon), but it has some internal data structures, for example an object graph. We cannot easily copy the whole state every time we do some undoable action, because, first, the state can be huge in size, and keeping many instances of state will fill the memory very soon. Second, we need a deep copy for storing the state, we cannot just keep the address of the root node of the graph and restore it from that address. In some cases, we can implement some kind of simple compression, for example, we can store only the difference between previous and current states, not the whole state, more precisely, store only the fields which have been changed. But this will introduce some more complexities in code. Also this still does not solve the deep copy problem. That's when the second approach of implementing undo/redo comes to a stage.
    In second approach, as I have already mentioned, we do not need to keep any state, but the actions that we want to be undoable, have to have some more logic. Let's take the same example of a graphical editor. There are several actions like stretch a line, fill the shape, etc. First, each action has some execute() function, which incorporates the logic of the action itself. Now we want to add an undo() function, which will work at least so well as execute does. For simplicity I will not focus on making the code generic, so I will present some specific actions for specific targets (always referring to the examples already brought up). Here are our actions for stretching a line and filling the shape with some color:

class StretchAction
{
public:
       void setLength(double length);
       void execute(Line line);
private:
       double length;
};

class FillAction
{
public:
       void setColor(Color color);
       void execute(Shape shape);
private:
       Color color;
};

Let's think about how to support undo. We need to keep the history of executed actions, so that each time we press undo in the editor it retrieves the current item and calls undo() on it. This means that each action should have some small amount of history also, to know how to revert things back. For stretch action we can have the previous (one that was before stretching) position of the line, uniquely defined by its endpoints, for example. For the fill action, we have no other way than keeping the old color. So we can change our actions a little bit and get the following version:

class StretchAction
{
public:
       void setLength(double length);
       void execute(Line line);
       void undo(Line line)
       {
              line.moveTo(oldP1, oldP2);
       }
private:
       double length;
       Point oldP1, oldP2;
};

class FillAction
{
public:
       void setColor(Color color);
       void execute(Shape shape);
       void undo(Shape shape)
       {
              shape.fill(oldColor);
       }
private:
       Color color;
       Color oldColor;
};

You probably have many questions now, and I will try to answer all of them, well, all that I can think of.
  • How do we know which Line or Shape object to pass to undo()? - I assume that the worksheet itself supports this functionality, e.g., current selection, active object, etc. If not, we could make the action to execute on the worksheet itself and also remember the Line object also which it operated on. But in this case we would have to worry about some synchronization stuff, for example when we delete a shape from the worksheet and then undo, the address of the new object is not necessarily the same, so we should think of some complicated way of referring to the worksheet objects.
  • How do we know that the object acted upon will always support the operations implied by undo? - As we can see, doing something and undoing that change do not always invoke the same function of the object acted upon. But most likely if we are the author of undo/redo support, we also have a change access to the source code for the classes for which we are implementing that support. I mean we can add the missing pieces of behavior.
  • What do we store in the undo history? - We can store instances of the actions themselves, though we would need to make an abstract base Action (see Command design pattern) which would be the parameter type of the history container. In case of my example I hardly can find a more efficient way of retaining the history, because we would still need to know the original and target values (color or pair of endpoints) and we still would need to know which action was applied, so at least some 4 bytes again. But this is exactly the case now - we have the values and vptr (I am considering that you are not reluctant and have already created the base abstract Action) for each instance of class which is again 4 bytes (for 32-bit systems).
  • How to implement redo() then? - Well, redo() will be just a single call of execute() on the same object.
  • Who should keep the history? - Most probably the editor, or if it supports multiple worksheets, it may be the worksheet, it depends on your business logic, so this is not always the same.
For some actions you may not even need to store additional data for undo support. Remember my example of driving the car. So if you keep the distance passed during driving, then driving back will need exactly the same distance, nothing more (well you may keep the route also, to know when and where to turn, but this is again the data required for driving forward, so no additional cost for backing up).
    This was the idea of the second approach, each action is responsible for reverting the changes done by itself. Both of these approaches share some common thing - they keep the old state to be able to restore it later. This is actually the essence of undo, without knowing what was before, we cannot go back to that state, and no one can do that, so do not think of any new ways of implementing undo, without having information about the state which you want to go back to.

I did not bring up the complete code and even not a well-defined piece of code, it was just some mock-up to make the comprehension easier and faster. And I put the title "Thinking about..." not "Implementing...", so don't blame me. I believe there are still open questions, but I don't have much time to cover everything, and everything in my understanding differs from what you think of it. Please post your questions in the comments, and I will be happy to answer. Thanks for reading.

2 March 2013

Quick sort implementation

Yesterday I tried to implement the quick sort algorithm in C++. I think everyone knows the algorithm, and it seems very easy-to-do stuff, but it took me about 1.5 hours to complete and polish it. So I thought it might be useful for some people and decided to share my implementation. I put in very descriptive comments, so I don't think I need to add anything else, the code follows:


// <iterator> header contains the definitions of
// std::advance, std::distance and std::iterator_traits
#include <iterator>

// SelectPivot is used to select the pivot element in
// the sequence which will serve as a partition point.
// Returns an iterator pointing to the pivot element.
template <typename Iter>
Iter SelectPivot(Iter begin, Iter end)
{
       // Current implementation just returns the middle element,
       // but we are free to choose the pivot in any other way.
       std::advance(begin, std::distance(begin, end) / 2);
       return begin;
}

// Implements the quick sort algorithm.
template <typename Iter, typename Cmp>
void QuickSort(Iter begin, Iter end, Cmp less)
{
       // No need to sort an empty or a single-element sequence.
       if (std::distance(begin, end) < 2)
       {
              return;
       }

       // Select the pivot element and store
       // its value in 'val' variable.
       Iter pivot = SelectPivot(begin, end);
       std::iterator_traits<Iter>::value_type val = *pivot;

       // Introduce new iterators to operate on,
       // begin and end will be needed for recursive
       // calls, so we do not modify them.
       Iter left = begin;
       Iter right = end;

       // Like all the similar algorithms in STL, our function accepts
       // a pair of iterators, pointing to the first and one beyond
       // the last elements respectively. That's why we should not
       // consider the value pointed to by 'end'.
       std::advance(right, -1);

       // Move the pivot element to the end of the sequence.
       std::swap(*pivot, *right);

       // The following piece of code partitions the whole into
       // two sub-sequences so that all the elemets less than the
       // pivot appear to the left from pivot and all the greater
       // elements appear to the right. This means that the chosen
       // pivot element will be in its final place.
       Iter pivot_position = left;

       while (left != right)
       {
              if (less(*left, val))
              {
                     std::swap(*left, *pivot_position);
                     std::advance(pivot_position, 1);
              }
              std::advance(left, 1);
       }

       // The pivot_position now points to the first
       // element which is not 'less' than the pivot. So we
       // need to swap the pivot stored in the rightmost
       // element with that stored in pivot_position.
       std::swap(*pivot_position, *right);

       // Calling the function recursively to
       // sort the sub-sequences to the left
       // and right from the pivot. The latter
       // is already in its final position.
       right = pivot_position;
       std::advance(right, 1);

       QuickSort(begin, pivot_position, less);
       QuickSort(right, end, less);
}

11 February 2013

A little more about virtual functions

I wanted to share a piece of knowledge on virtual functions in C++, then I thought it might be useful to make a little introduction to virtual functions, then only come back to the main topic, so you can find an introduction in my previous post. So I consider that we already know what virtual functions are, what they are meant for, and how they may be implemented (not in much details).

C++ standard puts requirements for the behavior of virtual functions, but it does not specify how they should be supported. Nevertheless, this feature is usually implemented using virtual function tables (vtbl). vtbl is, simply explained, a table of function pointers. The compiler generates a vtbl for each polymorphic class, i.e. a class defining a virtual function or a class derived from the former. vtbl contains entries for all virtual functions available in the class, I say available, because virtual functions defined in upper level of inheritance hierarchy also have their place in vtbl. Let's discuss on an example:

class Base
{
public:
       virtual void func1();
       virtual void func2();
       virtual void func3();
       virtual void func4();
};

class Child : public Base
{
public:
       void func1() override;
       void func2() override;
       virtual void func5();
       virtual void func6();
};

class GrandChild : public Child
{
public:
       void func1() override;
       void func3() override;
       void func5() override;
       virtual void func7();
};

I missed the function bodies and all the other stuff of classes for brevity purpose. Thus, we have three classes - Base, Child and GrandChild, and 7 functions in total. The compiler will generate a virtual function table for each of these classes. Here is what the virtual function tables will contain for each class:

vtbl for ‘Base’
0
Base::func1
1
Base::func2
2
Base::func3
3
Base::func4

vtbl for ‘Child
0
Child::func1
1
Child::func2
2
Base::func3
3
Base::func4
4
Child::func5
5
Child::func6

vtbl for ‘GrandChild’
0
GrandChild::func1
1
Child::func2
2
GrandChild::func3
3
Base::func4
4
GrandChild::func5
5
Child::func6
6
GrandChild::func7

As we can see, each vtbl contains the correct addresses of functions for each virtual function in corresponding class. Here correct means the address of the corresponding function of the most derived class that defines/overrides that function. When we instantiate the class, the instance will contain a pointer to the virtual function table (vptr) of the instantiated class. When we call a virtual function on an object, the object always has the type of its class, so in any case the function defined in that very class will be called, that's why virtual functions do not considered when working with objects. When we store an object of a derived class within a pointer to a base class, then virtual functions "work". The call of a virtual function is somehow translated at run-time and the corresponding function from the virtual function table of the class of underlying object (not the pointer type) is chosen. So let's see several examples of calls:

Base *pb1 = new Child();
Base *pb2 = new GrandChild();
Child *pc = new GrandChild();

pb1->func1(); // calls Child::func1
pb2->func1(); // calls GrandChild::func1

pb1->func3(); // calls Base::func3
pb2->func3(); // calls GrandChild::func3

pc->func2(); // calls Child::func2
pc->func3(); // calls GrandChild::func3
pc->func4(); // calls Base::func4

Thus, what function is called depends on what type of object the pointer points to, which can't be known at compile-time, that is why the virtual function call is decided at run-time. The same works for references, because they also work with addresses, not objects. As I am testing my examples with Visual Studio, I will give the implementation details for Visual C++ compiler. It stores the vptr as the first member of object. So, for example, the first call from the example above is converted to something like this:

reinterpret_cast<void (*)()>(*(int *)*((int *)pb1 + 0))();

If we run this code, it will do exactly the same as the first call in the list above (pb1->func1()). So let's break it down into smaller pieces to understand what really happens there. Here is the extracted version of a virtual function call:

typedef void (*fptr)();

// vptr is aligned with the start of the object, so we can get the vptr
int *vptr = (int *)pb1;

// vptr points to the correct vtbl, so the address of the vtbl is
int *vtbl = (int *)*vptr;

// func1 is the first function in the vtable,
// so its offset is 0, as it is stored in vtbl
// offset may be stored in bytes also (+4 bytes for each pointer on 32-bit platform)
fptr func1 = reinterpret_cast<fptr>(*(vtbl + 0));

// call the function
func1();

As I already mentioned, the standard does not specify the implementation details, so this kind of code will be not only superfluous, but either non-portable. Anyway, I hope it gave a better understanding of how things turn over during the run-time. Thus, the virtual function call (by means of a pointer or a reference) is not an ordinary call and has a little performance overhead, which may turn into a huge if we have numerous calls.

We now know that a virtual function call via a pointer is converted to something else using vtbl and vptr. But someone should create them and correctly initialize. And this someone is the compiler for the virtual function table. Remember, I wrote in the last article, that if we do not define a body for a virtual function the compiler will complain even if we do not create any objects of that class. That is because it creates a virtual function table, but the function body is not there, and the compiler cannot initialize the corresponding function pointer. As for vptr, the compiler generates some extra code in the constructor of the class, which it usually adds before the code we write. Even if we do not define a constructor, the compiler generates a default one, and the initialization of vptr is there. So each time we create an object of a polymorphic class, vptr is correctly initialized and points to the vtbl of that class.

Let's see what happens when a class inherits from several polymorphic classes. Again it is implementation-dependent, though, generally, the picture is the following. In this case, the number of virtual function tables for a class is equal to the number of polymorphic base (immediate) classes. And each object of the class contains exactly as many vptr's as many polymorphic base (immediate) classes it has. Now in order for each function to know which sub-object it should use, the vtbl also stores the offset of the corresponding sub-object in the most-derived object. The rest of the story is actually the same thing as for single inheritance hierarchy, so I will not go further. Just to note, Visual C++ compiler stores the virtual functions of the most-derived class in the virtual function table of the first base, so the first vptr points to a virtual function table which has the function pointers for all virtual functions of first base class, plus, the function pointers for all virtual functions of the derived class itself.

What else should we know about virtual functions in C++? A virtual function can be pure. To declare the virtual function as pure we should assign 0 at the end of the declaration:

virtual void func() = 0;

A class containing a pure virtual function is called an abstract class. An abstract class cannot be instantiated, if we try to we will get a compile error. This is natural, because the idea of abstract class is abstractness, and we cannot have something that does not exist, i.e. is abstract. A class containing only pure virtual functions is known as an interface. Though, in C++ context interface is often referred to as the part of the class intended for access from other components (clients), i.e. the public member functions, and any other functions which accept an object of the class as an argument. A class which overrides all the pure virtual functions forms a concrete type and can be instantiated.
    A pure virtual function is usually used when the function body cannot be defined, not because of complex implementation, or long code, just because the class itself is not responsible for that function, and does not know what to do in that function, the class is only aware that it should do something. For example we can have a class 'Appliance', and a pure virtual function 'MakeSound'. We do not know what sound an appliance makes and how it makes it. But we know if the appliance is an audio player it just plays the music, if it is a refrigerator or a kettle, it will make some noise, etc. So we should override the 'MakeSound' function in each inheriting concrete appliance.
    Most often a pure virtual function will not have a body defined, though it is not restricted. Since we cannot create an instance of an abstract class, we cannot directly call that function, but we can call it in a child class, for example:


class Base
{
public:
       virtual void func() = 0;
};

void Base::func()
{
       // Do something very general, or output some message
}
    
class Child : public Base
{
public:
       void func() override
       {
              if (hasItsOwnBehaviour())
              {
                     // Child knows how to behave,
                     // so implement func here for Child
              }
              else
              {
                     Base::func();
              }
       }
};

Hooh, just a little more, and I'll finish. We still have not seen the case with special member functions, particularly, constructor and destructor. The constructor cannot be virtual, because it always needs the exact type of the object being created, i.e. the static and dynamic types are the same, and there is no sense in polymorphic behavior in this case. Also, we cannot have a pointer to constructor. If we want a polymorphic behavior when creating objects, we can take advantage of techniques used in design patterns like factory method and prototype.
    As opposed to constructor, the destructor can be and in most cases must be virtual. Suppose this example:

Base *pb = new Derived();
delete pb;

If the destructor of Base is not virtual, operator delete will call the destructor of Base and then free the allocated memory. This means that Derived object will not be fully destructed. For example if the constructor of Derived allocates a chunk of memory, it won't be freed, because only the destructor of Base will be called. To solve this problem we just need to declare the destructor of Base as virtual. In that case the correct destructor (~Derived) will be executed. So if you are designing a polymorphic type, always declare the destructor as virtual.
    The destructor also can be declared as pure virtual. In this case the class will become an abstract one, and cannot be instantiated. But in this case, it should always define a body for the destructor, because an object of a more derived class will call this destructor when being destructed itself, so the body is mandatory for a pure virtual destructor. A pure virtual destructor may be needed when we do not have any pure virtual functions in the class, but we want to specify and emphasize that the class is abstract.
    If we call a virtual function inside a class constructor the function defined in that class or if not there, in the nearest base which defines it, will be called. And it is logical, because in the constructor the object may not be fully constructed, i.e. if we create an object of a more derived class, there are still other constructors in the queue to be executed to completely construct the object. So, first, vptr may not be correctly initialize (pointing to incorrect vtbl of a less-derived class), and second, the members of the more-derived class that the virtual function is going to use may not be yet initialized.
    The same works for destructors: if we call a virtual function in destructor, the local version of the function will be executed. Again, if it worked as ordinary virtual function call, it may access some members of a more-derived class object, which may have been already destroyed, because the destructors of more derived classes are called first. Here is a little example demonstrating the virtual function calls inside the constructor and destructor:

class Base
{
public:
       Base() : data(2)
       {
              f();
       }
      
       virtual ~Base()
       {
              f();
       }

       virtual void f()
       {
              data = 7;
       }

protected:
       int data;
};

class Derived : public Base
{
public:

       Derived() : extra_data(10)
       {
       }

       virtual void f()
       {
              data = 17;
              extra_data = 20;
       }

private:
       double extra_data;
};

int main()
{
       {
              Derived d; // data = 7, extra_data = 10.0
       }
       return 0;
}

When 'f' is called from the Base constructor, the Derived part of the object does not exist yet, that's why the 'Base::f' is executed and 7 is assigned to 'data'. If you put a breakpoint in the destructor of Base and run, then step into the 'f' call, again you will see that 'Base::f' is called, this time because the Derived part of the object has already been destroyed.

I think I covered some interesting points. There is still a lot to talk about virtual functions, some usages, some nuances... anyway, I have come to a logical end, and I want to stop here. Thanks for your time, I am very glad if you have learnt anything new from this article. Until the next post.