Respond to an unknown method call: Difference between revisions
(→{{header|Tcl}}: ++ smalltalk) |
m (→{{header|Smalltalk}}: removed a commented code) |
||
Line 224: | Line 224: | ||
bar [ 'bar received' displayNl ] |
bar [ 'bar received' displayNl ] |
||
doesNotUnderstand: aMessage [ |
doesNotUnderstand: aMessage [ |
||
"aMessage selector asString printNl." |
|||
('message "' , (aMessage selector asString) , '"') displayNl. |
('message "' , (aMessage selector asString) , '"') displayNl. |
||
(aMessage arguments) do: [ :a | |
(aMessage arguments) do: [ :a | |
||
Line 237: | Line 236: | ||
a weCanDoIt. |
a weCanDoIt. |
||
a theyCanToo: 'eat' and: 'walk'.</lang> |
a theyCanToo: 'eat' and: 'walk'.</lang> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
Revision as of 11:09, 8 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>
PHP
<lang php><?php class Example {
function foo() { echo "this is foo\n"; } function bar() { echo "this is bar\n"; } function __call($name, $args) { echo "tried to handle unknown method $name\n"; if ($args) echo "it had arguments: ", implode(', ', $args), "\n"; }
}
$example = new 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>
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>
Slate
Here is an example of unknown methods being used to call shell commands (this is already defined in the base image):
<lang slate> define: #shell &builder: [lobby newSubSpace].
_@shell didNotUnderstand: message at: position "Form a command string and execute it." [
position > 0 ifTrue: [resend] ifFalse: [([| :command |
message selector isUnarySelector ifTrue: [command ; message selector. message optionals pairsDo: [| :key :value | command ; ' -' ; (key as: String) allButFirst allButLast ; ' ' ; (value as: String)]]. message selector isKeywordSelector ifTrue: [| keywords args | keywords: ((message selector as: String) splitWith: $:). command ; keywords first. keywords size = 1 ifTrue: "Read a string or array of arguments." [args: message arguments second. (args is: String) ifTrue: [command ; ' ' ; args] ifFalse: [args do: [| :arg | command ; ' ' ; arg]]]]] writingAs: String) ifNil: [resend] ifNotNilDo: [| :cmd | [Platform run: cmd]]] ]. </lang>
Here is an example of it being used:
<lang slate> slate[1]> shell ls: '*.image'. kernel.new.little.64.1244260494374694.image slate2.image net.image slate.image True slate[2]> </lang>
Smalltalk
<lang smalltalk>Object subclass: CatchThemAll [
foo [ 'foo received' displayNl ] bar [ 'bar received' displayNl ] doesNotUnderstand: aMessage [ ('message "' , (aMessage selector asString) , '"') displayNl. (aMessage arguments) do: [ :a | 'argument: ' display. a printNl. ] ]
]
|a| a := CatchThemAll new. a foo. a bar. a weCanDoIt. a theyCanToo: 'eat' and: 'walk'.</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>