Reflection/List methods: Difference between revisions

From Rosetta Code
Content added Content deleted
(added java)
(added objc)
Line 178: Line 178:
.filter(function(p) {return typeof p[1] == 'function';})
.filter(function(p) {return typeof p[1] == 'function';})
//[["subOwn", function () {...}]]</lang>
//[["subOwn", function () {...}]]</lang>

=={{header|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>
{{out}}
<pre>
bar: i24@0:8d16
</pre>


=={{header|Perl 6}}==
=={{header|Perl 6}}==

Revision as of 18:47, 6 August 2016

Reflection/List methods is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
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.

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>

  1. 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

Perl6 provides a Meta Object Protocol which allows introspection of both core and user defined objects.

See docs.perl6.org/type/Metamodel::ClassHOW for details.

For example, let's look at an instance of a rational (Rat) number: <lang perl6>my $variable = 2.5;

say "Value: ", $variable; # print the object value say "Type: ", $variable.WHAT; # print the object Type say "Name: ", $variable.VAR.name; # print the object name say "Attributes: ", $variable.^attributes; # print a list of object attributes say "Methods: ", $variable.^methods».name.sort; # print a list of methods that can be used by that object</lang>

Output:
Value:      2.5
Type:       (Rat)
Name:       $variable
Attributes: (Int $!numerator Int $!denominator)
Methods:    (ACCEPTS Bool Bridge Complex DUMP FatRat Int Num Numeric REDUCE-ME Range Rat Real Str WHICH abs acos acosec acosech acosh acotan acotanh asec asech asin asinh atan atan2 atanh base base-repeating ceiling cis conj cos cosec cosech cosh cotan cotanh denominator exp floor gist isNaN log log10 narrow new norm nude numerator perl polymod pred rand roots round sec sech sign sin sinh sqrt succ tan tanh truncate unpolar)

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

  1. 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

  1. names

[method for method in dir(sub) if callable(getattr(sub, method))]

  1. 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]

  1. ['__dir__', '__getattr__', '__init__', '__str__', 'doSub', 'doSup', 'otherMethod', 'strs']
  2. 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)]

  1. ['__subclasshook__', 'cls', 'subCls', 'supCls']
  2. static & free dynamic methods

[method for method in dir(sub) if callable(getattr(sub, method)) and type(getattr(sub, method)) == type(lambda:nil)]

  1. ['incr', 'subStatic', 'supStatic']
  1. names & values; doesn't include wrapped, C-native methods

inspect.getmembers(sub, predicate=inspect.ismethod)

  1. names using inspect

map(lambda t: t[0], inspect.getmembers(sub, predicate=inspect.ismethod))

  1. ['__dir__', '__getattr__', '__init__', '__str__', 'cls', 'doSub', 'doSup', 'otherMethod', 'strs', 'subCls', 'supCls']</lang>

Ruby

Ruby has various properties that will return lists of 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
   @rest = args;
   @dynamic = {}
   def self.subOwn
     return '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?
       args += args + [nil] * (method.arity - args.length, 0).max
       if method.parameters[-1][0] != :rest
         args = args[0,method.arity]
       end
     end
     return method.call(*args)
   end
   return method.call
 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}

sub.public_methods(false)

  1. [:superOwn, :subOwn, :respond_to?, :method_missing, :to_s, :methods, :public_methods, :doSub, :dynamic, :incr]

sub.methods - Object.methods

  1. [:superOwn, :subOwn, :method_missing, :doSub, :protSup, :protSub, :dynamic, :otherStuff, :doSup, :incr]

sub.public_methods - Object.public_methods

  1. [:superOwn, :subOwn, :method_missing, :doSub, :dynamic, :otherStuff, :doSup, :incr]

sub.methods - sup.methods

  1. [:subOwn, :method_missing, :doSub, :protSub, :dynamic, :otherStuff, :incr]
  1. singleton/eigenclass methods

sub.methods(false)

  1. [:superOwn, :subOwn, :incr]

sub.singleton_methods

  1. [:superOwn, :subOwn]</lang>