Saturday, October 17, 2009

Using Boost Function with Qt, Part 2.

[Following up this post]

Johan asks:

please, please post that follow-up. I'm new to Qt and have just run into this problem. While searching the net, I think your solution seems like the best approach!

Who am I to deny a seeker of knowledge? Having used this method in a couple of projects now, I think it is fairly sound and easy to maintain. So here goes.
The main problem with the solution outlined in the earlier post was that it could not handle multiple arguments. On that same post, Ken posted his solution apparently inspired by mine. His solution also handles multiple arguments but does it by implementing qt_metacall, i.e., mimicking moc. This is probably the most scalable solution and I'll probably give it a second look when I need to do this again. The only problem might be requiring exact matches for types but I am not sure how much of an issue this is for code I have written.

To review, the problem is that we want to use function objects (Boost Bind, Boost Function, etc) as Qt slots because sometimes it is too much work to create stateful slots.

My solution looked something like this:

struct SignalHandler0 : QObject
{
private:
Q_OBJECT
public:
SignalHandler0(QObject * parent,
boost::function const & f):
QObject(parent), // parent will delete this object when destructed
m_f(f) {}

public slots:
void
handleSignal()
{
try
{
m_f();
}
catch(...)
{
// Cannot throw exceptions from signals.
ASSERT_BUG_HERE
}
}
private:
boost::function m_f;
};

bool
connect(QObject * sender, const char * signal,
boost::function const & f)
{
return QObject::connect(sender,signal,
// Note: Not a leak as sender will delete the handler when destructed
new SignalHandler0(sender,f),SLOT(handleSignal()));
}
To extend it to a single argument, we might do:
struct SignalHandler1 : QObject
{
private:
Q_OBJECT
public:
SignalHandler1(QObject * parent,
boost::function const & f):
QObject(parent), // parent will delete this object when destructed
m_f(f) {}

public slots:
void
handleSignal(QString const & a)
{
try
{
m_f(a);
}
catch(...)
{
// Cannot throw exceptions from signals.
ASSERT_BUG_HERE
}
}
private:
boost::function m_f;
};

That is, create a new class with the right signature. So you might think: well that screams for class templates! Unfortunately, Qt does not support class templates. Doh.

So basically, we write it out:

struct SignalHandler : public QObject
{
template
SignalHandler(QObject * parent,boost::function f):
QObject(parent),
m_handler(new SignalHandlerImpl(f))
{}

struct SignalHandlerBase
{
virtual ~SignalHandlerBase();
}

template
struct SignalHandlerImpl
{
SignalHandlerImpl(boost::function f):m_f(f){}
boost::function f;
}
public slots:
void handleSignal(void);
void handleSignal(QString const &);
...

private:
shared_ptr m_handler;
};

void
SignalHandler::handleSignal(void)
{
typename SignalHandlerImpl type;
type* handler = dynamic_cast;(m_handler.get());
ASSERT(handler);
handler->f();
}

void
SignalHandler::handleSignal(QString const & a)
{
typename SignalHandlerImpl type;
type* handler = dynamic_cast(m_handler.get());
ASSERT(handler);
handler->f(a);
}

You can use macros to generate these handlers. You will also need overloaded connect() functions:

template
QObject*
connect(QObject * sender,
const char * signal,
boost::function slot);

...
template<>
QObject*
connect(QObject * sender,
const char * signal,
boost::function slot);

template<>
QObject*
connect(QObject * sender,
const char * signal,
boost::function slot);
Again, you can use macros.

I prefer Ken's solution from a technical standpoint. It is a good evolution. The main advantage of his solution is that the amount of code you need to add scales linearly with the number of arguments you need to handle whereas with my solution, they scale with the number of signals and that there are no macros.

The main advantage of my solution is that it is simpler to understand and maintain, which might be worth the extra code.

Hope that helps!

Saturday, September 12, 2009

Hello, Toronto

