Send an unknown method call: Difference between revisions
m (changed the ;C.f. to ;Related task, added whitespace before the TOC.) |
m (added a ;Task to the task's preamble.) |
||
Line 1: | Line 1: | ||
{{task|Object oriented}} |
{{task|Object oriented}} |
||
;Task: |
|||
Invoke an object method where the name of the method to be invoked can be generated at run time. |
Invoke an object method where the name of the method to be invoked can be generated at run time. |
||
;Related tasks: |
;Related tasks: |
Revision as of 21:50, 5 September 2017
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Invoke an object method where the name of the method to be invoked can be generated at run time.
- Related tasks
AutoHotkey
This object has 3 methods, and asks the user to name one to call. Instead of using Func(), one could use a class definition. <lang AHK>obj := {mA: Func("mA"), mB: Func("mB"), mC: Func("mC")} InputBox, methodToCall, , Which method should I call? obj[methodToCall].()
mA(){
MsgBox Method A
} mB(){
MsgBox Method B
} mC(){
MsgBox Method C
} </lang>
Bracmat
<lang Bracmat>(task=
( oracle = (predicate="is made of green cheese") (generateTruth=.str$(!arg " " !(its.predicate) ".")) (generateLie=.str$(!arg " " !(its.predicate) "!")) )
& new$oracle:?SourceOfKnowledge & put
$ "You may ask the Source of Eternal Wisdom ONE thing.
Enter \"Truth\" or \"Lie\" on the next line and press the <Enter> key. " & whl
' ( get':?trueorlie:~Truth:~Lie & put$"Try again\n" )
& put$(str$("You want a " !trueorlie ". About what?" \n)) & get'(,STR):?something & (SourceOfKnowledge..str$(generate !trueorlie))$!something ); </lang>
- Example:
{?} !task You may ask the Source of Eternal Wisdom ONE thing. Enter "Truth" or "Lie" on the next line and press the <Enter> key. "Lie" You want a Lie. About what? The sea {!} The sea is made of green cheese!
C#
<lang csharp>using System;
class Example {
public int foo(int x) { return 42 + x; }
}
class Program {
static void Main(string[] args) { var example = new Example(); var method = "foo"; var result = (int)example.GetType().GetMethod(method).Invoke(example, new object[]{ 5 }); Console.WriteLine("{0}(5) = {1}", method, result); }
} </lang>
- Output:
foo(5) = 47
Caché ObjectScript
$METHOD executes a named instance method for a specified instance of a designated class.
<lang cos>Class Unknown.Example Extends %RegisteredObject {
Method Foo() { Write "This is foo", ! }
Method Bar() { Write "This is bar", ! }
}</lang>
- Examples:
USER>Set obj=##class(Unknown.Example).%New() USER>Do $Method(obj, "Foo") This is foo USER>Do $Method(obj, "Bar") This is bar
Common Lisp
Unknown methods are called just like any other function. Find the method-naming symbol using INTERN then call it with FUNCALL. <lang lisp>(funcall (intern "SOME-METHOD") my-object a few arguments)</lang>
Déjà Vu
<lang dejavu>local :object { :add @+ } local :method :add
!. object! method 1 2</lang>
- Output:
3
E
This example goes well with the object named example
in Respond to an unknown method call#E.
<lang e>for name in ["foo", "bar"] {
E.call(example, name, [])
}</lang>
Elena
ELENA 3.2 : <lang elena>import extensions.
class Example {
foo : x = x + 42.
}
program = [
var example := Example new. var methodSignature := "foo". var result := example~(Signature new literal:methodSignature) eval:5. console printLine(methodSignature,"(",5,") = ",result).
].</lang>
- Output:
foo(5) = 47
Forth
Works with any ANS Forth
Needs the FMS-SI (single inheritance) library code located here: http://soton.mpeforth.com/flag/fms/index.html <lang forth>include FMS-SI.f include FMS-SILib.f
var x \ instantiate a class var object named x
\ Use a standard Forth string and evaluate it. \ This is equivalent to sending the !: message to object x 42 x s" !:" evaluate
x p: 42 \ send the print message ( p: ) to x to verify the contents
</lang>
Go
<lang go>package main
import (
"fmt" "reflect"
)
type example struct{}
// the method must be exported to be accessed through reflection. func (example) Foo() int {
return 42
}
func main() {
// create an object with a method var e example // get the method by name m := reflect.ValueOf(e).MethodByName("Foo") // call the method with no argments r := m.Call(nil) // interpret first return value as int fmt.Println(r[0].Int()) // => 42
}</lang>
Groovy
<lang grrovy>class Example {
def foo(value) { "Invoked with '$value'" }
}
def example = new Example() def method = "foo" def arg = "test value"
assert "Invoked with 'test value'" == example."$method"(arg)</lang>
Icon and Unicon
<lang Unicon>procedure main()
x := foo() # create object x.m1() # static call of m1 method # two examples where the method string can be dynamically constructed ... "foo_m1"(x) # ... need to know class name and method name to construct name x.__m["m1"] # ... general method (better)
end
class foo(a,b,c) # define object method m1(x) end end</lang>
For more information on this see Respond to an unknown method call.
Io
String literal "foo" may be replaced by any expression resulting in a string. <lang Io>Example := Object clone Example foo := method(x, 42+x)
name := "foo" Example clone perform(name,5) println // prints "47"</lang>
J
Solution: There are multiple ways to evoke code at runtime. The most common is ". y (evaluate the code in the string y, producing a noun), but there's also 'name'~ (which will modify J's stack by replacing the two tokens 'name' and ~ with the named object) as well as x 128!:2 y (apply the verb described by x to the noun y).
There are other methods as well, e.g., @.,`:, and ^:, though these are designed to consume gerunds (pre-parsed ASTs) rather than strings (though, of course, a pre-processor can always be provided to convert strings into ASTs before feeding them to these operators).
Example:<lang j> sum =: +/
prod =: */ count =: #
nameToDispatch =: 'sum' NB. pick a name already defined
". nameToDispatch,' 1 2 3'
6
nameToDispatch~ 1 2 3
6
nameToDispatch (128!:2) 1 2 3
6
nameToDispatch =: 'count' NB. pick another name
". nameToDispatch,' 1 2 3'
3
nameToDispatch~ 1 2 3
3
nameToDispatch (128!:2) 1 2 3
3</lang>
Java
Using reflection <lang java>import java.lang.reflect.Method;
class Example {
public int foo(int x) { return 42 + x; }
}
public class Main {
public static void main(String[] args) throws Exception { Object example = new Example(); String name = "foo"; Class<?> clazz = example.getClass(); Method meth = clazz.getMethod(name, int.class); Object result = meth.invoke(example, 5); // result is int wrapped in an object (Integer) System.out.println(result); // prints "47" }
}</lang>
JavaScript
String literal "foo" may be replaced by any expression resulting in a string <lang javascript>example = new Object; example.foo = function(x) {
return 42 + x;
};
name = "foo"; example[name](5) # => 47</lang>
Kotlin
When you try to compile the following program, it will appear to the compiler that the local variable 'c' is assigned but never used and a warning will be issued accordingly. You can get rid of this warning by compiling using the -nowarn flag. <lang scala>// Kotlin JS version 1.1.4-3
class C {
fun foo() { println("foo called") }
}
fun main(args: Array<String>) {
val c = C() val f = "c.foo" js(f)() // invokes c.foo dynamically
}</lang>
- Output:
foo called
Lasso
<lang Lasso>define mytype => type { public foo() => { return 'foo was called' } public bar() => { return 'this time is was bar' } } local(obj = mytype, methodname = tag('foo'), methodname2 = tag('bar'))
- obj->\#methodname->invoke
- obj->\#methodname2->invoke</lang>
- Output:
foo was called this time is was bar
Lingo
<lang lingo>obj = script("MyClass").new() -- ... method = #foo arg1 = 23 res = call(method, obj, arg1)</lang>
Logtalk
For this task, we first define a simple object with a single method: <lang logtalk>:- object(foo).
:- public(bar/1). bar(42).
- - end_object.</lang>Second, we define another object that asks the user for a message to be sent to the first object:<lang logtalk>
- - object(query_foo).
:- public(query/0). query :- write('Message: '), read(Message), foo::Message. write('Reply: '), write(Message), nl.
- - end_object.</lang>After compiling and loading both objects, we can try:
| ?- query_foo::query. Message: bar(X). Reply: bar(42)
Lua
Don't forget to pass the object for methods! <lang lua>local example = { } function example:foo (x) return 42 + x end
local name = "foo" example[name](example, 5) --> 47</lang>
Mathematica
Creates a dialog box where one can type a function (Sin, Cos, Tan ...) and then a second dialog box for a value. <lang>ToExpression[Input["function? E.g. Sin",]][Input["value? E.g. 0.4123"]]</lang>
- Output:
Input: Sin Input: 3.1415 Output: 0.0000926536
MATLAB / Octave
<lang Matlab>
funName = 'foo'; % generate function name feval (funNAME, ...) % evaluation function with optional parameters
funName = 'a=atan(pi)'; % generate function name eval (funName, 'printf(Error\n)')
</lang>
Objective-C
<lang objc>#import <Foundation/Foundation.h>
@interface Example : NSObject - (NSNumber *)foo; @end
@implementation Example - (NSNumber *)foo {
return @42;
} @end
int main (int argc, const char *argv[]) {
@autoreleasepool {
id example = [[Example alloc] init]; SEL selector = @selector(foo); // or = NSSelectorFromString(@"foo"); NSLog(@"%@", [example performSelector:selector]); } return 0;
}</lang>
The performSelector: ...
methods can only be used with methods with 0 - 2 object arguments, and an object or void
return type. For all other calls, one can create an NSInvocation
object and invoke it, or directly call one of the objc_msgSend
family of runtime functions.
Oforth
A method object can be retrieved from its name using asMethod. <lang Oforth>16 "sqrt" asMethod perform</lang>
Others :
asFuntion : retrieve a function asClass : retrieve a class asProperty : retrieve a property
A generic way to search a word into the dictionary in to use find method : <lang Oforth>16 "sqrt" Word find perform</lang>
PARI/GP
<lang parigp>foo()=5; eval(Str("foo","()"))</lang>
Perl
<lang perl>package Example; sub new {
bless {}
} sub foo {
my ($self, $x) = @_; return 42 + $x;
}
package main; my $name = "foo"; print Example->new->$name(5), "\n"; # prints "47"</lang>
Perl 6
Just for the fun of it, we'll mix in an anonymous role into an integer instead of defining a class. <lang perl6>my $object = 42 but role { method add-me($x) { self + $x } } my $name = 'add-me'; say $object."$name"(5); # 47</lang> The double quotes are required, by the way; without them the variable would be interpreted as a hard ref to a method.
Phix
Not specifically anything to do with objects, but you can construct routine names at runtime: <lang Phix>procedure Hello()
?"Hello"
end procedure
string erm = "Hemmm" for i=3 to 5 do
erm[i]+=-1+(i=5)*3
end for
call_proc(routine_id(erm),{})</lang>
PHP
<lang php><?php class Example {
function foo($x) { return 42 + $x; }
}
$example = new Example();
$name = 'foo'; echo $example->$name(5), "\n"; // prints "47"
// alternately: echo call_user_func(array($example, $name), 5), "\n"; ?></lang>
PicoLisp
This can be done with the 'send' function. <lang PicoLisp>(send (expression) Obj arg1 arg2)</lang>
Pike
with [] instead of -> a string can be used to name a method: <lang Pike>string unknown = "format_nice"; object now = Calendar.now(); now[unknown]();</lang>
PowerShell
A random method using a random number: <lang PowerShell> $method = ([Math] | Get-Member -MemberType Method -Static | Where-Object {$_.Definition.Split(',').Count -eq 1} | Get-Random).Name $number = (1..9 | Get-Random) / 10 $result = [Math]::$method($number) $output = [PSCustomObject]@{
Method = $method Number = $number Result = $result
}
$output | Format-List </lang>
- Output:
Method : Atan Number : 0.5 Result : 0.463647609000806
Python
String literal "foo" may be replaced by any expression resulting in a string <lang python>class Example(object):
def foo(self, x): return 42 + x
name = "foo" getattr(Example(), name)(5) # => 47</lang>
Qi
<lang qi> (define foo -> 5)
(define execute-function
Name -> (eval [(INTERN Name)]))
(execute-function "foo") </lang>
Racket
<lang racket>
- lang racket
(define greeter
(new (class object% (super-new) (define/public (hello name) (displayln (~a "Hello " name "."))))))
- normal method call
(send greeter hello "World")
- sending an unknown method
(define unknown 'hello) (dynamic-send greeter unknown "World") </lang>
Ruby
You may replace :foo, :bar or "bar" with any expression that returns a Symbol or String.
<lang ruby>class Example
def foo 42 end def bar(arg1, arg2, &block) block.call arg1, arg2 end
end
symbol = :foo Example.new.send symbol # => 42 Example.new.send( :bar, 1, 2 ) { |x,y| x+y } # => 3 args = [1, 2] Example.new.send( "bar", *args ) { |x,y| x+y } # => 3</lang>
Object#send can also call protected and private methods, skipping the usual access checks. Ruby 1.9 adds Object#public_send, which only calls public methods.
<lang ruby>class Example
private def privacy; "secret"; end public def publicity; "hi"; end
end
e = Example.new e.public_send :publicity # => "hi" e.public_send :privacy # raises NoMethodError e.send :privacy # => "secret"</lang>
Scala
<lang scala>class Example {
def foo(x: Int): Int = 42 + x
}
object Main extends App {
val example = new Example
val meth = example.getClass.getMethod("foo", classOf[Int])
assert(meth.invoke(example, 5.asInstanceOf[AnyRef]) == 47.asInstanceOf[AnyRef], "Not confirm expectation.") println(s"Successfully completed without errors. [total ${scala.compat.Platform.currentTime - executionStart} ms]")
}</lang>
Sidef
<lang ruby>class Example {
method foo(x) { 42 + x }
}
var name = 'foo' var obj = Example()
say obj.(name)(5) # prints: 47 say obj.method(name)(5) # =//=</lang>
Smalltalk
<lang smalltalk>Object subclass: #Example.
Example extend [
foo: x [ ^ 42 + x ] ].
symbol := 'foo:' asSymbol. " same as symbol := #foo: "
Example new perform: symbol with: 5. " returns 47 "</lang>
The perform:with:with:
family of methods exist for methods with 0 - 2 (3 in GNU Smalltalk) arguments. For methods with more arguments, use perform:withArguments:
, which takes an array of arguments.
Tcl
Method names are really just strings, i.e., ordinary values that can be produced by any mechanism: <lang tcl>package require Tcl 8.6 oo::class create Example {
method foo {} {return 42} method 1 {s} {puts "fee$s"} method 2 {s} {puts "fie$s"} method 3 {s} {puts "foe$s"} method 4 {s} {puts "fum$s"}
} set eg [Example new] set mthd [format "%c%c%c" 102 111 111]; # A "foo" by any other means would smell as sweet puts [$eg $mthd] for {set i 1} {$i <= 4} {incr i} {
$eg $i ...
}</lang>
- The above produces this output:
42 fee... fie... foe... fum...
zkl
<lang zkl>name:="len"; "this is a test".resolve(name)() //-->14</lang>
- Programming Tasks
- Object oriented
- AutoHotkey
- Bracmat
- C sharp
- Caché ObjectScript
- Common Lisp
- Déjà Vu
- E
- Elena
- Forth
- Go
- Groovy
- Unicon
- Io
- J
- Java
- JavaScript
- Kotlin
- Lasso
- Lingo
- Logtalk
- Lua
- Mathematica
- MATLAB
- Octave
- Objective-C
- Oforth
- PARI/GP
- Perl
- Perl 6
- Phix
- PHP
- PicoLisp
- Pike
- PowerShell
- Python
- Qi
- Racket
- Ruby
- Scala
- Sidef
- Smalltalk
- Tcl
- Zkl
- Ada/Omit
- Axe/Omit
- BASIC/Omit
- C/Omit
- GUISS/Omit
- REXX/Omit
- ZX Spectrum Basic/Omit