Reflection/List properties: Difference between revisions
Lingo added |
|||
Line 84:
cnt = obj.count
repeat with i = 1 to cnt
put obj.getPropAt(i)&" = "&obj[i]
end repeat</lang>
{{Out}}
<pre>
-- "bar = 42"
-- "foo = 23"
</pre>
|
Revision as of 05:13, 10 October 2016
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
The goal is to get the properties of an object, as names, values or both.
Some languages support dynamic properties, which in general can only be inspected if a class' public API includes a way of listing them.
Java
<lang java>import java.lang.reflect.Field;
public class ListFields {
public int examplePublicField = 42; private boolean examplePrivateField = true; public static void main(String[] args) throws IllegalAccessException { ListFields obj = new ListFields(); Class clazz = obj.getClass();
System.out.println("All public fields (including inherited):"); for (Field f : clazz.getFields()) { System.out.printf("%s\t%s\n", f, f.get(obj)); } System.out.println(); System.out.println("All declared fields (excluding inherited):"); for (Field f : clazz.getDeclaredFields()) { System.out.printf("%s\t%s\n", f, f.get(obj)); } }
}</lang>
- Output:
All public fields (including inherited): public int ListFields.examplePublicField 42 All declared fields (excluding inherited): public int ListFields.examplePublicField 42 private boolean ListFields.examplePrivateField true
JavaScript
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. Properties in JavaScript can be enumerable or non-enumerable; enumerable properties are accessable when looping over the object with for
. Object.getOwnPropertyNames()
.
<lang javascript>var obj = Object.create({
name: 'proto', proto: true, doNothing: function() {} }, { name: {value: 'obj', writable: true, configurable: true, enumerable: true}, obj: {value: true, writable: true, configurable: true, enumerable: true}, 'non-enum': {value: 'non-enumerable', writable: true, enumerable: false}, doStuff: {value: function() {}, enumerable: true}
});
// 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;
}
get_property_names(obj); //["name", "obj", "doStuff", "proto", "doNothing"]
Object.getOwnPropertyNames(obj); //["name", "obj", "non-enum", "doStuff"]
Object.keys(obj); //["name", "obj", "doStuff"]
Object.entries(obj); //[["name", "obj"], ["obj", true], ["doStuff", function()]] </lang>
Lingo
<lang lingo>obj = script("MyClass").new() obj.foo = 23 obj.bar = 42
-- ...
-- show obj's property names and values cnt = obj.count repeat with i = 1 to cnt
put obj.getPropAt(i)&" = "&obj[i]
end repeat</lang>
- Output:
-- "bar = 42" -- "foo = 23"
Objective-C
<lang objc>#import <Foundation/Foundation.h>
- import <objc/runtime.h>
@interface Foo : NSObject {
int exampleIvar;
} @property (nonatomic) double exampleProperty; @end @implementation Foo - (instancetype)init {
self = [super init]; if (self) { exampleIvar = 42; _exampleProperty = 3.14; } return self;
} @end
int main() {
id obj = [[Foo alloc] init]; Class clazz = [obj class];
NSLog(@"\Instance variables:"); unsigned int ivarCount; Ivar *ivars = class_copyIvarList(clazz, &ivarCount); for (unsigned int i = 0; i < ivarCount; i++) { Ivar ivar = ivars[i]; const char *name = ivar_getName(ivar); const char *typeEncoding = ivar_getTypeEncoding(ivar); // for simple types we can use Key-Value Coding to access it // but in general we will have to use object_getIvar and cast it to the right type of function // corresponding to the type of the instance variable id value = [obj valueForKey:@(name)]; NSLog(@"%s\t%s\t%@", name, typeEncoding, value); } free(ivars);
NSLog(@""); NSLog(@"Properties:"); unsigned int propCount; objc_property_t *properties = class_copyPropertyList([Foo class], &propCount); for (unsigned int i = 0; i < propCount; i++) { objc_property_t p = properties[i]; const char *name = property_getName(p); const char *attributes = property_getAttributes(p); // for simple types we can use Key-Value Coding to access it // but in general we will have to use objc_msgSend to call the getter, // casting objc_msgSend to the right type of function corresponding to the type of the getter id value = [obj valueForKey:@(name)]; NSLog(@"%s\t%s\t%@", name, attributes, value); } free(properties);
return 0;
}</lang>
- Output:
Instance variables: exampleIvar i 42 _exampleProperty d 3.14 Properties: exampleProperty Td,N,V_exampleProperty 3.14
Perl 6
You can get a list of an object's attributes (instance variables) using .^attributes, which is part of the Meta Object Protocol..
Each is represented as an Attribute object that contains a bunch of info:
<lang perl6>class Foo {
has $!a = now; has Str $.b; has Int $.c is rw;
}
my $object = Foo.new: b => "Hello", c => 42;
for $object.^attributes {
say join ", ", .name, .readonly, .container.^name, .get_value($object);
}</lang>
- Output:
$!a, True, Any, Instant:1470517602.295992 $!b, True, Str, Hello $!c, False, Int, 42
Public attributes (in this case, $.b and $.c) are really just attributes for which the compiler also auto-generates a method of the same name. See Reflection/List_methods#Perl_6.
PHP
<lang php><? class Foo { } $obj = new Foo(); $obj->bar = 42; $obj->baz = true;
var_dump(get_object_vars($obj)); ?></lang>
- Output:
array(2) { ["bar"]=> int(42) ["baz"]=> bool(true) }
Python
The dir()
function and Python's inspect
module both will list properties.
<lang python>class Parent(object):
__priv = 'private' def __init__(self, name): self.name = name def __repr__(self): return '%s(%s)' % (type(self).__name__, self.name) def doNothing(self): pass
import re
class Child(Parent):
# prefix for "private" fields __rePrivate = re.compile('^_(Child|Parent)__') # used when setting dynamic property values __reBleh = re.compile('\Wbleh$') @property def reBleh(self): return self.__reBleh def __init__(self, name, *args): super(Child, self).__init__(name) self.args = args def __dir__(self): myDir = filter( # filter out private fields lambda p: not self.__rePrivate.match(p), list(set( \ sum([dir(base) for base in type(self).__bases__], []) \ + type(self).__dict__.keys() \ + self.__dict__.keys() \ ))) return myDir + map( # dynamic properties lambda p: p + '_bleh', filter( # don't add dynamic properties for methods and other special properties lambda p: (p[:2] != '__' or p[-2:] != '__') and not callable(getattr(self, p)), myDir)) def __getattr__(self, name): if name[-5:] == '_bleh': # dynamic '_bleh' properties return str(getattr(self, name[:-5])) + ' bleh' if hasattr(super(Child, chld), '__getattr__'): return super(Child, self).__getattr__(name) raise AttributeError("'%s' object has no attribute '%s'" % (type(self).__name__, name)) def __setattr__(self, name, value): if name[-5:] == '_bleh': # skip backing properties that are methods if not (hasattr(self, name[:-5]) and callable(getattr(self, name[:-5]))): setattr(self, name[:-5], self.reBleh.sub(, value)) elif hasattr(super(Child, self), '__setattr__'): super(Child, self).__setattr__(name, value) elif hasattr(self, '__dict__'): self.__dict__[name] = value def __repr__(self): return '%s(%s, %s)' % (type(self).__name__, self.name, str(self.args).strip('[]()')) def doStuff(self): return (1+1.0/1e6) ** 1e6
par = Parent('par') par.parent = True dir(par)
- ['_Parent__priv', '__class__', ..., 'doNothing', 'name', 'parent']
inspect.getmembers(par)
- [('_Parent__priv', 'private'), ('__class__', <class '__main__.Parent'>), ..., ('doNothing', <bound method Parent.doNothing of <__main__.Parent object at 0x100777650>>), ('name', 'par'), ('parent', True)]
chld = Child('chld', 0, 'I', 'two') chld.own = "chld's own" dir(chld)
- ['__class__', ..., 'args', 'args_bleh', 'doNothing', 'doStuff', 'name', 'name_bleh', 'own', 'own_bleh', 'reBleh', 'reBleh_bleh']
inspect.getmembers(chld)
- [('__class__', <class '__main__.Child'>), ..., ('args', (0, 'I', 'two')), ('args_bleh', "(0, 'I', 'two') bleh"), ('doNothing', <bound method Child.doNothing of Child(chld, 0, 'I', 'two')>), ('doStuff', <bound method Child.doStuff of Child(chld, 0, 'I', 'two')>), ('name', 'chld'), ('name_bleh', 'chld bleh'), ('own', "chld's own"), ('own_bleh', "chld's own bleh"), ('reBleh', <_sre.SRE_Pattern object at 0x10067bd20>), ('reBleh_bleh', '<_sre.SRE_Pattern object at 0x10067bd20> bleh')]
</lang>
Ruby
<lang ruby>class Foo
@@xyz = nil def initialize(name, age) @name, @age = name, age end def add_sex(sex) @sex = sex end
end
p foo = Foo.new("Angel", 18) #=> #<Foo:0x0000000305a688 @name="Angel", @age=18> p foo.instance_variables #=> [:@name, :@age] p foo.instance_variable_defined?(:@age) #=> true p foo.instance_variable_get(:@age) #=> 18 p foo.instance_variable_set(:@age, 19) #=> 19 p foo #=> #<Foo:0x0000000305a688 @name="Angel", @age=19> foo.add_sex(:woman) p foo.instance_variables #=> [:@name, :@age, :@sex] p foo #=> #<Foo:0x0000000305a688 @name="Angel", @age=19, @sex=:woman> foo.instance_variable_set(:@bar, nil) p foo.instance_variables #=> [:@name, :@age, :@sex, :@bar]
p Foo.class_variables #=> [:@@xyz] p Foo.class_variable_defined?(:@@xyz) #=> true p Foo.class_variable_get(:@@xyz) #=> nil p Foo.class_variable_set(:@@xyz, :xyz) #=> :xyz p Foo.class_variable_get(:@@xyz) #=> :xyz p Foo.class_variable_set(:@@abc, 123) #=> 123 p Foo.class_variables #=> [:@@xyz, :@@abc]</lang>
zkl
In zkl, properties are static read only informational data.
Every object has a "properties" method, which returns a list of property names [for that object]. <lang zkl>properties:=List.properties; properties.println(); List(1,2,3).property(properties[0]).println(); // get value List(1,2,3).Property(properties[0])().println(); // method that gets value List(1,2,3).BaseClass(properties[0]).println(); // another way to get value</lang>
- Output:
L("size","isReadOnly","id","name","fullName","type","otype","oID","itype","typeID","properties","methods","vaultPath","numObjects","isThreadSafe","isContainer","createReturnsSelf") L(24,32) L(24,32) L(24,32)