Respond to an unknown method call: Difference between revisions
(added ruby and perl) |
(added objective-c) |
||
Line 19: | Line 19: | ||
} |
} |
||
} |
} |
||
}</lang> |
|||
=={{header|Objective-C}}== |
|||
<code>-forwardInvocation:</code> is usually used to "forward" the message on to another object to handle. |
|||
<lang objc>#include <Foundation/Foundation.h> |
|||
// The methods need to be declared somewhere |
|||
@interface Dummy : NSObject { } |
|||
- (void)grill; |
|||
- (void)ding:(NSString *)s; |
|||
@end |
|||
@interface Example : NSObject { } |
|||
- (void)foo; |
|||
- (void)bar; |
|||
@end |
|||
@implementation Example |
|||
- (void)foo { |
|||
NSLog(@"this is foo"); |
|||
} |
|||
- (void)bar { |
|||
NSLog(@"this is bar"); |
|||
} |
|||
- (void)forwardInvocation:(NSInvocation *)inv { |
|||
NSLog(@"tried to handle unknown method %@", NSStringFromSelector([inv selector])); |
|||
unsigned n = [[inv methodSignature] numberOfArguments]; |
|||
unsigned i; |
|||
for (i = 0; i < n-2; i++) { // first two arguments are the object and selector |
|||
id arg; |
|||
[inv getArgument:&arg atIndex:i+2]; |
|||
NSLog(@"argument #%u: %@", i, arg); |
|||
} |
|||
} |
|||
@end |
|||
int main() |
|||
{ |
|||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|||
id example = [[Example alloc] init]; |
|||
[example foo]; // prints "this is foo" |
|||
[example bar]; // prints "this is bar" |
|||
[example grill]; // prints "tried to handle unknown method grill" |
|||
[example ding:@"dong"]; // prints "tried to handle unknown method ding:" |
|||
// prints "argument #0: dong" |
|||
[example release]; |
|||
[pool release]; |
|||
return 0; |
|||
}</lang> |
}</lang> |
||
Line 45: | Line 98: | ||
my $example = Example->new; |
my $example = Example->new; |
||
$example->foo; # prints |
$example->foo; # prints "this is foo" |
||
$example->bar; # prints |
$example->bar; # prints "this is bar" |
||
$example->grill; # prints |
$example->grill; # prints "tried to handle unknown method Example::grill" |
||
$example->ding("dong"); # prints |
$example->ding("dong"); # prints "tried to handle unknown method Example::ding" |
||
# prints |
# prints "it had arguments: dong" |
||
# prints |
# prints "tried to handle unknown method Example::DESTROY" <- I don't know why it does this</lang> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
Line 68: | Line 121: | ||
example = Example() |
example = Example() |
||
example.foo() # prints |
example.foo() # prints "this is foo" |
||
example.bar() # prints |
example.bar() # prints "this is bar" |
||
example.grill() # prints |
example.grill() # prints "tried to handle unknown method grill" |
||
example.ding("dong") # prints |
example.ding("dong") # prints "tried to handle unknown method ding" |
||
# prints |
# prints "it had arguments: ('dong',)"</lang> |
||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
Line 92: | Line 145: | ||
example = Example.new |
example = Example.new |
||
example.foo # prints |
example.foo # prints "this is foo" |
||
example.bar # prints |
example.bar # prints "this is bar" |
||
example.grill # prints |
example.grill # prints "tried to handle unknown method grill" |
||
example.ding("dong") # prints |
example.ding("dong") # prints "tried to handle unknown method ding" |
||
# prints |
# prints "it had arguments: ["dong"]"</lang> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
Revision as of 08:10, 4 June 2009
You are encouraged to solve this task according to the task description, using any language you may know.
Demonstrate how to make the object respond (sensibly/usefully) to an invocation of a method on it that it does not support through its class definitions. Note that this is not the same as just invoking a defined method whose name is given dynamically; the method named at the point of invocation must not be defined.
This task is intended only for object systems that use a dynamic dispatch mechanism.
E
In E, a message consists of a verb (arbitrary string) and arguments (sequence of arbitrary objects). It is conceptually entirely up to any given object how it dispatches incoming messages.
Practically, the object definition syntax provides a matcher clause to handle unrecognized messages. This example has the same behavior as the Python example.
<lang e>def example {
to foo() { println("this is foo") } to bar() { println("this is bar") } match [verb, args] { println(`got unrecognized message $verb`) if (args.size() > 0) { println(`it had arguments: $args`) } }
}</lang>
Objective-C
-forwardInvocation:
is usually used to "forward" the message on to another object to handle.
<lang objc>#include <Foundation/Foundation.h>
// The methods need to be declared somewhere @interface Dummy : NSObject { } - (void)grill; - (void)ding:(NSString *)s; @end
@interface Example : NSObject { } - (void)foo; - (void)bar; @end
@implementation Example - (void)foo {
NSLog(@"this is foo");
} - (void)bar {
NSLog(@"this is bar");
} - (void)forwardInvocation:(NSInvocation *)inv {
NSLog(@"tried to handle unknown method %@", NSStringFromSelector([inv selector])); unsigned n = [[inv methodSignature] numberOfArguments]; unsigned i; for (i = 0; i < n-2; i++) { // first two arguments are the object and selector id arg; [inv getArgument:&arg atIndex:i+2]; NSLog(@"argument #%u: %@", i, arg); }
} @end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id example = [[Example alloc] init];
[example foo]; // prints "this is foo" [example bar]; // prints "this is bar" [example grill]; // prints "tried to handle unknown method grill" [example ding:@"dong"]; // prints "tried to handle unknown method ding:" // prints "argument #0: dong" [example release];
[pool release];
return 0;
}</lang>
Perl
<lang perl>package Example; sub new {
bless {}
} sub foo {
print "this is foo\n";
} sub bar {
print "this is bar\n";
} sub AUTOLOAD {
my $name = $AUTOLOAD; my ($self, @args) = @_; print "tried to handle unknown method $name\n"; if (@args) { print "it had arguments: @args\n"; }
} 1;
package main; my $example = Example->new;
$example->foo; # prints "this is foo" $example->bar; # prints "this is bar" $example->grill; # prints "tried to handle unknown method Example::grill" $example->ding("dong"); # prints "tried to handle unknown method Example::ding"
# prints "it had arguments: dong" # prints "tried to handle unknown method Example::DESTROY" <- I don't know why it does this</lang>
Python
Python objects can implement a __getattr__()
method to handle accesses of unknown attributes (methods are just attributes that are callable; so this function handles both methods and non-method fields). Here we assume that if you access an unknown attribute, you want a method, so we return a function that can be called.
<lang python>class Example:
def foo(self): print "this is foo" def bar(self): print "this is bar" def __getattr__(self, name): def method(*args): print "tried to handle unknown method " + name if args: print "it had arguments: " + str(args) return method
example = Example()
example.foo() # prints "this is foo" example.bar() # prints "this is bar" example.grill() # prints "tried to handle unknown method grill" example.ding("dong") # prints "tried to handle unknown method ding"
# prints "it had arguments: ('dong',)"</lang>
Ruby
<lang ruby>class Example
def foo puts "this is foo" end def bar puts "this is bar" end def method_missing(name, *args) puts "tried to handle unknown method %s" % name # name is a symbol unless args.empty? puts "it had arguments: %p" % [args] end end
end
example = Example.new
example.foo # prints "this is foo" example.bar # prints "this is bar" example.grill # prints "tried to handle unknown method grill" example.ding("dong") # prints "tried to handle unknown method ding"
# prints "it had arguments: ["dong"]"</lang>
Tcl
<lang tcl># First create a simple, conventional class and object oo::class create Example {
method foo {} { puts "this is foo" } method bar {} { puts "this is bar" }
} Example create example
- Modify the object to have a custom ‘unknown method’ interceptor
oo::objdefine example {
method unknown {name args} { puts "tried to handle unknown method \"$name\"" if {[llength $args]} { puts "it had arguments: $args" } }
}
- Show off what we can now do...
example foo; # prints “this is foo” example bar; # prints “this is bar” example grill; # prints “tried to handle unknown method "grill"” example ding dong; # prints “tried to handle unknown method "ding"”
# prints “it had arguments: dong”</lang>