Research time

First of all… HAPPY NEW YEAR ALL !!

I felt I had to do some research… and I did for couple days till yesterday morning I felt ill as hell. Now, I’m getting better, and it seems the “virus” that hit spain got me too… Anyway, I’m winning the battle to my flu.

So, before getting ill, I had a look at Qt’s signals and slots, and wondered if I could do something similar myself. Well, I called this tiny library “Ideal”, and till now it only has signals/”slots” (there are no slots, we’ll see later) and a small timer for testing purposes…

I don’t mean this thing to be huge, but I guess I will be working on it from time to time. However, it was a great thing for me seeing it working. The “bad” thing: it uses c++0x stuff to work.

Let’s see a small usage example:

#include <object.h>
#include <iostream>

using namespace Ideal;
using namespace Ideal::Core;
using namespace std;

class MyObject
: public Object
{
public:
MyObject(Object *object = 0);

IDEAL_SIGNAL(mySignal); // signal with no parameters
IDEAL_SIGNAL(pushed, bool); // signal with a bool parameter
};

MyObject::MyObject(Object *object)
: Object(object)
, IDEAL_SIGNAL_INIT(mySignal)
, IDEAL_SIGNAL_INIT(pushed, bool)
{
}

class OtherObject
: public Object
{
public:
OtherObject(Object *object = 0);

void receivedSignal(Object *sender);
void buttonPushed(Object *sender, bool param);
};

OtherObject::OtherObject(Object *object)
: Object(object)
{
}

void OtherObject::receivedSignal(Object *sender)
{
cout << "received a signal ! (from object: " << sender << ")" << endl;
}

void OtherObject::buttonPushed(Object *sender, bool param)
{
cout << "button pushed ! (from object: " << sender << " and param " << param << ")" << endl;
}

int main(int argc, char **argv)
{
MyObject object;
OtherObject otherObject;
object.mySignal.connect(&otherObject, &OtherObject::receivedSignal);
object.pushed.connect(&otherObject, &OtherObject::buttonPushed);

// simulate that something happened, and see how slots become called
object.mySignal.emit();
object.pushed.emit(true);
object.pushed.emit(false);
object.pushed.disconnect(&otherObject, &OtherObject::buttonPushed);
object.pushed.emit(true); // this two calls won't have any effect (no "slots" called)
object.pushed.emit(false);
object.mySignal.emit();

return 0;
}

This is the general look of this stuff… the pros:

  • Signal/Slot type safe at compile time, not runtime.
  • No external tool like ‘moc’ needed for signals to work (also a weak point, see later)
  • You know in which order “slots” will become called. Planned also a way to “reorder” the way they will. At this very moment, they are called in the exact order they are connected.
  • Slightly faster than Qt’s signal/slot callings (based on a test that was doing 1.000.000 calls).
  • Don’t know if a strong point: there is no slot concept. They are callbacks, you can call the method you want using signals without mattering if it was declared as a slot or not. I can see the use case where you would have expect something to have been a slot but it isn’t, so you can’t call it easily with Qt’s signals/slots.

Weak points:

  • Tiny tool. At this very moment, this library only contains a timer and the signal/”slot” thingy.
  • Because no tool like ‘moc’ is needed, I haven’t got that cool meta object information that Qt has.
  • It uses a new feature from c++0x.

The philosophy:

  • Won’t be public until I have something more to show.
  • One-way-of-doing-it principle. Will try to KISS by letting the library user doing a certain thing in a certain way.
  • Correction. As everything… on the real paper this is much more difficult than in the theory :)
  • There is no interest in having this library built with old compilers and other systems than GNU/Linux (or better said, POSIX compliant). I mean, we all can get a free operating system which builds this library, so I don’t find the reason for making this library build for, say Solaris 2. However, the way it is going to be written allows it to be also expandable for other operating systems. Based on conditional d pointers where there is a d pointer for system doing the nasty job behind the cool scenes of the nice API.
  • C++ on steroids usage.
  • Obviously, this will be free software. At this very moment I have licensed the very small work as (LGPLv3), but well, I need to really study better all the licenses and decide.
  • maninalift

    You only compare your method to Qt, have you looked at the boost signal/slot implementation and as well as the libsigc++ implementation.

    Boost implementatin is of course rather cool, I don’t know about libgsigc++

  • http://ivan.fomentgroup.org/blog/ Ivan �?.

    Cool :)

    Once upon a time I decided to do the same, only in Java. Unfortunately, I haven’t had the time to finish it yet – the signal/slot mechanism works, but the Swing integration is not finished yet.

  • http://zwabel.wordpress.com David Nolden

    Looks nice! Except for the IDEAL_SIGNAL_INIT part, that looks a bit redundant, shouldn’t it be possible to do that initialization within the constructor of a member object?

  • Michael “Boost” Howell

    How does this compare to Boost? Ideal really looks like boost, since they both have a signal-slot implementation that doesn’t use a preprocessor and appear to do things other than signal-slots (Ideal has the timer).

  • http://www.ereslibre.es Rafael Fernández López

    @all: thanks for your comments !!

    @David Nolden: well, yeah, you can also do an initialization on the constructor body instead of using the convenience macro.

    @Michael “Boost” Howell: hehe, well, I looked at boost’s signal-slot implementation, and internally I still prefer far this one. Much simpler, probably more intuitive in the code, fast as hell too and well, no preprocessor, they are just convenience macros. There is no huge magic behind those.

  • woot

    Any reason to use emit as a function rather than just using the function call operator?
    i.e.
    object.mySignal.emit();
    object.pushed.emit(true);
    becomes
    object.mySignal();
    object.pushed(true);

  • Maltus

    Happy new year Rafael Fernandez Lopez.