Dynamic binding -- Qt's Signals and Slots vs Objective-C
Bill Baxter
wbaxter at gmail.com
Tue Sep 26 14:49:53 PDT 2006
Fredrik,
Thanks for this very informative reply.
It definitely seems from your explanations that just going for "Qt-style
signals and slots" in D is "aiming low", and that a basic dynamic
messaging system is more the level of abstraction you'd want. And from
there you can implement Qt-style S&S easily, as you demonstrated.
However, I think taking a 2.5x speed hit (worse for a poorly optimized
implementation) for all method calls will be difficult for D users to
swallow.
It sounds like basically what is required in terms of per-class storage
is a second sort of vtable per class, a dynamic vtable. Maybe more like
a dictionary/hash-table, but anyway you need some place to store
per-class mappings from messages to actual functions. It could probably
be pointed to from the regular vtable in some manner so that each class
instance still only has the overhead of one vtable pointer.
You can go ahead and put every method in the dynamic dispatch vtable.
It's just per-class, so not a huge overhead. Kind of like how every
non-private method in D is virtual. Then I guess it needs to be the
caller's choice whether to use dynamic dispatch or static. So a
separate syntax for making "message"-based calls, like Objective C uses.
Gotta go, but I think some sort of built-in dynamic dispatch mechanism
like this would have to be part of my "dream language".
--bb
Fredrik Olsson wrote:
> First some rech stuff :).
>
> How Qt S&S does it:
>
> Each object can have signals and slots. A signal is an event that can be
> signaled to the "runtime", and a slot is a method that is performed in
> response to a signal.
>
> You connect signals and slots like this:
> connect(&obj1, SIGNAL(valueChanged(int)), &obj2, SLOT(setValue(int)));
> You are free to hook up a signal to as many slots as you like, and to
> different objects.
>
> And you may then later emit this signal (From obj1) using:
> emit valueChanged(42);
> which will cause the setValue(int) slot to be performed.
>
>
> How Obj-C Cocoa does it:
>
> Each object can have an action and a target. An action is an event that
> is signaled at run-time, and the target is an object instance to call.
> If target is nil (null) then the action will be sent to the responder
> chain, instead of a predestined object.
>
> The responder chain is implemented in the NSResponder protocol
> (Interface) and will send the action down the controllers is logical
> order acording to how windows are stacked, ending up in the
> NSApplication instance if no one else is interested. This make sure that
> if a single menu item (OSX == one menu you know :) ) has nil as target,
> then the topmost window will get a chance to respond first, and yet the
> same item will work for all windows.
>
> You connect an action/target like this:
> [obj1 setAction:@selector(valueChanged:)];
> [obj1 setTarget:obj2];
>
> And you can later "emit" the action using:
> [obj1 sendAction:[obj1 action] to:[obj1 target]];
> which will cause the valueChanged: method of obj2 to be performed. In
> reality most classes have shortcuts such as sendAction, and even more so
> you rarely need to care about sending manually at all.
>
>
> Bill Baxter skrev:
> <sbip>
>
>> - Is Qt S&S a subset of Obj-C's messaging?
>
> I think Qt's S&S is more of a superset. Qt allows a signal to trigger
> many slots, while Obj-C have only one target. In short, one button click
> invokes a single action, in Obj-C, while in Qt it could invoke a series
> of actions.
>
> This is more of a design limitation in Cocoa, not in Objective-C.
>
> On the plus-side of Cocoa is that a "signal"/"action" do not need to
> have a target set, but can dynamically find it's target using a
> responder chain, for example targetting the top-most windows document
> controller from a single menu item.
>
>> - Could Qt S&S be implemented using Obj-C messaging?
>
> Yes, no problem. And no hacks :).
>
>> - Could Obj-C-like messaging be implemented using Qt S&S?
>
> Yes, with some problem. The responder chain mechanism needs to be
> implemented.
>
>> - Qt S&S includes an observer pattern in that emit() will call all
>> connected slots. Is this built into Obj-C messaging too?
>
> As I mentioned Cocoa only use one action. So the equivalent of emit()
> would be performAction. But it can only be hooked up to a single
> target/slot.
>
>> - Qt requires derivation from QObject to participate in S&S. Does
>> Obj-C also require deriving from a particular base object? Is it
>> explicit?
>
> More or less. All existing senders are subclasses of NSControl, so using
> those subclasses will let you use say [foo sendAction], and such shorter
> things. In the same way subclasses of NSResponder will automatically fit
> in the responder chain.
>
> But in practice, Obj-C will not care as much of the classes, but of what
> the classes implement. So if you send the action foo: to bar what the
> run-time will do is a:
> if ([bar respondsToSelector:@selector(foo:)]) {
> [bar performSelector:@selector(foo:)];
> }
> And yes, if it does not respond, it is no error, unless you want it to
> be, it is perfctly legal to call methods that are not implemented :).
>
>> - What is the overhead to support Obj-C messaging in a class? Is
>> there a way to create an Obj-C class that doesn't support messaging?
>
> The Obj-C language is build upon this message dispatch, so no way around
> it, each "method call" is a message dispatch. And there is a overhead as
> compared to C++. The run-time uses caching and other neat tricks, so in
> practice a Obj-C method call cost about 2.5 C++ method calls.
>
>> - Do people use Obj-C messaging for anything besides GUIs?
>
> Oooh, yes. The real power here is in the dynamic dispatching of
> messages. Best of all is what is called categories. You can extend a
> class by subclassing, or by adding a category.
>
> NSArray is a base class for static arrays.
> NSMutableArray is a subclass of NSArray that is mutable (dynamic).
> If you wanted to add a method say something useful as reversedArray to
> them, then in C++ (And D) you would need to make two subclasses, one to
> NSArray, and one to NSMutableArray, and it would be dead on impossible
> make a function accept both without typecasting (Ok, add an interface
> then). In Obj-C you can instead add a category to NSArray, and it will
> automatically be added to all subclasses as well. Like this:
> @interface NSArray (ReversedCat)
> - (NSArray *)reversedArray;
> @end
>
> And named arguments rocks, for code readability:
> myFoo.write("bar.txt", true);
> vs
> [myFoo writeToFile:@"bar.txt" atomically:YES];
>
> Same thing cn be done with lots of comments, but is rarely done. And
> short names have already become a bad habit/convention anyway.
>
>>
>> The goal of this questioning, of course, is to encourage discussion
>> about whether these or any other form dynamic binding could / should
>> be added to D.
>
> Could: YES! The first Obj-C compilers where simple preprocessors for C.
> I see no real problem in linking with the GNU Obj-C runtime. And Obj-C
> as such is very tiny, the power lies in the flexibility of the little
> there is.
>
> Should: Not too sure. I would like it, my only problem with Obj-C is the
> C part, so replacing that with D would be nice. But I seriously doubt it
> is worth the trouble, mostly because it is a quite different paradigm,
> and before you understand it you cannot appreciate it.
>
>
>>
>> I've heard many people in C++ land say things to the effect of "Bah,
>> those silly Qt people weren't smart enough realize that you can
>> implement signals and slots directly in C++". But I've not been
>> particularly impressed by the pure C++ S&S libraries I've seen. On
>> the other hand, I found Qt's S&S to be simple, clean, straightforward,
>> and very easy to use. And I've not heard anything but praise about
>> making GUIs with Obj-C. Lutger's S&S for D posted earlier looks very
>> nice, but there must be something neat that Qt S&S--being dynamic--can
>> do that isn't possible with the static S&S solutions. Like
>> enumerating available signals for use in a GUI builder tool.
>>
>> - Is it possible to mix D-style classes with Obj-C style messaging?
>> Apple's Objective-C++ apparently doesn't allow it.
>> http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html
>> I.e. a class is either a C++ class or an Obj-C class. They can call
>> each other, but they are separate. You can't send an Obj-C message to
>> a C++ class. I think the ideal, though, would be something closer to
>> Qt where you have the ability to make any method you want be a slot.
>> In Qt those methods remain valid C++ methods, but you can also call
>> them by name, effectively.
>>
> This is because C++/D and Obj-C works very differently. Lets call the
> object that will have a method called the reciever.
>
> What C++/D does is very simply put: classes are structs with hidden
> function pointers, when calling a method it looks up the function
> pointer at a static offset from the reciever, and jumps. And the class
> better make sure there is a valid function at the other end.
>
> What Obj-C does is that it takes the reciever, and requested method
> message and send to objc_msgSend(), that function looks up the correct
> function pointer for the given reciever and method pair, if found it
> jumps there. If not found it can raise en exception, pass control to a
> "unhandled message" method, or silently ignore.
>
>
> Oh well, hopefully you have less question now at least :).
>
>
> // Fredrik Olsson
More information about the Digitalmars-d
mailing list