views:

737

answers:

3

Don't get me wrong: Boost's bind() is great.

But I do hate to write&read code with it, and I've given up hope my coworkers will ever grok/use it.

I end up with code like this:

btn.clicked.connect(bind(&BetBar::placeBet, this, bet_id));
animator.eachFrame.connect(bind(&Widget::move, buttons[bet_id]));

Which, while logical, is very far from what I'd call nice code.

To demonstrate... in C++1x we'll have this:

btn.clicked.connect([&](int bet_id){ placeBet(bet_id); })
animator.eachFrame.connect([&](Point newPos) { buttons[bet_id].move(newPos) })

And a good DSL could look kinda like this:

on(btn.clicked) placeBet(bet_id);
on(animator.eachFrame) buttons[bet_id].move(eachFrame::newPos);

How do you cope with binding in C++? Do you just live with what boost gives you?

+2  A: 

I doubt you can get any better then this on pre-0x C++. Boost.Lambda or Phoenix provide their own binding mechanisms, but for such cases it won't get any more readable, really.

If you could think of how to program such a DSL within the current C++ using boost::proto (are there any other alternatives?), well, then you may get better help by the only other proto-guys on the boost mailing list itself, as this would be over my head.

For the co-workers: When they are doing programming C++ professionally (read: they get paid for it), they either grok it, or they should do another job. If they can't read such simple constructs, they will probably produce a bigger maintenance burden then they can ever make up with helping on implementing new features.

In such a case, providing a nice binding to Lua (or whatever scripting language you prefer), and make them do the business logic in that language. This is actually a not too bad solution, anyway.

gimpf
proto looks mindblowing, I'll definitely have a deep look at it. Thanks!
+2  A: 

It seems you want the following:

  • Implicit binding to this
  • An alternative for the parentheses associated with the fucntion call which stores the binding.
  • Automatic identification which parameters in your lambda-expression are bound.

The first is very hard in C++ today, as this is implicit in very few contexts, and you certainly cannot pass it to functions implicitly. I.e. you can't achieve this with a library function, but you could with a macro. Still, it would be ugly.

The second part is far easier:

button.clicked.handler = bind(BetBar::placeBet, this, bet_id);

This just requires handler.operator=(boost::function<void(*)()> const&)

The third is hard again, because you have just designed another case of two-phase name lookup. That was hard enough with templates. boost's _1 trick works by making it explicit which arguments should be bound later. However, _1 as name isn't magic. It's basically a free function returning boost::arg<1>. So, with a suitable definition of animator.eachFrame.newPos the following could be made equivalent:

animator.eachFrame.handler = bind(&Widget::move, buttons[bet_id], _1)
animator.eachFrame.handler = bind(&Widget::move, buttons[bet_id], animator.eachFrame.newPos)
MSalters
A: 

As a side note, actually a good DSL could look kinda like this:

btn.clicked { |bet_id| placeBet bet_id }
animator.eachFrame { |newPos| buttons[bet_id].move newPos }

To answer your question: For the simple example you provided a plain bind works just fine.

J.F. Sebastian