tango.core.Signal API should allow return types
The problem and solution
Currently the tango.core.Signal only allows for delegates and functions that return void. This is also in the current API itself, as all the arguments passed to the Signal!() are the argument types. It would be better for Tango signals to follow the established standard of taking the first argument to the Signal!() template as the return type of the delegate/function. E.g. Signal!(void, int) would
create a signal with the return type void and an int argument. Signal!(float, float, int, bool) would have float as it's return type. Signal!(void) would be a plain Signal without any arguments and returning void. (Perhaps that could be further simplified to Signal!()...)
Why's this important to fix before Tango 1.0
This is a fundamental change to the Signal API. Currently the fist argument just tells the first argument of the delegate/function. So current Tango signal of the form Signal!(float, float) will except two float arguments, but in the new proposed syntax, it will be a delegate/function returning float and taking one float argument. So, the current syntax will be legal, but it will mean totally different things. That's why it should be fixed fast, if everybody would agree that this should be done. Any other fixes to the Signals, and what one can do with them, can wait for later, and they will be additions to the proposed API.
Where's that "standard" established, one might ask?
It seems that the Tango signals draw their inspiration from Qt signals, which seems to require the signals to return void. Although unrelated to the issue, Qt signals were AFAIK one of the first signal systems in C++, but they also need a weird precompiler and aren't standard C++. They are not considered to be modern in that sense. Also the Phobos std.signals seems to follow the slot delegates/functions must return void rule.
There are atleast two major signal libraries that follow standard C++, and are widely used, and more modern than Qt signals. Those would be boost::signals and libsigc++. And then there's a D signal/slot library called sslot. (sslot is in the public domain, and works with Phobos. Download.)
All of these follow the (rather nice) API of having the first parameter define the return type, thus allowing functions and delegates with return types to be attached to signals.
In my world these three set the standard and Qt and std.signals are just archaic (no offence intended, really. Just a figure of speech). Qt has a good reputation, but as it comes to Signals, their implementation certainly isn't the most flexible.
What are the benefits?
The major benefit to me atleast would be the ability to have more flexible Signals, that won't require all your slot functions/delegates to return void. It would save the programmer from the trouble of wrapping some of her/his methods that return something, inside methods that don't. Returning something from the signal is not as important as this added flexibility, but it's an added bonus that can have some interesting benefits (like giving the ability to calculate the average or sum of the return values). Flexibility is the keyword.
So, what should the signal return then - There's multiple slots?
The established standard here is to return the last called delegates/functions return value. That might seem silly, but I think it's good default. Somebody suggested on the #d.tango that the opCall() and call() would return the last returned value, and that there could be an extra T[] callArray() that would return all the returned values in an array. Although I think it wouldn't hurt to have the T[] callArray() to be the default for opCall() too. (And then there would be alias OpCall? call, and T callLast() for the last returned value.)
The sslot uses a special MapSignal? for getting multiple return values, but I don't see that as a good way of doing it.
In addition in boost and libsigc++ there's a way of adding a Marshaller/Combiner class that will take all the return values and do whatever is needed with them (e.g. calculate the sum/average/difference/product/median or some other processing). This could be added later if need be, and could easily be replaced with the proposed T call() and T[] callArray() as suggested above.
Further enhancements
It would be nice to have a way to rebinding and retyping the slots. That would add even more flexibility. They are ways to alter the functions/delegates signature, and pass some extra arguments if need be, to make them compatible with a Signals signature. Those can certainly wait for later, and I haven't got much clue about their technical implementation.