Inspection
Objective: Extend class by a method that will print names and types of the instance variables.
Python
Based on type hints:
class Inspectable:
def show_vars(self):
for field_name, field_type in self.__annotations__.items():
print(f"{field_name!r} : {field_type.__name__}")
class Foo(Inspectable):
bar: int
baz: str
foo = Foo()
foo.show_vars()
Based the values of variables:
class Inspectable:
def show_vars(self):
for field_name in dir(self):
if not (field_name.startswith('__') and field_name.endswith('__')):
field_value = getattr(self, field_name)
if not callable(field_value):
print(f"{field_name!r} : {field_value.__class__.__name__}")
class Foo(Inspectable):
def __init__(self):
self.bar = 123
self.baz = "qwx"
foo = Foo()
foo.show_vars()
Note that there are more corner cases to be considered in Python. For instance how to differentiate instance variables and methods. Whether dunder variables should be considered or not, etc.
Rust
// inspired by: https://stackoverflow.com/a/56389650 macro_rules! generate_struct { ($name:ident {$($field_name:ident : $field_type:ty),+}) => { struct $name { $($field_name: $field_type),+ } impl $name { fn show_vars(&self) { $( let field_name = stringify!($field_name); let field_type = stringify!($field_type); println!("{:?} : {:?}", field_name, field_type); )* } } }; } generate_struct! { Foo { bar: i32, baz: String } } fn main() { let foo = Foo{bar: 123, baz: "abc".to_string()}; foo.show_vars(); }
Crystal
class Object
def vars
{{ @type.instance_vars.map {|v| v.name.stringify + " : " + v.type.stringify} }}
end
def show_vars
self.vars.each {|v| puts v}
end
end
class Foo
def initialize(@bar : Int32, @baz : String)
end
end
foo = Foo.new 123, "abc"
foo.show_vars()