We just completed a cross-country move back to Toronto. Moving is tiring but my wife was very organized. I have to make it up to her somehow. We will still be setting up for a few months, I'm sure.

I'm looking for some good meet ups but I can't seem to find any quality ones. The only things I might actually be able to make time for are:

  • Backyard / amateur astronomy
  • Business-related
  • Software-related (anything to do with 3D graphics would be awesome)
I've found meet ups for the first 2 but nothing enticing for the software-related. It's all fluff.

The business-related one I will be attending is "Tech Entrepreneurs & Emerging Companies Group". There seem to be some serious people there. I look forward to sharing and learning (mostly learning, I'm sure!) from them. This one seems to be a diamond in the rough as most of the business-related meet ups are just advertising for the host.

Time will tell.

It's good to be back Toronto. By the way, your garbage bins have become too small.

Tuesday, August 18, 2009

The best market is one with lots of money

There are always people who feel that developing plug-ins is not a profitable market. Now while developing a plug-in may not make you as rich as Bill Gates, if there is a sizable market, you will make money.

So if you are looking for whether your idea makes sense, here is a simple relation to figure it out:

UnitPrice * NumberOfQualifiedCustomers * ConversionRate >= SomeSpecificFinancialGoal

If the statement is true, you will make money. If it is not, you will fail.

I'm pretty sure that I grossly over estimated NumberOfQualifiedCustomers when creating Worklog Assistant. How did I over calculate? Simply, the number of total JIRA users who also use JIRA as a timesheet system is quite small (yeah, duh right?) I would not have known this if I did not reach market quickly.

However, I used very pessimistic values for ConversionRate so maybe that balanced it out because I still reached my financial goals.

What does this mean for me? It means V2 is going to kick some serious ass. Oh how I wish I could have people to work on this with me, wink wink :-)

Thursday, July 9, 2009

Going AFK with Bazaar

One thing I've really liked about distributed VC systems is that they handle merging really well. Of course, this is not limited to DVCSs. Subversion and Perforce have very good merging but do not support offline work very well.

I've been using Bazaar for a little while now for my app because I knew that I would need to be offline every now and then. I just had one of those periods and thought it would be a great chance to see how well AFK mode works with Bazaar.

This is more for my own future reference rather than for you :-)

laptop $ rsync -avz -e ssh sohail@desktop:/home/sohail/bzr/ ~/bzr
laptop $ bzr branch ~/bzr/code/master project
laptop $ bzr bind ~/bzr/code/master

Now I can work offline in the "project" directory and all checkins go to ~/bzr .

Upon return:

laptop $ rsync -avz -e ssh ~/bzr/ sohail@desktop:/home/sohail/bzr

NOTE TRAILING SLASH ON SOURCE DIRECTORY!!!!!1111oneone....

Note: I think the above is insane. Ideally, I'd just do something like:

laptop $ bzr checkout bzr+ssh://sohail@desktop/home/sohail/bzr bzr
laptop $ cd bzr
laptop $ bzr work-offline

Return from afk:

laptop $ bzr I'm back

Or something like that.

Sunday, June 28, 2009

Software developer, businessman or problem solver?

[Warning: Soap box post. I reserve the right to use this blog as such and you reserve the right not to read it! Please let me know if it reads like a Steve Yegge post. You can tell if it is like Steve Yegge if you hate it more and more as you read it. If this is so, please inform me and I will revise the article.]

As a software developer and still fledgling businessman, I am faced with many problems I need to solve each day. From how to accept payments online to maintenance renewals to how to write as little code as possible to do something useful, sometimes it boggles the mind how much we really have to deal with each day in our profession. Good thing I don't think about it much!

Some time back, I had lunch with a friend and we got to talking about needed skills for a software developer. This friend is quite possibly one of the smartest guys I know, not because he knows at what point Newton's theories break down or how generational garbage collection works, but because I think he really understands people. So I was very interested when he stated that the most important skill needed is the ability to search out solutions to problems. Not coding or encyclopedic knowledge of C++, .NET, Java, or functional programming but simply, the ability to take a problem, go away and come back with a solution.

