Friday, September 30, 2011

Web applications in Python without Javascript, CSS, HTML


Download: rctk_zk.tar.gz

If would like to know how to write rich web applications in pure Python without any knowledge of Javascript, CSS, HTML or Ajax then continue reading this post.


Take a look at the screen-shot. It is the demo application of a framework called RCTK – which makes the development of complex web applications as easy as desktop applications. As the RCTK documentation puts it, the API has been inspired by Tkinter. So if you are comfortable with Tkinter (or for example wxPython), you don't have to be a web programmer to create impressive web applications. Even though applications like the one in the screen-shot are programmed in pure Python, RCTK still has to render Javascript widgets in the browser, transparently to the programmer of course. Currently, two different front-end tool-kits are supported for this: Jquery (see demo) and Qooxdoo (see demo).

If you have just looked at the demos you will be wondering why my screen-shot looks different. Not even the creators of RCTK will fully recognise it. On the other hand, If you have ever used the ZK Java framework then you will probably be familiar with the “classic” blue colour theme and “Grid” widget shown in the screen-shot. I have extracted the Javascript part of ZK and added it to RCTK as an optional third front-end tool-kit. I will contribute the source code to the RCTK project as soon as I can. However, not all ZK components are available. For the moment, it is limited to the current RCTK API. Hopefully, we will expand the API to add other widgets, layouts and features such as border layout, html editor, drag-and-drop and other ZK components. Take a look at the ZK demo to see what components are available.

Below you can see the source code for the grid in the screen-shot. Simple !

class Demo(object):
    title = "List"
    description = "Demonstrates the List control"

    def build(self, tk, parent):
        parent.setLayout(GridLayout(rows=4, columns=2))
        parent.append(StaticText(tk, "Single"))
        parent.append(StaticText(tk, "Multiple"))
        grid = Grid(tk,
        [
            Column('Inv. No', width=55, sorttype=Column.INT),
            Column('Date', width=90, sorttype=Column.DATE),
            Column('Amount', width=80, sorttype=Column.FLOAT),
            Column('Tax', width=80, align=Column.RIGHT, sorttype=Column.FLOAT),
            Column('Total', width=80, align=Column.RIGHT, sorttype=Column.FLOAT),
            Column('Notes', width=150, sortable=False)
        ])

        parent.append(grid,colspan=2)

        for i in range(0, 20):
            grid.add((str(1000+i), "2010-01-%d" % (i+1), str(i), str(i*10.19), str(i*1.19), "Hello world, %d" % I))




Friday, September 02, 2011

A case for replacing polymorphism with switch-statements

Download: switch_benchmark.tar.gz

In this post I benchmark and compare virtual function calls to functionally equivalent if-else and switch statements. In object oriented design switch statements are substituted by polymorphism. The reason is to make the code more compact, readable and maintainable. However, the benchmark indicates that there is a case for doing the opposite -- replacing polymorphism with switch statements, if only for very specific and limited applications where performance considerations are the highest priority. Of course, switch statements can be made more compact, readable and maintainable using other C++ techniques such as metaprogramming. The source code for these techniques and the benchmark is available for download. Tested with gcc version 4.3.2.


The polymorphic benchmark uses a container (an array) that holds pointers to a base class from which several classes are derived. The time taken to make a virtual function call is measured for arrays of between 2 and 10 objects. An array of 2 objects takes 14 ns on average and 18 ns for 10 objects.

A functionally equivalent if-else function varies between 10 ns and nearly 18 ns.

The switch statement was the best performing at a constant 4 ns irrespective of number of objects. The switch statement is obviously being optimized by the compiler with the construction of a jump table.   

