What is the best way of doing delegation in Smalltalk, more specifically in Pharo? I know of the doesNotUnderstand strategy, but it does not delegates subclassResponsability messages.
I was thinking on something that delegates every message send not explicitly implemented on the class to some specified object, like I can do, for example, with #Delegate in Groovy. Is there some already known way of doing this?
doesNotUndersand: will only work on methods that the object does not understand (thus the name), so if you already have implemented a method it will not be used (as is the case with subclassResponsibility.
If you use Pharo 5 (which should be released this week (May 2016)), you could use MetaLinks. It's a bit of an overkill, however what you are doing doesn't seem right to begin with (why would you want to delegate subclassResponsibility)?
In either case, MetaLinks allow to attach runtime behavior to your methods, for example:
You have some method that you want to delegate
MyObject>>someMethod
^ self subclassResponsiblity
And an object to which you wish to delegate to…
MyObject>>delegate
^ delegate
So you create a MetaLink
link := MetaLink new
metaObject: [ :object :selector :arguments |
object delegate perform: selector withArguments: argument ];
selector: #perform:withArguments:;
arguments: #(object selector arguments);
control: #instead.
Which you can install to any method AST you want.
(MyObject>>someMethod ast) link: link.
Now every time the method will be called, instead (that's what the control: does) of executing the method, the arguments of the message (if any) will be given to the block in metaObject:.
Although this should work and is extremely powerful mechanism, right now there are serious disadvantages that currently being addressed:
no documentation
little tooling support (it's pretty hard to debug)
a lot of work (we are working on a framework that would ease this as you would want to easily install them and uninstall them everywhere you need, but it's not ready yet, so it has to be done by hand)
recompilation removes the link (see point above)
Summary
To summarize, this is possible to do with MetaLinks as I've shown, however at the moment it's quite a lot of work, but we are addressing those issues.
what Peter was talking about is, you can override the
subclassResponsibility, just like you did for the doesNotUnderstand method.
There is no need to override every senders of "self subclassResponsibility".
For example, just delegate to the implementation of doesNotUnderstand
subclassResponsibility
^ self
doesNotUnderstand: (Message selector: thisContext sender selector
arguments: thisContext sender arguments)
Related
I understand what purpose protocols serve (to have a type conform to a set list of methods or/and properties), but I don't understand what the purpose is of a protocol with all optional methods. One example would be UITextFieldDelegate.
If all methods are optional in a protocol, why would you conform to the protocol instead of just writing the methods from scratch in your class? I don't see what the benefit or purpose of conforming to the protocol is in this case.
Are the optional methods there just as suggestions of functionality that could be implemented?
Historically, for delegates and data sources in Cocoa, informal protocols were used. Informal protocol was implemented trough a category for NSObject class:
#interface NSObject (NSTableViewDelegate)
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
// ...
#end
Later, optional methods in protocols were introduced. This change leads to better documenting of class responsibilities. If you see in code, that class conforms to NSTableViewDelegate, you suspect that somewhere exists a table view, that managed by instance of this class.
Also, this change leads to stronger checks in compile time. If programmer accidentally assign wrong object to delegate or dataSource properties, compiler will warn.
But your assumption is also correct. Optional methods are also suggestions for possible functionality.
By default, all methods in a protocol are required. Each method has to be marks as optional if the nor required for everything to function correctly.
If all methods are optional in a protocol, why would you conform to the protocol instead of just writing the functions from scratch in your class?
Conforming to a protocol allow your class to tell another object the methods it has without the other object needing to know about your class. This is really useful when using Delegation as it allows the delegate to decide what information they wish to receive/provide to another class.
For example,the UIScrollViewDelegate protocol only defines optional methods. Lets say we have a class Foo that we want to know when things change with a UIScrollView.
If we decided to throw that protocol away and implement the functions from scratch, how would we tell UIScrollView which methods we implement and which methods to call when certain event occur? There is no good way it could find out. When UIScrollView was built, it didn't know about Foo so it can't know what methods it implements. Also, Foo has no way of knowing what methods can be called on it by the UIScrollView.
However, when UIScrollView was built, it did know about UIScrollViewDelegate. So if Foo conforms the the UIScrollViewDelegate protocol, there is now a common definition that both Foo and UIScrollView can follow. So Foo can implement any methods it cares about, like scrollViewDidScroll: and the UIScrollView just needs to check if the delegate implemented the methods in UIScrollViewDelegate.
The protocol establishes a contract for the interface between one object and another. The fact that the methods are optional simply says that you don't have to implement that particular method, but you can if your app calls for it.
Generally, if you're conforming to a protocol for which all of the methods are optional, though, you're doing that for a reason, namely that you plan on implementing one or more of those methods. Just because all of the protocol's methods are optional doesn't mean you will not implement any of them, but rather simply that you can elect which are relevant in your particular situation.
For example, consider the UITextFieldDelegate protocol. You'd generally conform to that because you want to specify, for example, whether certain characters should be allowed to be inserted into the text field or what to do when the return key is pressed. Sometimes you only want to implement the former. Sometimes you only want to implement the latter. Sometimes you do both. But just because you choose to implement one or the other doesn't mean you necessarily want to do other one (but you can if you want). Frankly, though, if you really didn't want to implement any of the methods, you probably wouldn't even bother to specify the delegate of the text field, nor bother to specify that you're conforming to the protocol.
Bottom line, the protocol that consists solely of optional methods basically says "if you need it, this is the documented interface for the methods you may elect to implement". The protocol still is very useful to establish the possible interfaces, but doesn't force you to implement those methods you do not need.
I really hope someone can answer this one. I think I am definitely not the only one confused about this and I wasn't able to find anything that clearly explains this concept.
My understanding of the delegation pattern comes from studying the Cocoa framework. To me, the Cocoa implementation is very clear. But I am having a very hard time understanding it in Ruby (standard library's Delegator, SimpleDelegator vs. ActiveSupport's Delegate). It makes little sense to me. Mostly because one is type safe the other is duck type. You can see my point already, but allow me to expand... Here is my summary of how to use the delegate pattern in Cocoa:
Our "ingredients" are: 2 classes, A and B and a protocol, which is Cocoa for a pre-defined set of methods to use for delegation.
The implementation of the pattern is basically as follows:
A defines the set of methods to delegate to B.
B's delegate is set to be A
=> B can now call delegated methods like so: #delegate.send(a_delegated_method)
What I am not tying together is the fact that Ruby uses duck typing, so you can send any method call to any object, right? So using the pattern I just explained, as long as the 2 objects are in the same domain you can say while in A #b.send(:a_delegated_method) and vice versa while in B #a.send(:another_delegated_method).
Could it be that the point with delegates in Ruby is where the delegated method is defined? Meaning that we send from within class A to property #b (#b(:delegated_method)) a :delegated_method defined within A itself?
Hope this isn't too confusing. I myself am confused about why delegates even exist in a duck typing language and what the differences are between Delegator, SimpleDelegator and ActiveSupport's Delegate.
It isn't clear to me that you have understood how delegation works in Cocoa. It is true that the common variety of the delegation pattern in Cocoa involves a protocol, but that's just a way of quieting the compiler.
So let's talk first about quieting the compiler. You can't send the woohoo message to an object in Objective-C unless one of two things is true:
The compiler has reason to believe that this object might respond to the woohoo message.
The compiler is made to suspend judgment.
Nowadays, the first approach is usually used - that's what a protocol is for. But this was not always the case. It used to be that delegation depended mostly on informal protocols. And there still are informal protocols in Cocoa. The idea is that either the method is injected into NSObject by a category, or else you are careful to type the object as id so that it can be sent any message at all.
Now let's talk about dynamism. The reason informal protocols are no longer used is that a feature was introduced allowing protocols to declare optional members. But dynamism is still needed! We may satisfy the compiler, one way or another, but at runtime we have to make sure that it is safe to send a certain message to a certain object. Your app delegate may adopt UIApplicationDelegate, but Cocoa is not going to send it the applicationDidBecomeActive: message unless your app delegate class implements applicationDidBecomeActive: - if it did, you'd crash, and that wouldn't be very nice.
Moreover, if you can just get past the compiler, you can perform delegation in Objective-C even more dynamically than that, as explained here:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html
The idea is that we go right ahead at runtime and send the object the message anyway! If a message arrives that Object A can't handle, it can see if Object B handles it. If it does, it passes the message along to Object B. So we might not crash after all!! I use that approach in one of my apps:
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([self.originalDataSource respondsToSelector: aSelector])
return self.originalDataSource;
return [super forwardingTargetForSelector:aSelector];
}
In that code, I'm saying that if a message arrives and I can't handle it, I should try to get it sent on to another object, called self.originalDataSource.
If you think about it, that is almost identical to Ruby delegation. I have a helper object, and messages that I can't handle are passed on to it.
Another common use of this pattern is when wrapping a Cocoa collection. You can't subclass, say, NSArray, because it's a class cluster, so the proper approach is to wrap it. You then just forward everything to the NSArray, and presto, you are duck-typed as an NSArray! You look like an NSArray as far as your methods are concerned. Then you introduce some difference in behavior, and now you are duck-typed as a customized NSArray.
I'm wondering why protocols are used in swift. In every case I've had to use one so far (UICollectionViewDelegate, UICollectionViewDataSource) I've noted that they don't even have to be added to the class declaration for my code to work. All they do is make it such that your class needs to have certain methods in it so that it can compile. Beats me why this is useful other then as a little post it note to help you keep track of what your classes do.
I'm assuming I'm wrong though. Would anyone care to point out why to me please?
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like.
So it's basically an interface, right?
You use an interface when you want to define a "contract" for your code. In most cases, the purpose of this is to enable multiple implementations of that contract. For example, you can provide a real implementation, and a fake one for testing.
Further Reading
Protocols
What is the point of an Interface?
It allows flexible linkage between parts of code. Once the protocol is defined it can be used by code that doesn't need to know what will be done when the methods are called or exactly what object (or struct or enum) is actually being used. An alternative approach could be setting callbacks or blocks but by using a protocol as complete set of behaviours can be grouped and documented.
Some other code will typically create the concrete instance and pass it to the code expecting the protocol (sometimes the concrete instance will pass itself). In some cases neither the implementation of the code using it need to be aware of each other and it can all be set up by some other code to keep it reusable and testable.
It might be possible to do this in some languages by duck typing which is to say that a runtime inspection could allow a object to act in such a context without particular declaration but this is probably not possible to do at compile time in all cases and it could also be error prone if worked out implicitly.
WebView supports, through the WebEditingDelegate, a mechanism for the delegate to implement custom behavior for a variety of actions the WebView (or the private WebHTMLView) receives. When an action such as:
-(void)changeAttributes:(id)sender
is received in WebHTMLView, it is passed through to the delegate method:
-(BOOL)webView:(WebView *)webView doCommandBySelector:(SEL)command
Unfortunately, the mechanism does not provide for conveyance of the "sender" in the original action method.
For the vast majority of actions, the sender is unimportant, but for changeAttributes, and changeFont, for example, the contract requires that "sender" be called by the recipient in order to e.g. convertAttributes: or convertFont:.
For the changeFont case, it turns out that calling [[NSFontManager sharedFontManager] convertFont:] is sufficient, as coincidentally this is what the sender is.
In the changeAttributes case, in particular when strikethrough is changed, the sender may be a private class "NSFontEffectsBox" which presumably corresponds to the subsection of the font panel that is responsible for changing strikethrough/etc settings.
Unfortunately, calling [[NSFontManager sharedFontManager] convertAttributes:] does NOT obtain the expected attribute changes. This leaves a delegate who is interested in implementing this method meaningfully in a bit of a conundrum:
WebKit does not convey the sender, so the delegate can't make the contractual [sender convertAttributes:] call.
The changeAttributes: call is sent to a private WebKit class, WebHTMLView, which cannot be subclassed to, e.g., customize the behavior of changeAttributes:.
The sender for the changeAttributes: call, NSFontEffectsBox, is a private class and cannot be accessed e.g. as [NSFontEffectsBox sharedFontEffectsBox].
In short: there appears to be no way for a developer to meaningfully override the behavior of changeAttributes: for a WebView.
Any ideas?
This is an evil one. A suitably evil pair of actions (neither of them particularly clean or ideal) would be:
Do some inline assembler to look back up the stack to read the sender argument from the caller's stack (or the caller's caller, as the case should be). This of course assumes that the sender is placed on the stack and not in %eax when the call to WebHTMLView was made. That will always apply to PowerPC code however, so it's likely a non-starter there.
Put a category on WebHTMLView with a method named something like __my_evil_hacky_nasty_ugly_changeAttributes_thing: and at runtime use method_exchangeImplementations() from the ObjC runtime to swap your category's implementation with theirs. Your method becomes changeAttributes: and theirs becomes __my_evil_hacky_nasty_ugly_changeAttributes_thing:, which you can then call to pass on the original call.
As I said, neither is particularly ideal, but the second has the advantage of full runtime support (i.e. the runtime is explicitly designed to let you do this), and since you're looking up the class and methods at runtime, it's failure-tolerant. Failure in this case gets you back to square one however.
Really it needs a bug logged against WebKit to have them pass on the sender to make it meaningful at all. Your overridden version could potentially look for a method -(BOOL)webView:(WebView*)webView doCommandBySelector:(SEL)selector sender:(id)sender and call that if found, otherwise just call through to the original method. This is what Apple's code should be doing, TBH.
Have you looked at the source code?
WebHTMLView.mm
I don't see how -changeAttributes: is calling -webView:doCommandBySelector:, as within this class it's only called inside its own -doCommandBySelector: method.
- (void)changeAttributes:(id)sender
{
[self _applyStyleToSelection:[self _styleForAttributeChange:sender] withUndoAction:EditActionChangeAttributes];
}
- (void)doCommandBySelector:(SEL)aSelector
{
…
if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:aSelector] && coreFrame) {
…
}
Also, why can't you subclass WebHTMLView? Is it because of the Mac App Store restrictions on API? Does WebKit count as private? I thought it was Open Source.
-Wil
I would like to code a proxy that forwards method invocations to another object over TCP without NSConnection and NSDistanceObject stuff. What I want is my own protocol.
The problem is that subclassing NSProxy and overriding forwardInvocation: is not sufficient. I have also to override methodSignatureForSelector
Here is my question:
– (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return ???
}
#Brian, This may be ok, but setProtocolForProxy: is just for optimization. cocoafan could mandate it for his solution, but it wouldn't be a drop-in replacement. You're supposed to be able to get signatures automatically. To do that, the network protocol needs a way to request the signature.
I believe the solution here is to include in the network protocol a "request method signature" method, and have it run methodSignatureForSelector: on the distant object and encode and return the result. That's what NSDistantObject does.
Providing setProtocolForProxy: is an important optimization if you're going to chatter a lot, but it does restrict you to objects that you have a protocol for, and prior to 10.5 that introduces some annoying limitations (all methods are required). Even on 10.5, it may introduce some problematic limitations if it's the only way to get method signatures.
#cocoafan, I think you're probably right to create this from scratch on top of NSProxy, but do take a look at NSConnection and see if you can sub-class it to manage the network connection the way you want. If you can find a way to do that (though I don't see an easy way right off), you'll probably get a lot of stuff for free from NSDistantObject.
The way NSDistantObject handles this is by its setProtocolForProxy: method, which specifies a protocol containing the list of methods that the object on the other end of the connection handles. It can then use the information for these methods to provide appropriate NSMethodSignature objects when doing forwarding.
It looks like the most straightforward to do that is via the protocol_getMethodDescription() function, declared in <objc/runtime.h>. This returns an objc_method_description struct which contains a types field. I believe you should be able to pass that value into +[NSMethodSignature signatureWithObjCTypes:] to get a method signature object that matches what's declared in the protocol.
I found a smart solution to generate NSInvocation objects.