I don't recall whether we talked about it more but it's been sitting in the back of my mind. Ever since then, I've come across situations where this statement jumps to the forefront and I think, "Yeah, this person could be a really good problem solver!" or "Hmm, I really should have tried to put on my problem solving hat here."

Is software development or growing a business actually problem solving? Maybe the answer is obvious to you but I have never thought about it consciously. To answer that question, I have to think about what a problem is. To me, a problem is an obstacle in the way to achieving a goal.

A goal one should probably have when starting a software business is to get paid. Now, unless I am experienced at achieving this goal, I will have no idea where to start. So one of two things will happen:

  • I will give up because I don't know the answer already
  • I will start to look for the answer
I know, it's obvious right? Every time there is a bug I don't know how to fix, or a feature I don't know how to implement, I am faced with these two choices. I'd like to think that I never choose the first option, but I'd be lying to myself.

Fixing bugs is something I'm generally good at. I've fixed some whoppers (mmm whopper) in the past, self-inflicted or otherwise. So I rather like the example above of choosing a way to get paid because I've never done it before. I've no idea how it works. I'm deathly afraid to screw up. But I've bought lots of software online. I know people who sell software online. So I start by asking people I know or people I trust. I recall situations in which I hated the purchasing process and situations in which it was the best process ever. I go back to these online stores and find out what I liked or hated. I make a list and check it twice.

With all this research, I have not written a line of code, yet I now have a very good idea of what a good solution should look like. Problem solved? Not quite. Now I have to decide whether to buy or build. I've already decided ahead of time that writing it myself is not really something I'm interested in but to ensure I understand what is going on, I research this topic as well. Indeed, it is not worth it. Eventually, I settle on a reseller and move on to achieving the next goal.

There is nothing magical about solving the problem above. In fact, it is almost mechanical. But the key point is the decision that was taken at the first point. That is, the decision to actually solve the problem.

I am fairly convinced that software development as well as growing a fledgling business are very much problem-centric. They are filled with goals along with many obstacles to achieving them. At each obstacle, you have two choices: to give up or keep going. We need to keep going. This does not mean being stubborn and trying the same thing over and over again. This often means trial and error, hypothesizing and experimentation (Carl Sagan might like that!) Above all, don't give up and say it is impossible.

Anyway, just thought I'd put the thought in your heads since it's been in mine for a while. I think I'm going to try calling myself Chief Problem Solver from now on.

Monday, June 8, 2009

VanCPP June meeting

