views:

773

answers:

8

Q1. Why are callback functions used?

Q2. Are callbacks evil? Fun for those who know, for others a nightmare.

Q3. Any alternative to callback?

A: 
  1. Callbacks are used for example to invoke aynchronous operations, that is, code that runs in a different thread while the caller follows its own way. You need some mechanism to know when the asyncrhonous operation has finished.

  2. Why would them be evil? As with any other programming resource, they are useful when used judiciously. In fact the Windows API and the .NET framework, for example, use callbacks extensively.

  3. Don't know about C++, but in the .NET world, syncronization objects and events are alternatives.

Konamiman
for #1, sure, a callback is useful for that, but callbacks are often used for completely synchronous fuctions...
asveikau
I haven't heared of callbacks for thread communication and Wikipedia doesn't mention it (http://en.wikipedia.org/wiki/Callback_%28computer_science%29). Callback handlers can send messages to other threads though.
stefaanv
+25  A: 

Callbacks decrease coupling - the invoked party is passed some pointer and it has no idea what's behind it. Callbacks are such a fortunate solution that they are very widespread.

For example look at sqlite3_exec(). You give it a query and optionally a callback. It executes the query and invokes the callback for each row as it is retrieved. Now it's SQLite's business to execute the query fast and with low resource consumtion and it's only your business to process the retrieved results as you like. You can add them to a container and process all later or you can process them immediately one-by-one or you can fax them somewhere and expect the other party to fax them back - SQLite doesn't care, it's completely abstracted and can just do its job.

sharptooth
Nice example. Thank you.
Seth Illgard
A: 

Q1. Callbacks are needed if you use a layered approach in which higher levels call lowers and get feedback from lowers via callback.
Q2. When taken some precautions they're not worse than e.g. exceptions. In some ways, they're similar. Q3. More coupling: lower lovels know higher.

Remarks:
- simple way (1 callback handler per callback): Register CallbackHandler objects via interfaces
- Use signals (QT, boost,...), and make sure that unique signals are used per callback to enhance traceability

Edit: example:

User calls ProtocolHandler to send a message and ProtocolHandler calls the user to send the reply: mutual dependency.

Layered: user is higher level, ProtocolHandler is lower level. On startup, it registers a callback for the reply and calls the ProtocolHandler to send a message. The ProtocolHandler uses the callback to send the reply: Only user is dependent of ProtocolHandler.

stefaanv
Concerning Q1: Obviously feature X is needed if feature X is used.
ziggystar
They reduce coupling. The point is the lower level does not know what the higer level is doing. It only has an anonymous pointer.
Martin York
I think what stefaanv meant was that more coupling between the layers is the alternative to callbacks.
Devil Jin
@Devil Jin: Martin is correct, I was confused by the sub-questions, so I didn't answer the title-question directly. To me, it is clearer to think in layers when considering callbacks, to avoid the use of callbacks all over the place.
stefaanv
A: 

If we in C++ context, consider using (e.g. generalized callbacks).

The basic behaind idea is that callback (class method) can be of any name and the callback is not required to derive from some class knowned by callback executor.

The only restriction on callback is input arguments and return value. So this reduces couple to zero ... :)

UDP:

Answer of @EffoStaff Effo is an example where callback should be of the particular class (deriving) and have a fix name. All this "restrictions" are absent in context of generalize callbacks.

dimba
+3  A: 

Regardless of "using callbacks in C++ increase coupling" or not, I suggest using event handler style especially process event-like things. For example, concrete a Design Pattern instead of callback concept as the below:

class MyClass
{
public:
    virtual bool OnClick(...) = 0;
    virtual bool OnKey(...) = 0;
    virtual bool OnTimer(...) = 0;
    virtual bool OnSorting(...) = 0
    ...
};

You may still consider the above functions are callbacks, but when considering them as the known Design Pattern, you won't get confused because you are doing OO and writing C++.

Effo UPD@2009nov13 - Typical cases: Framework, Events System or Concurrent Programming Model, and so on. Following examples should be useful.

Framework controls the overall flow as the Hollywood Principle states "Don't call us, we'll call you." (that's what "callback" means exactly) while per a normal function or lib, caller controls the flow.

A well-known C framework is Linux kernel and a Linux driver writer knows that s/he'd implement a "struct file_operations" in it "read()" means OnRead() and "write()" means OnWrite() etc.

struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ...
};

But the simplest example of a framework should be:

    The Framework           |     A developer to do
