Send an unknown method call: Difference between revisions
→{{header|Lasso}}: Adding Lasso example |
PascalABC.NET |
||
(57 intermediate revisions by 33 users not shown) | |||
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. |
||
;Cf: |
|||
;Related tasks: |
|||
* [[Respond to an unknown method call]]. |
* [[Respond to an unknown method call]]. |
||
* [[Runtime evaluation]] |
* [[Runtime evaluation]] |
||
<br><br> |
|||
=={{header|AutoHotkey}}== |
=={{header|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. |
This object has 3 methods, and asks the user to name one to call. Instead of using Func(), one could use a class definition. |
||
< |
<syntaxhighlight lang="ahk">obj := {mA: Func("mA"), mB: Func("mB"), mC: Func("mC")} |
||
InputBox, methodToCall, , Which method should I call? |
InputBox, methodToCall, , Which method should I call? |
||
obj[methodToCall].() |
obj[methodToCall].() |
||
Line 22: | Line 25: | ||
MsgBox Method C |
MsgBox Method C |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Bracmat}}== |
=={{header|Bracmat}}== |
||
< |
<syntaxhighlight lang="bracmat">(task= |
||
( oracle |
( oracle |
||
= (predicate="is made of green cheese") |
= (predicate="is made of green cheese") |
||
Line 44: | Line 47: | ||
& (SourceOfKnowledge..str$(generate !trueorlie))$!something |
& (SourceOfKnowledge..str$(generate !trueorlie))$!something |
||
); |
); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out|Example}} |
{{out|Example}} |
||
<pre>{?} !task |
<pre>{?} !task |
||
Line 53: | Line 56: | ||
The sea |
The sea |
||
{!} The sea is made of green cheese!</pre> |
{!} The sea is made of green cheese!</pre> |
||
=={{header|C sharp|C#}}== |
|||
<syntaxhighlight 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); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
foo(5) = 47 |
|||
=={{header|Caché ObjectScript}}== |
=={{header|Caché ObjectScript}}== |
||
Line 58: | Line 87: | ||
$METHOD executes a named instance method for a specified instance of a designated class. |
$METHOD executes a named instance method for a specified instance of a designated class. |
||
< |
<syntaxhighlight lang="cos">Class Unknown.Example Extends %RegisteredObject |
||
{ |
{ |
||
Line 71: | Line 100: | ||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out|Examples}} |
{{out|Examples}} |
||
<pre> |
<pre> |
||
Line 80: | Line 109: | ||
This is bar |
This is bar |
||
</pre> |
</pre> |
||
=={{header|Clojure}}== |
|||
<syntaxhighlight lang="clojure"> |
|||
(import '[java.util Date]) |
|||
(import '[clojure.lang Reflector]) |
|||
(def date1 (Date.)) |
|||
(def date2 (Date.)) |
|||
(def method "equals") |
|||
;; Two ways of invoking method "equals" on object date1 |
|||
;; using date2 as argument |
|||
;; Way 1 - Using Reflector class |
|||
;; NOTE: The argument date2 is passed inside an array |
|||
(Reflector/invokeMethod date1 method (object-array [date2])) |
|||
;; Way 2 - Using eval |
|||
;; Eval runs any piece of valid Clojure code |
|||
;; So first we construct a piece of code to do what we want (where method name is inserted dynamically), |
|||
;; then we run the code using eval |
|||
(eval `(. date1 ~(symbol method) date2)) |
|||
</syntaxhighlight> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Unknown methods are called just like any other function. Find the method-naming symbol using INTERN then call it with FUNCALL. |
Unknown methods are called just like any other function. Find the method-naming symbol using INTERN then call it with FUNCALL. |
||
<syntaxhighlight lang="lisp">(funcall (intern "SOME-METHOD") my-object a few arguments)</syntaxhighlight> |
|||
=={{header|Déjà Vu}}== |
|||
<lang lisp>(funcall (intern "SOME-METHOD") my-object a few arguments)</lang> |
|||
<syntaxhighlight lang="dejavu">local :object { :add @+ } |
|||
local :method :add |
|||
!. object! method 1 2</syntaxhighlight> |
|||
{{out}} |
|||
<pre>3</pre> |
|||
=={{header|E}}== |
=={{header|E}}== |
||
Line 90: | Line 150: | ||
This example goes well with the object named <code>example</code> in [[Respond to an unknown method call#E]]. |
This example goes well with the object named <code>example</code> in [[Respond to an unknown method call#E]]. |
||
< |
<syntaxhighlight lang="e">for name in ["foo", "bar"] { |
||
E.call(example, name, []) |
E.call(example, name, []) |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Ecstasy}}== |
|||
Here's a simple example of a test module using its runtime type to search for methods by some name (specified on the the command line), grabbing the one by that name that requires no parameters, and dynamically invoking it: |
|||
<syntaxhighlight lang="ecstasy"> |
|||
module test { |
|||
@Inject Console console; |
|||
void run(String[] args) { |
|||
String name = args.empty ? "foo" : args[0]; |
|||
if (val mm := &this.actualType.multimethods.get(name), |
|||
val m := mm.methods.any(m -> m.ParamTypes.size == 0)) { |
|||
m.invoke(this, Tuple:()); |
|||
} else { |
|||
console.print($"No such 0-parameter method: {name.quoted()}"); |
|||
} |
|||
} |
|||
void foo() { |
|||
console.print("this is the foo() method"); |
|||
} |
|||
void bar() { |
|||
console.print("this is the bar() method"); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
x$ xec test foo |
|||
this is the foo() method |
|||
x$ xec test bar |
|||
this is the bar() method |
|||
x$ xec test baz |
|||
No such 0-parameter method: "baz" |
|||
</pre> |
|||
=={{header|Elena}}== |
|||
ELENA 4.1 : |
|||
<syntaxhighlight lang="elena">import extensions; |
|||
class Example |
|||
{ |
|||
foo(x) |
|||
= x + 42; |
|||
} |
|||
public program() |
|||
{ |
|||
var example := new Example(); |
|||
var methodSignature := "foo"; |
|||
var invoker := new MessageName(methodSignature); |
|||
var result := invoker(example,5); |
|||
console.printLine(methodSignature,"(",5,") = ",result) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
foo(5) = 47 |
|||
</pre> |
|||
=={{header|Factor}}== |
|||
Factor's object model is such that objects themselves don't contain methods — generic words do. So there is nothing different about invoking an unknown method than invoking an unknown word in general. |
|||
<syntaxhighlight lang="factor">USING: accessors kernel math prettyprint sequences words ; |
|||
IN: rosetta-code.unknown-method-call |
|||
TUPLE: foo num ; |
|||
C: <foo> foo |
|||
GENERIC: add5 ( x -- y ) |
|||
M: foo add5 num>> 5 + ; |
|||
42 <foo> ! construct a foo |
|||
"add" "5" append ! construct a word name |
|||
! must specify vocab to look up a word |
|||
"rosetta-code.unknown-method-call" |
|||
lookup-word execute . ! 47</syntaxhighlight> |
|||
=={{header|Forth}}== |
|||
{{works with|Forth}} |
|||
Works with any ANS Forth |
|||
Needs the FMS-SI (single inheritance) library code located here: |
|||
http://soton.mpeforth.com/flag/fms/index.html |
|||
<syntaxhighlight 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 |
|||
</syntaxhighlight> |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="basic">Type Example |
|||
foo As Integer Ptr |
|||
Declare Constructor (x As Integer) |
|||
End Type |
|||
Constructor Example(x As Integer) |
|||
This.foo = New Integer |
|||
*This.foo = 42 + x |
|||
End Constructor |
|||
Dim As Example result = 5 |
|||
Print *result.foo |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 47</pre> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 118: | Line 293: | ||
// interpret first return value as int |
// interpret first return value as int |
||
fmt.Println(r[0].Int()) // => 42 |
fmt.Println(r[0].Int()) // => 42 |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Groovy}}== |
|||
<syntaxhighlight 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)</syntaxhighlight> |
|||
==Icon and {{header|Unicon}}== |
==Icon and {{header|Unicon}}== |
||
< |
<syntaxhighlight lang="unicon">procedure main() |
||
x := foo() # create object |
x := foo() # create object |
||
x.m1() # static call of m1 method |
x.m1() # static call of m1 method |
||
Line 132: | Line 320: | ||
method m1(x) |
method m1(x) |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
For more information on this see [[Respond_to_an_unknown_method_call#Icon_and_Unicon|Respond to an unknown method call]]. |
For more information on this see [[Respond_to_an_unknown_method_call#Icon_and_Unicon|Respond to an unknown method call]]. |
||
=={{header|Io}}== |
|||
String literal "foo" may be replaced by any expression resulting in a string. |
|||
<syntaxhighlight lang="io">Example := Object clone |
|||
Example foo := method(x, 42+x) |
|||
name := "foo" |
|||
Example clone perform(name,5) println // prints "47"</syntaxhighlight> |
|||
=={{header|J}}== |
|||
'''Solution''': There are multiple ways to evoke code at runtime. The most common is '''<tt>". y</tt>''' (''eval''uate the code in the string y, producing a noun), but there's also <tt>'name'~ </tt> (which will modify J's stack by replacing the two tokens '''<tt>'name'</tt>''' and <tt>~</tt> with the named object) as well as '''<tt>x 128!:2 y</tt>''' (''apply'' the verb described by <tt>x</tt> to the noun <tt>y</tt>). |
|||
There are other methods as well, e.g., '''<tt>@.</tt>''','''<tt>`:</tt>''', and '''<tt>^:</tt>''', 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''':<syntaxhighlight 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</syntaxhighlight> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
Using reflection |
Using reflection |
||
< |
<syntaxhighlight lang="java">import java.lang.reflect.Method; |
||
class Example { |
class Example { |
||
Line 155: | Line 379: | ||
System.out.println(result); // prints "47" |
System.out.println(result); // prints "47" |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
String literal "foo" may be replaced by any expression resulting in a string |
String literal "foo" may be replaced by any expression resulting in a string |
||
< |
<syntaxhighlight lang="javascript">example = new Object; |
||
example.foo = function(x) { |
example.foo = function(x) { |
||
return 42 + x; |
return 42 + x; |
||
Line 165: | Line 389: | ||
name = "foo"; |
name = "foo"; |
||
example[name](5) # => 47</ |
example[name](5) # => 47</syntaxhighlight> |
||
=={{header|Julia}}== |
|||
{{works with|Julia|0.6}} |
|||
<syntaxhighlight lang="julia">const functions = Dict{String,Function}( |
|||
"foo" => x -> 42 + x, |
|||
"bar" => x -> 42 * x) |
|||
@show functions["foo"](3) |
|||
@show functions["bar"](3)</syntaxhighlight> |
|||
{{out}} |
|||
<pre>(functions["foo"])(3) = 45 |
|||
(functions["bar"])(3) = 126</pre> |
|||
=={{header|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. |
|||
<syntaxhighlight 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 |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
foo called |
|||
</pre> |
|||
=={{header|Lasso}}== |
=={{header|Lasso}}== |
||
< |
<syntaxhighlight lang="lasso">define mytype => type { |
||
public foo() => { |
public foo() => { |
||
return 'foo was called' |
return 'foo was called' |
||
Line 180: | Line 437: | ||
local(obj = mytype, methodname = tag('foo'), methodname2 = tag('bar')) |
local(obj = mytype, methodname = tag('foo'), methodname2 = tag('bar')) |
||
#obj->\#methodname->invoke |
#obj->\#methodname->invoke |
||
#obj->\#methodname2->invoke</ |
#obj->\#methodname2->invoke</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>foo was called |
<pre>foo was called |
||
this time is was bar</pre> |
this time is was bar</pre> |
||
=={{header| |
=={{header|Lingo}}== |
||
<syntaxhighlight lang="lingo">obj = script("MyClass").new() |
|||
-- ... |
|||
method = #foo |
|||
arg1 = 23 |
|||
res = call(method, obj, arg1)</syntaxhighlight> |
|||
=={{header|Logtalk}}== |
|||
For this task, we first define a simple object with a single method: |
For this task, we first define a simple object with a single method: |
||
< |
<syntaxhighlight lang="logtalk">:- object(foo). |
||
:- object(foo). |
|||
:- public(bar/1). |
:- public(bar/1). |
||
bar(42). |
bar(42). |
||
:- end_object.</syntaxhighlight>Second, we define another object that asks the user for a message to be sent to the first object:<syntaxhighlight lang="logtalk"> |
|||
:- 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). |
:- object(query_foo). |
||
Line 210: | Line 467: | ||
write(Message), nl. |
write(Message), nl. |
||
:- end_object.</syntaxhighlight>After compiling and loading both objects, we can try: |
|||
:- end_object. |
|||
| ?- query_foo::query. |
|||
</lang> |
|||
Message: bar(X). |
|||
Reply: bar(42) |
|||
After compiling and loading both objects, we can try: |
|||
<lang text> |
|||
| ?- query_foo::query. |
|||
Message: bar(X). |
|||
Reply: bar(42) |
|||
</lang> |
|||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
Don't forget to pass the object for methods! |
Don't forget to pass the object for methods! |
||
< |
<syntaxhighlight lang="lua">local example = { } |
||
function example:foo (x) return 42 + x end |
function example:foo (x) return 42 + x end |
||
local name = "foo" |
local name = "foo" |
||
example[name](example, 5) --> 47</ |
example[name](example, 5) --> 47</syntaxhighlight> |
||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
Creates a dialog box where one can type a function (Sin, Cos, Tan ...) and then a second dialog box for a value. |
|||
<syntaxhighlight lang="text">ToExpression[Input["function? E.g. Sin",]][Input["value? E.g. 0.4123"]]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Input: Sin |
|||
Input: 3.1415 |
|||
Output: 0.0000926536</pre> |
|||
=={{header|MATLAB}} / {{header|Octave}}== |
=={{header|MATLAB}} / {{header|Octave}}== |
||
<syntaxhighlight lang="matlab"> |
|||
<lang Matlab> |
|||
funName = 'foo'; % generate function name |
funName = 'foo'; % generate function name |
||
feval (funNAME, ...) % evaluation function with optional parameters |
feval (funNAME, ...) % evaluation function with optional parameters |
||
Line 238: | Line 497: | ||
funName = 'a=atan(pi)'; % generate function name |
funName = 'a=atan(pi)'; % generate function name |
||
eval (funName, 'printf(''Error\n'')') |
eval (funName, 'printf(''Error\n'')') |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
< |
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h> |
||
@interface Example : NSObject |
@interface Example : NSObject |
||
- (NSNumber *)foo; |
- (NSNumber *)foo; |
||
@end |
@end |
||
Line 249: | Line 508: | ||
@implementation Example |
@implementation Example |
||
- (NSNumber *)foo { |
- (NSNumber *)foo { |
||
return |
return @42; |
||
} |
} |
||
@end |
@end |
||
int main (int argc, const char *argv[]) { |
int main (int argc, const char *argv[]) { |
||
@autoreleasepool { |
|||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; |
|||
id example = [[Example alloc] init]; |
id example = [[Example alloc] init]; |
||
SEL selector = @selector(foo); // or = NSSelectorFromString(@"foo"); |
SEL selector = @selector(foo); // or = NSSelectorFromString(@"foo"); |
||
NSLog(@"%@", [example performSelector:selector]); |
NSLog(@"%@", [example performSelector:selector]); |
||
[example release]; |
|||
} |
|||
[pool release]; |
|||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
The <code>performSelector: ...</code> methods can only be used with methods with 0 - 2 object arguments, and an object or <code>void</code> return type. For all other calls, one can create an <code>NSInvocation</code> object and invoke it, or directly call one of the <code>objc_msgSend</code> family of runtime functions. |
The <code>performSelector: ...</code> methods can only be used with methods with 0 - 2 object arguments, and an object or <code>void</code> return type. For all other calls, one can create an <code>NSInvocation</code> object and invoke it, or directly call one of the <code>objc_msgSend</code> family of runtime functions. |
||
=={{header|Oforth}}== |
|||
A method object can be retrieved from its name using asMethod. |
|||
<syntaxhighlight lang="oforth">16 "sqrt" asMethod perform</syntaxhighlight> |
|||
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 : |
|||
<syntaxhighlight lang="oforth">16 "sqrt" Word find perform</syntaxhighlight> |
|||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
< |
<syntaxhighlight lang="parigp">foo()=5; |
||
eval(Str("foo","()"))</ |
eval(Str("foo","()"))</syntaxhighlight> |
||
=={{header|Pascal}}== |
|||
Works with FPC (tested with version 3.2.2). |
|||
In the simplest case, when the methods are procedures without parameters, it might look something like this (note that these methods are currently required to have PUBLISHED visibility): |
|||
<syntaxhighlight lang="pascal"> |
|||
program Test; |
|||
{$mode objfpc}{$h+} |
|||
uses |
|||
SysUtils; |
|||
type |
|||
TProc = procedure of object; |
|||
{$push}{$m+} |
|||
TMyObj = class |
|||
strict private |
|||
FName: string; |
|||
public |
|||
constructor Create(const aName: string); |
|||
property Name: string read FName; |
|||
published |
|||
procedure Foo; |
|||
procedure Bar; |
|||
end; |
|||
{$pop} |
|||
constructor TMyObj.Create(const aName: string); |
|||
begin |
|||
FName := aName; |
|||
end; |
|||
procedure TMyObj.Foo; |
|||
begin |
|||
WriteLn(Format('This is %s.Foo()', [Name])); |
|||
end; |
|||
procedure TMyObj.Bar; |
|||
begin |
|||
WriteLn(Format('This is %s.Bar()', [Name])); |
|||
end; |
|||
procedure CallByName(o: TMyObj; const aName: string); |
|||
var |
|||
m: TMethod; |
|||
begin |
|||
m.Code := o.MethodAddress(aName); |
|||
if m.Code <> nil then begin |
|||
m.Data := o; |
|||
TProc(m)(); |
|||
end else |
|||
WriteLn(Format('Unknown method(%s)', [aName])); |
|||
end; |
|||
var |
|||
o: TMyObj; |
|||
begin |
|||
o := TMyObj.Create('Obj'); |
|||
CallByName(o, 'Bar'); |
|||
CallByName(o, 'Foo'); |
|||
CallByName(o, 'Baz'); |
|||
o.Free; |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
This is Obj.Bar() |
|||
This is Obj.Foo() |
|||
Unknown method(Baz) |
|||
</pre> |
|||
=={{header|PascalABC.NET}}== |
|||
<syntaxhighlight lang="delphi"> |
|||
type MyClass = class |
|||
public |
|||
procedure Hello := Write('Hello'); |
|||
end; |
|||
begin |
|||
var obj := new MyClass; |
|||
var mi := typeof(MyClass).GetMethod('Hello'); |
|||
mi.Invoke(obj,new object[0]) |
|||
end. |
|||
</syntaxhighlight> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">package Example; |
||
sub new { |
sub new { |
||
bless {} |
bless {} |
||
Line 282: | Line 641: | ||
package main; |
package main; |
||
my $name = "foo"; |
my $name = "foo"; |
||
print Example->new->$name(5), "\n"; # prints "47"</ |
print Example->new->$name(5), "\n"; # prints "47"</syntaxhighlight> |
||
=={{header| |
=={{header|Phix}}== |
||
Not specifically anything to do with objects, but you can construct routine names at runtime: |
|||
Just for the fun of it, we'll mix in an anonymous role into an integer instead of defining a class. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang perl6>my $object = 42 but role { method add-me($x) { self + $x } } |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
my $name = 'add-me'; |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">Hello</span><span style="color: #0000FF;">()</span> |
|||
say $object."$name"(5); # 47</lang> |
|||
<span style="color: #0000FF;">?</span><span style="color: #008000;">"Hello"</span> |
|||
The double quotes are required, by the way; without them the variable would be interpreted as a hard ref to a method. |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">erm</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Hemmm"</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">3</span> <span style="color: #008080;">to</span> <span style="color: #000000;">5</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">erm</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]+=-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">call_proc</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">routine_id</span><span style="color: #0000FF;">(</span><span style="color: #000000;">erm</span><span style="color: #0000FF;">),{})</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
< |
<syntaxhighlight lang="php"><?php |
||
class Example { |
class Example { |
||
function foo($x) { |
function foo($x) { |
||
Line 306: | Line 674: | ||
// alternately: |
// alternately: |
||
echo call_user_func(array($example, $name), 5), "\n"; |
echo call_user_func(array($example, $name), 5), "\n"; |
||
?></ |
?></syntaxhighlight> |
||
=={{header|Picat}}== |
|||
For functions use <code>apply/n</code> and for predicates <code>call/n</code>. The name of the function/predicate must be an atom and strings must be converted to atom, e.g. with <code>to_atom/1</code>. |
|||
<syntaxhighlight lang="picat">go => |
|||
println("Function: Use apply/n"), |
|||
Fun = "fib", |
|||
A = 10, |
|||
% Convert F to an atom |
|||
println(apply(to_atom(Fun),A)), |
|||
nl, |
|||
println("Predicate: use call/n"), |
|||
Pred = "pyth", |
|||
call(Pred.to_atom,3,4,Z), |
|||
println(z=Z), |
|||
% Pred2 is an atom so it can be used directly with call/n. |
|||
Pred2 = pyth, |
|||
call(Pred.to_atom,13,14,Z2), |
|||
println(z2=Z2), |
|||
nl. |
|||
% A function |
|||
fib(1) = 1. |
|||
fib(2) = 1. |
|||
fib(N) = fib(N-1) + fib(N-2). |
|||
% A predicate |
|||
pyth(X,Y,Z) => |
|||
Z = X**2 + Y**2.</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Function: Use apply/n |
|||
55 |
|||
Predicate: use call/n |
|||
z = 25 |
|||
z2 = 365</pre> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
This can be done with the '[http://software-lab.de/doc/refS.html#send send]' function. |
This can be done with the '[http://software-lab.de/doc/refS.html#send send]' function. |
||
< |
<syntaxhighlight lang="picolisp">(send (expression) Obj arg1 arg2)</syntaxhighlight> |
||
=={{header|Pike}}== |
=={{header|Pike}}== |
||
with [] instead of -> a string can be used to name a method: |
with [] instead of -> a string can be used to name a method: |
||
< |
<syntaxhighlight lang="pike">string unknown = "format_nice"; |
||
object now = Calendar.now(); |
object now = Calendar.now(); |
||
now[unknown]();</ |
now[unknown]();</syntaxhighlight> |
||
=={{header|PowerShell}}== |
|||
A random method using a random number: |
|||
<syntaxhighlight 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 |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Method : Atan |
|||
Number : 0.5 |
|||
Result : 0.463647609000806 |
|||
</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
String literal "foo" may be replaced by any expression resulting in a string |
String literal "foo" may be replaced by any expression resulting in a string |
||
< |
<syntaxhighlight lang="python">class Example(object): |
||
def foo(self, x): |
def foo(self, x): |
||
return 42 + x |
return 42 + x |
||
name = "foo" |
name = "foo" |
||
getattr(Example(), name)(5) # => 47</ |
getattr(Example(), name)(5) # => 47</syntaxhighlight> |
||
=={{header|Qi}}== |
=={{header|Qi}}== |
||
<syntaxhighlight lang="qi"> |
|||
<lang qi> |
|||
(define foo -> 5) |
(define foo -> 5) |
||
Line 335: | Line 763: | ||
(execute-function "foo") |
(execute-function "foo") |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(define greeter |
(define greeter |
||
Line 351: | Line 779: | ||
(define unknown 'hello) |
(define unknown 'hello) |
||
(dynamic-send greeter unknown "World") |
(dynamic-send greeter unknown "World") |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
Just for the fun of it, we'll mix in an anonymous role into an integer instead of defining a class. |
|||
<syntaxhighlight lang="raku" line>my $object = 42 but role { method add-me($x) { self + $x } } |
|||
my $name = 'add-me'; |
|||
say $object."$name"(5); # 47</syntaxhighlight> |
|||
The double quotes are required, by the way; without them the variable would be interpreted as a hard ref to a method. |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
You may replace :foo, :bar or "bar" with any expression that returns a Symbol or String. |
You may replace :foo, :bar or "bar" with any expression that returns a Symbol or String. |
||
< |
<syntaxhighlight lang="ruby">class Example |
||
def foo |
def foo |
||
42 |
42 |
||
Line 369: | Line 805: | ||
Example.new.send( :bar, 1, 2 ) { |x,y| x+y } # => 3 |
Example.new.send( :bar, 1, 2 ) { |x,y| x+y } # => 3 |
||
args = [1, 2] |
args = [1, 2] |
||
Example.new.send( "bar", *args ) { |x,y| x+y } # => 3</ |
Example.new.send( "bar", *args ) { |x,y| x+y } # => 3</syntaxhighlight> |
||
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. |
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. |
||
{{works with|Ruby|1.9}} |
{{works with|Ruby|1.9}} |
||
< |
<syntaxhighlight lang="ruby">class Example |
||
private |
private |
||
def privacy; "secret"; end |
def privacy; "secret"; end |
||
Line 384: | Line 820: | ||
e.public_send :publicity # => "hi" |
e.public_send :publicity # => "hi" |
||
e.public_send :privacy # raises NoMethodError |
e.public_send :privacy # raises NoMethodError |
||
e.send :privacy # => "secret"</ |
e.send :privacy # => "secret"</syntaxhighlight> |
||
=={{header|Scala}}== |
|||
{{libheader|Scala}}<syntaxhighlight 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]") |
|||
}</syntaxhighlight> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight 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) # =//=</syntaxhighlight> |
|||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
< |
<syntaxhighlight lang="smalltalk">Object subclass: #Example. |
||
Example extend [ |
Example extend [ |
||
Line 395: | Line 858: | ||
symbol := 'foo:' asSymbol. " same as symbol := #foo: " |
symbol := 'foo:' asSymbol. " same as symbol := #foo: " |
||
Example new perform: symbol with: 5. " returns 47 "</ |
Example new perform: symbol with: 5. " returns 47 "</syntaxhighlight> |
||
The <code>perform:with:with:</code> family of methods exist for methods with 0 - 2 (3 in [[GNU Smalltalk]]) arguments. For methods with more arguments, use <code>perform:withArguments:</code>, which takes an array of arguments. |
The <code>perform:with:with:</code> family of methods exist for methods with 0 - 2 (3 in [[GNU Smalltalk]]) arguments. For methods with more arguments, use <code>perform:withArguments:</code>, which takes an array of arguments. |
||
=={{header|Swift}}== |
|||
Generally speaking, pure Swift is a very statically typed language, and calling unknown methods is impossible. However, Swift provides a few ways in which instances of specially marked objects can receive unknown method calls. |
|||
===Objective-C Compatibility Using @objc=== |
|||
The first case is used for interfacing with legacy Objective-C libraries. Objective-C is heavily dynamic with Smalltalk-style message passing. So Swift must be able to participate in this. |
|||
<syntaxhighlight lang="swift">import Foundation |
|||
class MyUglyClass: NSObject { |
|||
@objc |
|||
func myUglyFunction() { |
|||
print("called myUglyFunction") |
|||
} |
|||
} |
|||
let someObject: NSObject = MyUglyClass() |
|||
someObject.perform(NSSelectorFromString("myUglyFunction"))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>called myUglyFunction</pre> |
|||
===Dynamic Language Interop with @dynamicCallable and @dynamicMemberLookup=== |
|||
One of Swift's goals is to able to effectively bridge to dynamic languages such as Python and JavaScript. In order to facilitate more natural APIs, Swift provides the <code>@dynamicCallable</code> and <code>@dynamicMemberLookup</code> attributes which allow for runtime handling of method calls. |
|||
<syntaxhighlight lang="swift">@dynamicCallable |
|||
protocol FunDynamics { |
|||
var parent: MyDynamicThing { get } |
|||
func dynamicallyCall(withArguments args: [Int]) -> MyDynamicThing |
|||
func dynamicallyCall(withKeywordArguments args: [String: Int]) -> MyDynamicThing |
|||
} |
|||
extension FunDynamics { |
|||
func dynamicallyCall(withKeywordArguments args: [String: Int]) -> MyDynamicThing { |
|||
if let add = args["adding"] { |
|||
parent.n += add |
|||
} |
|||
if let sub = args["subtracting"] { |
|||
parent.n -= sub |
|||
} |
|||
return parent |
|||
} |
|||
} |
|||
@dynamicMemberLookup |
|||
class MyDynamicThing { |
|||
var n: Int |
|||
init(n: Int) { |
|||
self.n = n |
|||
} |
|||
subscript(dynamicMember member: String) -> FunDynamics { |
|||
switch member { |
|||
case "subtract": |
|||
return Subtracter(parent: self) |
|||
case "add": |
|||
return Adder(parent: self) |
|||
case _: |
|||
return Nuller(parent: self) |
|||
} |
|||
} |
|||
} |
|||
struct Nuller: FunDynamics { |
|||
var parent: MyDynamicThing |
|||
func dynamicallyCall(withArguments args: [Int]) -> MyDynamicThing { parent } |
|||
} |
|||
struct Subtracter: FunDynamics { |
|||
var parent: MyDynamicThing |
|||
func dynamicallyCall(withArguments args: [Int]) -> MyDynamicThing { |
|||
switch args.count { |
|||
case 1: |
|||
parent.n -= args[0] |
|||
case _: |
|||
print("Unknown call") |
|||
} |
|||
return parent |
|||
} |
|||
} |
|||
struct Adder: FunDynamics { |
|||
var parent: MyDynamicThing |
|||
func dynamicallyCall(withArguments arg: [Int]) -> MyDynamicThing { |
|||
switch arg.count { |
|||
case 1: |
|||
parent.n += arg[0] |
|||
case _: |
|||
print("Unknown call") |
|||
} |
|||
return parent |
|||
} |
|||
} |
|||
let thing = |
|||
MyDynamicThing(n: 0) |
|||
.add(20) |
|||
.divide(2) // Unhandled call, do nothing |
|||
.subtract(adding: 10, subtracting: 14) |
|||
print(thing.n)</syntaxhighlight> |
|||
{{out}} |
|||
<pre>16</pre> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Method names are really just strings, i.e., ordinary values that can be produced by any mechanism: |
Method names are really just strings, i.e., ordinary values that can be produced by any mechanism: |
||
< |
<syntaxhighlight lang="tcl">package require Tcl 8.6 |
||
oo::class create Example { |
oo::class create Example { |
||
method foo {} {return 42} |
method foo {} {return 42} |
||
Line 414: | Line 996: | ||
for {set i 1} {$i <= 4} {incr i} { |
for {set i 1} {$i <= 4} {incr i} { |
||
$eg $i ... |
$eg $i ... |
||
}</ |
}</syntaxhighlight> |
||
The above produces this output |
{{out|The above produces this output}} |
||
42 |
|||
fee... |
|||
fie... |
|||
foe... |
|||
fum... |
|||
=={{header|Wren}}== |
|||
<syntaxhighlight lang="wren">import "meta" for Meta |
|||
class Test { |
|||
construct new() {} |
|||
foo() { System.print("Foo called.") } |
|||
bar() { System.print("Bar called.") } |
|||
} |
|||
var test = Test.new() |
|||
for (method in ["foo", "bar"]) { |
|||
Meta.eval("test.%(method)()") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
<pre> |
||
Foo called. |
|||
42 |
|||
Bar called. |
|||
fee... |
|||
fie... |
|||
foe... |
|||
fum... |
|||
</pre> |
</pre> |
||
=={{header|zkl}}== |
|||
<syntaxhighlight lang="zkl">name:="len"; "this is a test".resolve(name)() //-->14</syntaxhighlight> |
|||
{{omit from|Ada}} |
|||
{{omit from|Axe}} |
|||
{{omit from|BASIC}} |
{{omit from|BASIC}} |
||
{{omit from|C|No such thing as object method}} |
{{omit from|C|No such thing as object method}} |
||
{{omit from|C++}} |
|||
{{omit from|GUISS}} |
{{omit from|GUISS}} |
||
{{omit from|Nim}} |
|||
{{omit from|Rust|No runtime reflection}} |
|||
{{omit from|ZX Spectrum Basic}} |
{{omit from|ZX Spectrum Basic}} |
Latest revision as of 10:53, 4 July 2024
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.
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
}
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
);
- 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#
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);
}
}
- Output:
foo(5) = 47
Caché ObjectScript
$METHOD executes a named instance method for a specified instance of a designated class.
Class Unknown.Example Extends %RegisteredObject
{
Method Foo()
{
Write "This is foo", !
}
Method Bar()
{
Write "This is bar", !
}
}
- Examples:
USER>Set obj=##class(Unknown.Example).%New() USER>Do $Method(obj, "Foo") This is foo USER>Do $Method(obj, "Bar") This is bar
Clojure
(import '[java.util Date])
(import '[clojure.lang Reflector])
(def date1 (Date.))
(def date2 (Date.))
(def method "equals")
;; Two ways of invoking method "equals" on object date1
;; using date2 as argument
;; Way 1 - Using Reflector class
;; NOTE: The argument date2 is passed inside an array
(Reflector/invokeMethod date1 method (object-array [date2]))
;; Way 2 - Using eval
;; Eval runs any piece of valid Clojure code
;; So first we construct a piece of code to do what we want (where method name is inserted dynamically),
;; then we run the code using eval
(eval `(. date1 ~(symbol method) date2))
Common Lisp
Unknown methods are called just like any other function. Find the method-naming symbol using INTERN then call it with FUNCALL.
(funcall (intern "SOME-METHOD") my-object a few arguments)
Déjà Vu
local :object { :add @+ }
local :method :add
!. object! method 1 2
- Output:
3
E
This example goes well with the object named example
in Respond to an unknown method call#E.
for name in ["foo", "bar"] {
E.call(example, name, [])
}
Ecstasy
Here's a simple example of a test module using its runtime type to search for methods by some name (specified on the the command line), grabbing the one by that name that requires no parameters, and dynamically invoking it:
module test {
@Inject Console console;
void run(String[] args) {
String name = args.empty ? "foo" : args[0];
if (val mm := &this.actualType.multimethods.get(name),
val m := mm.methods.any(m -> m.ParamTypes.size == 0)) {
m.invoke(this, Tuple:());
} else {
console.print($"No such 0-parameter method: {name.quoted()}");
}
}
void foo() {
console.print("this is the foo() method");
}
void bar() {
console.print("this is the bar() method");
}
}
- Output:
x$ xec test foo this is the foo() method x$ xec test bar this is the bar() method x$ xec test baz No such 0-parameter method: "baz"
Elena
ELENA 4.1 :
import extensions;
class Example
{
foo(x)
= x + 42;
}
public program()
{
var example := new Example();
var methodSignature := "foo";
var invoker := new MessageName(methodSignature);
var result := invoker(example,5);
console.printLine(methodSignature,"(",5,") = ",result)
}
- Output:
foo(5) = 47
Factor
Factor's object model is such that objects themselves don't contain methods — generic words do. So there is nothing different about invoking an unknown method than invoking an unknown word in general.
USING: accessors kernel math prettyprint sequences words ;
IN: rosetta-code.unknown-method-call
TUPLE: foo num ;
C: <foo> foo
GENERIC: add5 ( x -- y )
M: foo add5 num>> 5 + ;
42 <foo> ! construct a foo
"add" "5" append ! construct a word name
! must specify vocab to look up a word
"rosetta-code.unknown-method-call"
lookup-word execute . ! 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
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
FreeBASIC
Type Example
foo As Integer Ptr
Declare Constructor (x As Integer)
End Type
Constructor Example(x As Integer)
This.foo = New Integer
*This.foo = 42 + x
End Constructor
Dim As Example result = 5
Print *result.foo
Sleep
- Output:
47
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
}
Groovy
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)
Icon and 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
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.
Example := Object clone
Example foo := method(x, 42+x)
name := "foo"
Example clone perform(name,5) println // prints "47"
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:
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
Java
Using reflection
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"
}
}
JavaScript
String literal "foo" may be replaced by any expression resulting in a string
example = new Object;
example.foo = function(x) {
return 42 + x;
};
name = "foo";
example[name](5) # => 47
Julia
const functions = Dict{String,Function}(
"foo" => x -> 42 + x,
"bar" => x -> 42 * x)
@show functions["foo"](3)
@show functions["bar"](3)
- Output:
(functions["foo"])(3) = 45 (functions["bar"])(3) = 126
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.
// 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
}
- Output:
foo called
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
- Output:
foo was called this time is was bar
Lingo
obj = script("MyClass").new()
-- ...
method = #foo
arg1 = 23
res = call(method, obj, arg1)
Logtalk
For this task, we first define a simple object with a single method:
:- object(foo).
:- public(bar/1).
bar(42).
:- end_object.
Second, we define another object that asks the user for a message to be sent to the first object:
:- object(query_foo).
:- public(query/0).
query :-
write('Message: '),
read(Message),
foo::Message.
write('Reply: '),
write(Message), nl.
:- end_object.
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!
local example = { }
function example:foo (x) return 42 + x end
local name = "foo"
example[name](example, 5) --> 47
Mathematica /Wolfram Language
Creates a dialog box where one can type a function (Sin, Cos, Tan ...) and then a second dialog box for a value.
ToExpression[Input["function? E.g. Sin",]][Input["value? E.g. 0.4123"]]
- Output:
Input: Sin Input: 3.1415 Output: 0.0000926536
MATLAB / Octave
funName = 'foo'; % generate function name
feval (funNAME, ...) % evaluation function with optional parameters
funName = 'a=atan(pi)'; % generate function name
eval (funName, 'printf(''Error\n'')')
Objective-C
#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;
}
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.
16 "sqrt" asMethod perform
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 :
16 "sqrt" Word find perform
PARI/GP
foo()=5;
eval(Str("foo","()"))
Pascal
Works with FPC (tested with version 3.2.2).
In the simplest case, when the methods are procedures without parameters, it might look something like this (note that these methods are currently required to have PUBLISHED visibility):
program Test;
{$mode objfpc}{$h+}
uses
SysUtils;
type
TProc = procedure of object;
{$push}{$m+}
TMyObj = class
strict private
FName: string;
public
constructor Create(const aName: string);
property Name: string read FName;
published
procedure Foo;
procedure Bar;
end;
{$pop}
constructor TMyObj.Create(const aName: string);
begin
FName := aName;
end;
procedure TMyObj.Foo;
begin
WriteLn(Format('This is %s.Foo()', [Name]));
end;
procedure TMyObj.Bar;
begin
WriteLn(Format('This is %s.Bar()', [Name]));
end;
procedure CallByName(o: TMyObj; const aName: string);
var
m: TMethod;
begin
m.Code := o.MethodAddress(aName);
if m.Code <> nil then begin
m.Data := o;
TProc(m)();
end else
WriteLn(Format('Unknown method(%s)', [aName]));
end;
var
o: TMyObj;
begin
o := TMyObj.Create('Obj');
CallByName(o, 'Bar');
CallByName(o, 'Foo');
CallByName(o, 'Baz');
o.Free;
end.
- Output:
This is Obj.Bar() This is Obj.Foo() Unknown method(Baz)
PascalABC.NET
type MyClass = class
public
procedure Hello := Write('Hello');
end;
begin
var obj := new MyClass;
var mi := typeof(MyClass).GetMethod('Hello');
mi.Invoke(obj,new object[0])
end.
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"
Phix
Not specifically anything to do with objects, but you can construct routine names at runtime:
with javascript_semantics 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),{})
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";
?>
Picat
For functions use apply/n
and for predicates call/n
. The name of the function/predicate must be an atom and strings must be converted to atom, e.g. with to_atom/1
.
go =>
println("Function: Use apply/n"),
Fun = "fib",
A = 10,
% Convert F to an atom
println(apply(to_atom(Fun),A)),
nl,
println("Predicate: use call/n"),
Pred = "pyth",
call(Pred.to_atom,3,4,Z),
println(z=Z),
% Pred2 is an atom so it can be used directly with call/n.
Pred2 = pyth,
call(Pred.to_atom,13,14,Z2),
println(z2=Z2),
nl.
% A function
fib(1) = 1.
fib(2) = 1.
fib(N) = fib(N-1) + fib(N-2).
% A predicate
pyth(X,Y,Z) =>
Z = X**2 + Y**2.
- Output:
Function: Use apply/n 55 Predicate: use call/n z = 25 z2 = 365
PicoLisp
This can be done with the 'send' function.
(send (expression) Obj arg1 arg2)
Pike
with [] instead of -> a string can be used to name a method:
string unknown = "format_nice";
object now = Calendar.now();
now[unknown]();
PowerShell
A random method using a random number:
$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
- Output:
Method : Atan Number : 0.5 Result : 0.463647609000806
Python
String literal "foo" may be replaced by any expression resulting in a string
class Example(object):
def foo(self, x):
return 42 + x
name = "foo"
getattr(Example(), name)(5) # => 47
Qi
(define foo -> 5)
(define execute-function
Name -> (eval [(INTERN Name)]))
(execute-function "foo")
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")
Raku
(formerly Perl 6) Just for the fun of it, we'll mix in an anonymous role into an integer instead of defining a class.
my $object = 42 but role { method add-me($x) { self + $x } }
my $name = 'add-me';
say $object."$name"(5); # 47
The double quotes are required, by the way; without them the variable would be interpreted as a hard ref to a method.
Ruby
You may replace :foo, :bar or "bar" with any expression that returns a Symbol or String.
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
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.
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"
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]")
}
Sidef
class Example {
method foo(x) {
42 + x
}
}
var name = 'foo'
var obj = Example()
say obj.(name)(5) # prints: 47
say obj.method(name)(5) # =//=
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 "
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.
Swift
Generally speaking, pure Swift is a very statically typed language, and calling unknown methods is impossible. However, Swift provides a few ways in which instances of specially marked objects can receive unknown method calls.
Objective-C Compatibility Using @objc
The first case is used for interfacing with legacy Objective-C libraries. Objective-C is heavily dynamic with Smalltalk-style message passing. So Swift must be able to participate in this.
import Foundation
class MyUglyClass: NSObject {
@objc
func myUglyFunction() {
print("called myUglyFunction")
}
}
let someObject: NSObject = MyUglyClass()
someObject.perform(NSSelectorFromString("myUglyFunction"))
- Output:
called myUglyFunction
Dynamic Language Interop with @dynamicCallable and @dynamicMemberLookup
One of Swift's goals is to able to effectively bridge to dynamic languages such as Python and JavaScript. In order to facilitate more natural APIs, Swift provides the @dynamicCallable
and @dynamicMemberLookup
attributes which allow for runtime handling of method calls.
@dynamicCallable
protocol FunDynamics {
var parent: MyDynamicThing { get }
func dynamicallyCall(withArguments args: [Int]) -> MyDynamicThing
func dynamicallyCall(withKeywordArguments args: [String: Int]) -> MyDynamicThing
}
extension FunDynamics {
func dynamicallyCall(withKeywordArguments args: [String: Int]) -> MyDynamicThing {
if let add = args["adding"] {
parent.n += add
}
if let sub = args["subtracting"] {
parent.n -= sub
}
return parent
}
}
@dynamicMemberLookup
class MyDynamicThing {
var n: Int
init(n: Int) {
self.n = n
}
subscript(dynamicMember member: String) -> FunDynamics {
switch member {
case "subtract":
return Subtracter(parent: self)
case "add":
return Adder(parent: self)
case _:
return Nuller(parent: self)
}
}
}
struct Nuller: FunDynamics {
var parent: MyDynamicThing
func dynamicallyCall(withArguments args: [Int]) -> MyDynamicThing { parent }
}
struct Subtracter: FunDynamics {
var parent: MyDynamicThing
func dynamicallyCall(withArguments args: [Int]) -> MyDynamicThing {
switch args.count {
case 1:
parent.n -= args[0]
case _:
print("Unknown call")
}
return parent
}
}
struct Adder: FunDynamics {
var parent: MyDynamicThing
func dynamicallyCall(withArguments arg: [Int]) -> MyDynamicThing {
switch arg.count {
case 1:
parent.n += arg[0]
case _:
print("Unknown call")
}
return parent
}
}
let thing =
MyDynamicThing(n: 0)
.add(20)
.divide(2) // Unhandled call, do nothing
.subtract(adding: 10, subtracting: 14)
print(thing.n)
- Output:
16
Tcl
Method names are really just strings, i.e., ordinary values that can be produced by any mechanism:
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 ...
}
- The above produces this output:
42 fee... fie... foe... fum...
Wren
import "meta" for Meta
class Test {
construct new() {}
foo() { System.print("Foo called.") }
bar() { System.print("Bar called.") }
}
var test = Test.new()
for (method in ["foo", "bar"]) {
Meta.eval("test.%(method)()")
}
- Output:
Foo called. Bar called.
zkl
name:="len"; "this is a test".resolve(name)() //-->14
- Programming Tasks
- Object oriented
- AutoHotkey
- Bracmat
- C sharp
- Caché ObjectScript
- Clojure
- Common Lisp
- Déjà Vu
- E
- Ecstasy
- Elena
- Factor
- Forth
- FreeBASIC
- Go
- Groovy
- Unicon
- Io
- J
- Java
- JavaScript
- Julia
- Kotlin
- Lasso
- Lingo
- Logtalk
- Lua
- Mathematica
- Wolfram Language
- MATLAB
- Octave
- Objective-C
- Oforth
- PARI/GP
- Pascal
- PascalABC.NET
- Perl
- Phix
- PHP
- Picat
- PicoLisp
- Pike
- PowerShell
- Python
- Qi
- Racket
- Raku
- Ruby
- Scala
- Sidef
- Smalltalk
- Swift
- Tcl
- Wren
- Zkl
- Ada/Omit
- Axe/Omit
- BASIC/Omit
- C/Omit
- C++/Omit
- GUISS/Omit
- Nim/Omit
- Rust/Omit
- ZX Spectrum Basic/Omit