If you are in Vancouver and interested in programming (who isn't?!) you might want to make your way to the VanCPP meeting in June. The announcement is below:

Our June 2009 meeting will be held on Thursday, June 18. Please note the new venue.

Topic: Concurrent Programming in the D Programming Language

Presented by Walter Bright

Abstract: Many-core concurrent programming offers exciting and compelling advantages. The single core, single thread programming model is assumed by imperative programming languages. This model offers sequential consistency as its fundamental characteristic.Because many-core systems use layered cache memory systems,sequential consistency is not guaranteed among threads.Because imperative programming languages allow implicit sharing of data between threads, many misguided idioms and optimizations are possible that erroneously assume sequential consistency.One example of this is the double checked locking optimization.The pernicious nature of these sorts of bugs is they defy programmers' natural intuition about how programs behave,they are not statically detectable, and there is no way to reliably test a program to rule out the existence of such bugs.A program may appear to work, but have problems appear years later, fail when ported to a different platform, and such problems may be extremely hard to reproduce and track down.In essence, the correctness of the program relies entirely on the expertise and care of the programmer.This is not an acceptable situation for developers of programs that require high reliability.

The D programming language is an imperative programming language with an innovative type system that prevents implicit sharing and also fosters a complete, integrated pure functional subset. It is possible to statically verify that D programs do not have sequential consistency bugs. The double checked locking optimization bug is not possible. Type support for shared data and immutable data, as well as pure functions, means that mutating data interactions between threads can occur only under carefully controlled conditions.This dramatically reduces the problem space for concurrency bugs from the whole of the source code to a small subset of it, making it a much more tractable problem.

Speaker bio: Walter Bright graduated from Caltech in 1979 with a degree in mechanical engineering. He worked for Boeing for three years on the development of the 757 stabilizer trim system. He then switched to writing software, in particular compilers, and has been writing them ever since.

The meeting will be held at:
Workspace
21 Water Street
Vancouver, BC
V6B 1A

Regards,

Vladan Vidakovic

Thursday, May 7, 2009

Using C++0x lambda to replace Boost Bind in C++03 code

[Note: This post looks ugly under Internet Explorer. If you want to tell me how to fix my CSS, that would be much appreciated]
[Note: This post was written using the Intel C++ compiler with -std=c++0x.]

As some of you know, I work on Worklog Assistant which is written using C++/Qt.

One thing that I've made very good use of is a slightly modified version of the code in an earlier post titled "Using Boost Bind and Boost Function with Qt".

As an example, consider the following code from the above app which creates a popup menu to toggle the visibility of table columns. This is done by creating a "toggle" action for each column header that... toggles the visibility. It might help to think how this action would be created in plain Qt (hint: it would be painful.) It would certainly not have the locality it does now.

void
showColumnHeaderContextMenu(ssci::CustomTableView * self,const QPoint & pos)
{
QMenu columns(ssci::CustomTableView::tr("Visible Columns"));
columns.setIcon(QIcon(QString::fromLatin1(":/ui/icons/grid.png")));

QHeaderView * headers(self->horizontalHeader());

std::vector<std::pair<QString,int> > sorted_columns;
getSortedColumns(self->model(),headers,sorted_columns);

for(int ii = 0; ii < headers->count(); ++ii)
{
QAction * action =
new QAction(sorted_columns[ii].first,
&columns);

bool is_hidden = headers->isSectionHidden(sorted_columns[ii].second);

action->setCheckable(true);
action->setChecked(!is_hidden);

using boost::bind;
using boost::function;

function<void()> toggle =
bind(&QHeaderView::setSectionHidden,headers,
sorted_columns[ii].second,!is_hidden);

ssci::connect(action,SIGNAL(triggered()),
toggle);

columns.addAction(action);
}

QMenu menu;
menu.addMenu(&columns);

menu.exec(self->mapToGlobal(pos));
}


Of particular interest is the code in the for loop which sets up the actions:
    function<void()> toggle =
bind(&QHeaderView::setSectionHidden,headers,
sorted_columns[ii].second,!is_hidden);

ssci::connect(action,SIGNAL(triggered()),
toggle);



This creates a function object on the fly which hides the selected column using code from the above linked post. To do this in plain Qt is a gigantic pain. LibQxt has a solution as well but mine is much better!

Anyway, the point is that you might find a lot of code using bind and function in an app like this. Binding member function pointers, member data pointers and function pointers is fairly normal and is really the only way to maintain sanity and reduce boiler plate. Nested binds are also used where appropriate.

Boost Bind is a way to create closures, or at least as close as you can get in C++ to true closures. Therefore it is natural to try and replace some uses of Boost Bind with C++0x lambda. There is good coverage of how C++0x lambda works here so I won't repeat the same information. However, I will cover the cases of bind I could convert and (horrifically) the cases I couldn't!

Using automatic variables



Consider the following code:

const int LICENSING_TAB_INDEX = 1;

ssci::connect(lblImportNewLicense,SIGNAL(linkActivated(QString const &)),
boost::function<void()>(
boost::bind(&QTabWidget::setCurrentIndex,
tabWidget,
LICENSING_TAB_INDEX)
)
);



The above function call sets things up so that when a link is clicked in the interface, the LICENSING_TAB_INDEX tab is selected in the configuration.

One thing Boost Bind does is that it stores all bound arguments by value. That means &QTabWidget::setCurrentIndex, tabWidget and LICENSING_TAB_INDEX are all stored by value. C++0x lambda calls this capturing. This can be done using implicit capture (by parsing the lambda body) or by you. By default, C++0x lambda captures variables by reference. It is potentially buggy to capture function-local variables by reference automatically. Therefore, the above code translated to C++0x lambda is:
[=]()
{ tabWidget->setCurrentIndex(LICENSING_TAB_INDEX); }

The first element of a lambda-introducer (the []) can be a capture default which can be one of = or &. The capture default tells the compiler how to capture those variables that are implicitly captured. The assignment is supposed to make you think of copy assignment and the & is supposed to make you think of reference to. So in the above case, to get the exact same behaviour as the bind, we need to intentionally copy all variables by value.

Great! Not so bad :-)