Should I care about a 14 ns virtual function call overhead? For most applications a few nanoseconds here or there make no difference. However, there are probably some software applications that might need to make every nanosecond count. For example, a network device may be described as having a performance of 10 gigabits per second (Gb/s). A 10-Gb/s Ethernet interface can deliver packets at between 812,740 and 14,880,960 p/s depending on the size of the packet, or on average it delivers packets every 67 ns - 1.2 us (see this article). In this context, a 14 ns overhead is significant. Therefore, if you are building a software application on top of 10 gigabits Ethernet interfaces, if-else and especially switch-statements might be the way to go. You can not make too many virtual function calls in 67 ns. Granted, my hardware may not be cutting-edge but I think a case can be made for switch-statements over polymorphism. Function call overhead can be improved  by a factor of at least 4.

Getting back to compactness, readability and maintainability of the code; we can improve the if-else and switch statements using Boost’s mpl, preprocessor and tuple libraries. You can see below a typical switch-statement and how it is used in place of an array of pointers.

struct SwitchBase
{
    void function(long* x, int type)
    {
        switch(type) {
            case 0:
                obj1.function(x);   
                break;
            case 1:
                obj2.function(x);   
                break;
            case 2:
                obj3.function(x);   
                break;               
            case 3:
                obj4.function(x);   
                break;
            case 4:
                obj5.function(x);   
                break;
            case 5:
                obj6.function(x);   
                break;               
            case 6:
                obj7.function(x);   
                break;
            case 7:
                obj8.function(x);   
                break;
            case 8:
                obj9.function(x);   
                break;               
            case 9:
                obj10.function(x);   
                break;               
        }
    }

    ImpOfStatic1 obj1;
    ImpOfStatic2 obj2;
    ImpOfStatic3 obj3;   
    ImpOfStatic4 obj4;
    ImpOfStatic5 obj5;
    ImpOfStatic6 obj6;   
    ImpOfStatic7 obj7;
    ImpOfStatic8 obj8;
    ImpOfStatic9 obj9;   
    ImpOfStatic10 obj10;
};

long sum=0; 
SwitchBase sw;
sw.function(&sum, 2); // calls object 3 with a 4 ns overhead
sw.function(&sum, 0); // calls object 1 with a 4 ns overhead


Writing switch-statements like this by hand is tedious and error prone. Instead we can automate its construction. I provide a class called “switch_case”. The compiler automatically constructs all the case statements required and the performance (Switch-Boost) is exactly the same as the hand written version.


Usage: Create instances of each class and add them to a container (a Boost tuple).

// Instantiate the class instances
ImpOfStatic1 s1;
ImpOfStatic2 s2;
ImpOfStatic3 s3;   
ImpOfStatic4 s4;
ImpOfStatic5 s5;
ImpOfStatic6 s6;   
ImpOfStatic7 s7;
ImpOfStatic8 s8;
ImpOfStatic9 s9;   
ImpOfStatic10 s10;

// Create a tuple and store the instances
typedef boost::tuple<
      ImpOfStatic1*,
      ImpOfStatic2*,
      ImpOfStatic3*,
      ImpOfStatic4*,
      ImpOfStatic5*,
      ImpOfStatic6*,
      ImpOfStatic7*,
      ImpOfStatic8*,
      ImpOfStatic9*,
      ImpOfStatic10*> StatTuple;

// Store the instances in the tuple
StatTuple tup(&s1,&s2,&s3,&s4,&s5,&s6,&s7,&s8,&s9,&s10);
           

// Crreate a switch-statement for all types in the tuple.
switch_case<StatTuple> call(tup);
Func f;
call(f, 2, &sum);    // calls object s3 with a 4 ns overhead
call(f, 0, &sum);    // calls object s1 with a 4 ns overhead


In this case, you do not have to write a switch-case function by hand. The compiler does it automatically. It is almost as elegant as the polymorphic solution and comes with a couple of real advantages:

1) Function call overhead is improved by a factor of four.
2) Functions can be in-lined -- virtual functions can not.
3) No loss of type identity specific to derived classes. 
4) No derived classes are needed. Classes can have different member function names.