----------------------------+--------------------------------------
                            |    class MyClass : public Actor
                            |    {     
                            |    public:
pApplication->Init(...);    |        virtual bool OnInit(...) {}
pApplication->Run(...);     |        virtual int OnRun(...) {}  
pApplication->Quit(...);    |        virtual void OnQuit(...) {}
                            |        ...
                            |    };

and pApplication->Init() will call pActor->OnInit, and pApplication->Run() calls pActor->OnRun(), and so on internally. Most Windows GUI developers had experienced implementing OnMouseClick() or OnButtonPress() etc.

I agree with other answers of this thread that they give correct explanation based on the viewpoint accordingly, such as handlers in layered approach, generalized callback or aynchronous operations, and so on. It's up to you that what idea(s) would be suitable for you.

EffoStaff Effo
your explaination caught my eye, but I could not understand it properly. Can you explain more by a pseudo code probably
Devil Jin
What is the Design Pattern that you are refering to? I thought this was the normal way to work in C++. Your callback handler derives from MyClass (which is not a class but an interface) and registers to a class which uses the interface.It resembles the Observer Design Pattern, but there you should allow multiple observers, which is not obvious from your example and not always needed for callback.
stefaanv
See my update. Examples added.
EffoStaff Effo
You keep talking about a "Design Pattern", but don't say which one?
Pod
@Pod and @stefaanv: What I meant in my answer when I was saying "Design Pattern" is that one could get rid of the "callback" sense and just think you are concreting a specific Design Pattern. Many Design Patterns use callback mechanisim. Thanks
EffoStaff Effo
@Effo: no, your use of Design Pattern is still confusing for me. This is unfortunate as Design Patterns should make things clearer.
stefaanv
@stefaanv: really? sorry i'm making you confused, but why not try to get help from your friends. anyway here i give a pattern example; you can go thru pages http://en.wikipedia.org/wiki/Command_pattern and http://sourcemaking.com/design_patterns/command/cpp/2 for the Command pattern, and then think when you are using the command pattern, how does the "callback" concept affect you. for me, i was not aware of callback at all.
EffoStaff Effo
A: 

In rare scenarios with Win32-style-callbacks watch out for "obscure reentrancy" issues (the following is irrelevant if by callback you just mean very basic passing of a function as arg to another function where concurrency issues are unimaginable ).
The excellent index to Joe Duffy's "Concurrent Programming on Windows" lists 5 topics under "reentrancy", which generally are specializations of the concept of "Around Robin-Hood's Barn RECURSION on the SAME THREAD" -- in other words from the top-rated-answer "the invoked party is passed some pointer and it has no idea what's behind it.", "no idea" can sometimes lead around-Robin-Hood's-barn.
Nothing I just said is specific to callbacks, but if the invoked-party stumbles across one of Duffy's scenarios then "obscure reentrancy" can happen. To put it a different way, implicit in the concept of "callback" is that you're going to seem to be called back in-the-same-thread, how does this happen, how does it get synchronized.
If you Google on Duffy's book-title and tack the word Callback onto your search then you get more than 10 pages of hits.

pngaz
+1  A: 

Q3. Any alternative to callback?

I prefer the functor form of callback. e.g. this sort of thing:

class WidgetContainerOrProcessorOfSomeSort
{
public:
  struct IWidgetFunctor
  {
    virtual bool operator()( const Widget& thisWidget )=0;
  };
  ....
  bool ProcessWidgets( IWidgetFunctor& callback )
  {
     .....
     bool continueIteration = callback( widget[ idxWidget ] );
     if ( !continueIteration ) return false;
     .....
  }
};

struct ShowWidgets : public WidgetContainerOrProcessorOfSomeSort::IWidgetFunctor
{
  virtual bool operator(){ const Widget& thisWidget }
  {
     thisWidget.print();
     return true;
  }
};

WidgetContainterOrProcessorOfSomeSort wc;
wc.ProcessWidgets( ShowWidgets() );

It always seems a bit verbose for simple samples, but in the real world I find it much easier than trying to remember exactly how to construct complex function pointer declarations :-)

Andy J Buchanan
+1  A: 
  1. Callbacks decrease coupling as they allow you to write code that calls a function that can be changed
  2. Callbacks are not evil, just that if you are using raw function pointers things can get messy really fast.
  3. There isn't an alternative to callbacks per se, but there are alternatives to using raw function pointers.

A post pointing to Boost was made earlier for Boost.Function. If you are looking for a more generic solution for callbacks, such as multiple functions attached to the same callback or something like that, consider using Boost.Signals. The name comes from signals and slots, which is the way some people refer to callbacks nowadays, especially for GUIs.

blwy10