A simpler example... Or is it?



Consider the following code:

ssci::connect(clearSelectedRole,SIGNAL(clicked()),
boost::function<void()>(
boost::bind(
&QComboBox::setCurrentIndex,
projectRoles,
-1)
)
);


This code sets things up so that when the clearSelectedRole button is clicked, the corresponding QComboBox has an invalid index.

The C++0x version of this is really straightforward:

ssci::connect(clearSelectedRole,SIGNAL(clicked()),
boost::function<void()>(
[&](){projectRoles->setCurrentIndex(-1);}
)
);

In this case, the pointer object (not the value) projectRoles is captured by reference. This is not an issue because the pointer object is guaranteed to outlive the closure. Now you know why closures and garbage collection go together :-)

Verbosity or Why I wish C++0x used polymorphic lambdas



Consider the following code:

static
void
updateThreadSetup(QObject * parent,ssci::MainWindow * self);

m_checkForUpdatesThread(boost::bind(updateThreadSetup,_1,&parent))


The bound function in this case is an object that calls the function updateThreadSetup with a to-be-determined value for the first parameter and a fixed value for the second parameter.

The C++0x version of this is horrible:
m_checkForUpdatesThread([&parent](QObject * obj){updateThreadSetup(obj,&parent);});


First, since parent is a local variable (was passed into the function), you can't implicitly capture it. So you have to explicitly capture it. In this case, we want to capture it by reference, hence [&parent] in the lambda-introducer. Then, since this thread setup function is passed in a QObject* we have to tell the compiler to accept this argument. Apparently it isn't smart enough. Ask someone why it is this way, you'll hear some hand waving about the callable concept. Whatever.

That is some ugly code.

Anyway...

What you cannot convert without making your code super ugly



Consider the following simple code:
vector<int> d = {1,2,3,4,5};
vector<function<int()>> funcs;

for(vector<int>::iterator it = d.begin(), end = d.end();
it != end;
++it)
{
funcs.push_back(boost::bind(add5,*it));
}


This creates a vector of function objects that presumably add 5 to their bound argument and return the result.

Here is the equivalent in C++0x lambda:

vector<int> d = {1,2,3,4,5};
vector<function<int()>> funcs;

for(vector<int>::iterator it = d.begin(), end = d.end();
it != end;
++it)
{
int &i = *it; // WTF?
funcs.push_back([i](){add5(i);});//THIS IS REDUNDANT. REDUNDANT.
}


Naively, one might have done:

funcs.push_back([it](){add5(*it);});

in the loop. But this is a bug waiting to happen. Add the following line right after the for loop:
d.push_back(0)

Now all those iterators that are captured by value can be invalidated! YAY! The only way to avoid this issue is to manually extract the value referenced by the iterator and pass that into the closure which is what I did in my translation.

Conclusion



This exercise showed me that C++0x lambda is of some interest to me. I'd really like to get rid of the verbosity (I know, too late!) A couple of things would make this the perfect lambda for me:

  • Polymorphic lambdas (or at least let me specify auto for the arguments)

  • An easy way to capture computed values (the *it bug above)



I don't know how these problems would be solved, or whether they could be but until they are, I think there is still a future for function binding ala Boost Bind which is fine by me!