Reflection/List methods: Difference between revisions
(→{{header|Ruby}}: bugfix) |
(Added Sidef) |
||
Line 539: | Line 539: | ||
p sub.singleton_methods |
p sub.singleton_methods |
||
#=> [:superOwn, :subOwn]</lang> |
#=> [:superOwn, :subOwn]</lang> |
||
=={{header|Sidef}}== |
|||
The super-method ''Object.methods()'' returns an Hash with method names as keys and ''LazyMethod'' objects as values. Each ''LazyMethod'' can be called with zero or more arguments, internally invoking the method on the object on which ''.methods'' was called. |
|||
<lang ruby>class Example { |
|||
method foo { } |
|||
method bar(arg) { say "bar(#{arg})" } |
|||
} |
|||
var obj = Example() |
|||
say obj.methods.keys.sort #=> ["bar", "call", "foo", "new"] |
|||
var meth = obj.methods.item(:bar) # `LazyMethod` representation for `obj.bar()` |
|||
meth(123) # calls obj.bar()</lang> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
Revision as of 16:30, 5 September 2016
- Task
The goal is to get the methods of an object, as names, values or both.
Some languages offer dynamic methods, which in general can only be inspected if a class' public API includes a way of listing them.
C#
<lang csharp>using System; using System.Reflection;
public class Rosetta {
public static void Main() { //Let's get all methods, not just public ones. BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
foreach (var method in typeof(TestForMethodReflection).GetMethods(flags)) Console.WriteLine(method.Name); } class TestForMethodReflection { public void MyPublicMethod() {} private void MyPrivateMethod() {} public static void MyPublicStaticMethod() {} private static void MyPrivateStaticMethod() {} }
}</lang>
- Output:
MyPublicMethod MyPrivateMethod MyPublicStaticMethod MyPrivateStaticMethod //If we do not use BindingFlags.DeclaredOnly, we also get: ToString Equals GetHashCode GetType Finalize MemberwiseClone
Go
<lang go>package main
import (
"fmt" "reflect"
)
type t int // a type definition
// some methods on the type func (r t) twice() t { return r * 2 } func (r t) half() t { return r / 2 } func (r t) more() bool { return r > 2 }
func main() {
o := t(10) // create an "object" of type t v := reflect.ValueOf(o) t := v.Type() n := t.NumMethod() fmt.Println(n, "methods:") fmt.Println("Name Method expression Method value") for i := 0; i < n; i++ { fmt.Printf("%-5s %-19s %s\n", t.Method(i).Name, t.Method(i).Func.Type(), v.Method(i).Type()) }
}</lang>
- Output:
Name Method expression Method value half func(main.t) main.t func() main.t more func(main.t) bool func() bool twice func(main.t) main.t func() main.t
Java
<lang java>import java.lang.reflect.Method;
public class ListMethods {
public int examplePublicInstanceMethod(char c, double d) { return 42; }
private boolean examplePrivateInstanceMethod(String s) { return true; } public static void main(String[] args) { Class clazz = ListMethods.class;
System.out.println("All public methods (including inherited):"); for (Method m : clazz.getMethods()) { System.out.println(m); } System.out.println(); System.out.println("All declared methods (excluding inherited):"); for (Method m : clazz.getDeclaredMethods()) { System.out.println(m); } }
}</lang>
- Output:
public static void ListMethods.main(java.lang.String[]) public int ListMethods.examplePublicInstanceMethod(char,double) public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() All declared methods (excluding inherited): public static void ListMethods.main(java.lang.String[]) public int ListMethods.examplePublicInstanceMethod(char,double) private boolean ListMethods.examplePrivateInstanceMethod(java.lang.String)
JavaScript
In JavaScript, methods are properties that are functions, so methods are retrieved by getting properties and filtering. There are multiple ways of getting property names, each of which include different subsets of an object's properties, such as enumerable or inherited properties.
<lang javascript>// Sample classes for reflection function Super(name) {
this.name = name; this.superOwn = function() { return 'super owned'; };
} Super.prototype = {
constructor: Super className: 'super', toString: function() { return "Super(" + this.name + ")"; }, doSup: function() { return 'did super stuff'; }
}
function Sub() {
Object.getPrototypeOf(this).constructor.apply(this, arguments); this.rest = [].slice.call(arguments, 1); this.subOwn = function() { return 'sub owned'; };
} Sub.prototype = Object.assign(
new Super('prototype'), { constructor: Sub className: 'sub', toString: function() { return "Sub(" + this.name + ")"; }, doSub: function() { return 'did sub stuff'; } });
Object.defineProperty(Sub.prototype, 'shush', {
value: function() { return ' non-enumerable'; }, enumerable: false // the default
});
var sup = new Super('sup'),
sub = new Sub('sub', 0, 'I', 'two');
Object.defineProperty(sub, 'quiet', {
value: function() { return 'sub owned non-enumerable'; }, enumerable: false
});
// get enumerable methods on an object and its ancestors function get_method_names(obj) {
var methods = []; for (var p in obj) { if (typeof obj[p] == 'function') { methods.push(p); } } return methods;
}
get_method_names(sub); //["subOwn", "superOwn", "toString", "doSub", "doSup"]
// get enumerable properties on an object and its ancestors function get_property_names(obj) {
var properties = []; for (var p in obj) { properties.push(p); } return properties;
}
// alternate way to get enumerable method names on an object and its ancestors function get_method_names(obj) {
return get_property_names(obj) .filter(function(p) {return typeof obj[p] == 'function';});
}
get_method_names(sub); //["subOwn", "superOwn", "toString", "doSub", "doSup"]
// get enumerable & non-enumerable method names set directly on an object Object.getOwnPropertyNames(sub)
.filter(function(p) {return typeof sub[p] == 'function';})
//["subOwn", "shhh"]
// get enumerable method names set directly on an object Object.keys(sub)
.filter(function(p) {return typeof sub[p] == 'function';})
//["subOwn"]
// get enumerable method names & values set directly on an object Object.entries(sub)
.filter(function(p) {return typeof p[1] == 'function';})
//[["subOwn", function () {...}]]</lang>
Objective-C
<lang objc>#import <Foundation/Foundation.h>
- import <objc/runtime.h>
@interface Foo : NSObject @end @implementation Foo - (int)bar:(double)x {
return 42;
} @end
int main() {
unsigned int methodCount; Method *methods = class_copyMethodList([Foo class], &methodCount); for (unsigned int i = 0; i < methodCount; i++) { Method m = methods[i]; SEL selector = method_getName(m); const char *typeEncoding = method_getTypeEncoding(m); NSLog(@"%@\t%s", NSStringFromSelector(selector), typeEncoding); } free(methods); return 0;
}</lang>
- Output:
bar: i24@0:8d16
Perl 6
You can get a list of an object's methods using .^methods, which is part of the Meta Object Protocol.
Each is represented as a Method object that contains a bunch of info:
<lang perl6>class Foo {
method foo ($x) { } method bar ($x, $y) { } method baz ($x, $y?) { }
}
my $object = Foo.new;
for $object.^methods {
say join ", ", .name, .arity, .count, .signature.gist
}</lang>
- Output:
foo, 2, 2, (Foo $: $x, *%_) bar, 3, 3, (Foo $: $x, $y, *%_) baz, 2, 3, (Foo $: $x, $y?, *%_)
PHP
<lang php><? class Foo {
function bar(int $x) { }
}
$method_names = get_class_methods('Foo'); foreach ($method_names as $name) {
echo "$name\n"; $method_info = new ReflectionMethod('Foo', $name); echo $method_info;
} ?></lang>
- Output:
bar Method [ <user> public method bar ] { @@ /Users/xuanluo/test.php 3 - 4 - Parameters [1] { Parameter #0 [ <required> int $x ] } }
Python
In Python, methods are properties that are functions, so methods are retrieved by getting properties and filtering, using (e.g.) dir()
and a list comprehension. Python's inspect
module offers a simple way to get a list of an object's methods, though it won't include wrapped, C-native methods (type 'method-wrapper', type 'wrapper_descriptor', or class 'wrapper_descriptor', depending on version). Dynamic methods can be listed by overriding __dir__
in the class.
<lang python>import inspect
- Sample classes for inspection
class Super(object):
def __init__(self, name): self.name = name def __str__(self): return "Super(%s)" % (self.name,) def doSup(self): return 'did super stuff' @classmethod def cls(cls): return 'cls method (in sup)' @classmethod def supCls(cls): return 'Super method' @staticmethod def supStatic(): return 'static method'
class Other(object):
def otherMethod(self): return 'other method'
class Sub(Other, Super):
def __init__(self, name, *args): super(Sub, self).__init__(name); self.rest = args; self.methods = {} def __dir__(self): return list(set( \ sum([dir(base) for base in type(self).__bases__], []) \ + type(self).__dict__.keys() \ + self.__dict__.keys() \ + self.methods.keys() \ )) def __getattr__(self, name): if name in self.methods: if callable(self.methods[name]) and self.methods[name].__code__.co_argcount > 0: if self.methods[name].__code__.co_varnames[0] == 'self': return self.methods[name].__get__(self, type(self)) if self.methods[name].__code__.co_varnames[0] == 'cls': return self.methods[name].__get__(type(self), type) return self.methods[name] raise AttributeError("'%s' object has no attribute '%s'" % (type(self).__name__, name)) def __str__(self): return "Sub(%s)" % self.name def doSub(): return 'did sub stuff' @classmethod def cls(cls): return 'cls method (in Sub)' @classmethod def subCls(cls): return 'Sub method' @staticmethod def subStatic(): return 'Sub method'
sup = Super('sup') sub = Sub('sub', 0, 'I', 'two') sub.methods['incr'] = lambda x: x+1 sub.methods['strs'] = lambda self, x: str(self) * x
- names
[method for method in dir(sub) if callable(getattr(sub, method))]
- instance methods
[method for method in dir(sub) if callable(getattr(sub, method)) and hasattr(getattr(sub, method), '__self__') and getattr(sub, method).__self__ == sub]
- ['__dir__', '__getattr__', '__init__', '__str__', 'doSub', 'doSup', 'otherMethod', 'strs']
- class methods
[method for method in dir(sub) if callable(getattr(sub, method)) and hasattr(getattr(sub, method), '__self__') and getattr(sub, method).__self__ == type(sub)]
- ['__subclasshook__', 'cls', 'subCls', 'supCls']
- static & free dynamic methods
[method for method in dir(sub) if callable(getattr(sub, method)) and type(getattr(sub, method)) == type(lambda:nil)]
- ['incr', 'subStatic', 'supStatic']
- names & values; doesn't include wrapped, C-native methods
inspect.getmembers(sub, predicate=inspect.ismethod)
- names using inspect
map(lambda t: t[0], inspect.getmembers(sub, predicate=inspect.ismethod))
- ['__dir__', '__getattr__', '__init__', '__str__', 'cls', 'doSub', 'doSup', 'otherMethod', 'strs', 'subCls', 'supCls']</lang>
Ruby
Ruby has various properties that will return lists of methods:
- Object#methods
- Object#public_methods
- Object#private_methods
- Object#protected_methods
- Object#singleton_methods
Dynamic methods can be listed by overriding these methods. Ancestor methods can be filtered out by subtracting a list of methods from the ancestor.
<lang ruby># Sample classes for reflection class Super
CLASSNAME = 'super' def initialize(name) @name = name def self.superOwn 'super owned' end end def to_s "Super(#{@name})" end def doSup 'did super stuff' end def self.superClassStuff 'did super class stuff' end protected def protSup "Super's protected" end private def privSup "Super's private" end
end
module Other
def otherStuff 'did other stuff' end
end
class Sub < Super
CLASSNAME = 'sub' attr_reader :dynamic include Other def initialize(name, *args) super(name) @rest = args; @dynamic = {} def self.subOwn 'sub owned' end end def methods(regular=true) super + @dynamic.keys end def method_missing(name, *args, &block) return super unless @dynamic.member?(name) method = @dynamic[name] if method.arity > 0 if method.parameters[0][1] == :self args.unshift(self) end if method.lambda? # procs (hence methods) set missing arguments to `nil`, lambdas don't, so extend args explicitly args += args + [nil] * [method.arity - args.length, 0].max # procs (hence methods) discard extra arguments, lambdas don't, so discard arguments explicitly (unless lambda is variadic) if method.parameters[-1][0] != :rest args = args[0,method.arity] end end method.call(*args) else method.call end end def public_methods(all=true) super + @dynamic.keys end def respond_to?(symbol, include_all=false) @dynamic.member?(symbol) || super end def to_s "Sub(#{@name})" end def doSub 'did sub stuff' end def self.subClassStuff 'did sub class stuff' end protected def protSub "Sub's protected" end private def privSub "Sub's private" end
end
sup = Super.new('sup') sub = Sub.new('sub', 0, 'I', 'two') sub.dynamic[:incr] = proc {|i| i+1}
p sub.public_methods(false)
- => [:superOwn, :subOwn, :respond_to?, :method_missing, :to_s, :methods, :public_methods, :dynamic, :doSub, :incr]
p sub.methods - Object.methods
- => [:superOwn, :subOwn, :method_missing, :dynamic, :doSub, :protSub, :otherStuff, :doSup, :protSup, :incr]
p sub.public_methods - Object.public_methods
- => [:superOwn, :subOwn, :method_missing, :dynamic, :doSub, :otherStuff, :doSup, :incr]
p sub.methods - sup.methods
- => [:subOwn, :method_missing, :dynamic, :doSub, :protSub, :otherStuff, :incr]
- singleton/eigenclass methods
p sub.methods(false)
- => [:superOwn, :subOwn, :incr]
p sub.singleton_methods
- => [:superOwn, :subOwn]</lang>
Sidef
The super-method Object.methods() returns an Hash with method names as keys and LazyMethod objects as values. Each LazyMethod can be called with zero or more arguments, internally invoking the method on the object on which .methods was called. <lang ruby>class Example {
method foo { } method bar(arg) { say "bar(#{arg})" }
}
var obj = Example() say obj.methods.keys.sort #=> ["bar", "call", "foo", "new"]
var meth = obj.methods.item(:bar) # `LazyMethod` representation for `obj.bar()` meth(123) # calls obj.bar()</lang>
zkl
Every object has a "methods" method, which returns a list of method names [for that object]. If you want to get a method from a string, you can use reflection. <lang zkl>methods:=List.methods; methods.println(); List.method(methods[0]).println(); // == .Method(name) == .BaseClass(name) </lang>
- Output:
L("create","createLong","copy","toString","toBool","toData","toDictionary","toList","isType","isInstanceOf","holds","append","write","writeln","read","readln","extend","insert","find","findBop",...) Method(TSList.create)