Type introspection

Last updated

In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime. Some programming languages possess this capability.

Contents

Introspection should not be confused with reflection, which goes a step further and is the ability for a program to manipulate the metadata, properties, and functions of an object at runtime. Some programming languages also possess that capability (e.g., Java, Python, Julia, and Go).

Examples

Objective-C

In Objective-C, for example, both the generic Object and NSObject (in Cocoa/OpenStep) provide the method isMemberOfClass: which returns true if the argument to the method is an instance of the specified class. The method isKindOfClass: analogously returns true if the argument inherits from the specified class.

For example, say we have an Apple and an Orange class inheriting from Fruit.

Now, in the eat method we can write

-(void)eat:(id)sth{if([sthisKindOfClass:[Fruitclass]]){// we're actually eating a Fruit, so continueif([sthisMemberOfClass:[Appleclass]]){eatApple(sth);}elseif([sthisMemberOfClass:[Orangeclass]]){eatOrange(sth);}else{error();}}else{error();}}

Now, when eat is called with a generic object (an id), the function will behave correctly depending on the type of the generic object.

C++

C++ supports type introspection via the run-time type information (RTTI) typeid and dynamic cast keywords. The dynamic_cast expression can be used to determine whether a particular object is of a particular derived class. For instance:

Person*p=dynamic_cast<Person*>(obj);if(p!=nullptr){p->walk();}

The typeid operator retrieves a std::type_info object describing the most derived type of an object:

if(typeid(Person)==typeid(*obj)){serialize_person(obj);}

Object Pascal

Type introspection has been a part of Object Pascal since the original release of Delphi, which uses RTTI heavily for visual form design. In Object Pascal, all classes descend from the base TObject class, which implements basic RTTI functionality. Every class's name can be referenced in code for RTTI purposes; the class name identifier is implemented as a pointer to the class's metadata, which can be declared and used as a variable of type TClass. The language includes an is operator, to determine if an object is or descends from a given class, an as operator, providing a type-checked typecast, and several TObject methods. Deeper introspection (enumerating fields and methods) is traditionally only supported for objects declared in the $M+ (a pragma) state, typically TPersistent, and only for symbols defined in the published section. Delphi 2010 increased this to nearly all symbols.

procedureForm1.MyButtonOnClick(Sender:TObject);varaButton:TButton;SenderClass:TClass;beginSenderClass:=Sender.ClassType;//returns Sender's class pointerifsenderisTButtonthenbeginaButton:=senderasTButton;EditBox.Text:=aButton.Caption;//Property that the button has but generic objects don'tendelsebeginEditBox.Text:=Sender.ClassName;//returns the name of Sender's class as a stringend;end;

Java

The simplest example of type introspection in Java is the instanceof [1] operator. The instanceof operator determines whether a particular object belongs to a particular class (or a subclass of that class, or a class that implements that interface). For instance:

if(objinstanceofPersonp){p.walk();}

The java.lang.Class [2] class is the basis of more advanced introspection.

For instance, if it is desirable to determine the actual class of an object (rather than whether it is a member of a particular class), Object.getClass() and Class.getName() can be used:

System.out.println(obj.getClass().getName());

PHP

In PHP introspection can be done using instanceof operator. For instance:

if($objinstanceofPerson){// Do whatever you want}

Perl

Introspection can be achieved using the ref and isa functions in Perl.

We can introspect the following classes and their corresponding instances:

packageAnimal;subnew{my$class=shift;returnbless{},$class;}packageDog;usebase'Animal';packagemain;my$animal=Animal->new();my$dog=Dog->new();

using:

print"This is an Animal.\n"ifref$animaleq'Animal';print"Dog is an Animal.\n"if$dog->isa('Animal');

Meta-Object Protocol

Much more powerful introspection in Perl can be achieved using the Moose object system [3] and the Class::MOP meta-object protocol; [4] for example, you can check if a given object does a role X:

if($object->meta->does_role("X")){# do something ...}

This is how you can list fully qualified names of all of the methods that can be invoked on the object, together with the classes in which they were defined:

formy$method($object->meta->get_all_methods){print$method->fully_qualified_name,"\n";}

Python

The most common method of introspection in Python is using the dir function to detail the attributes of an object. For example:

classFoo:def__init__(self,val):self.x=valdefbar(self):returnself.x
>>> dir(Foo(5))['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__','__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__','__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']

Also, the built-in functions type and isinstance can be used to determine what an object is while hasattr can determine what an object does. For example:

>>> a=Foo(10)>>> b=Bar(11)>>> type(a)<type 'Foo'>>>> isinstance(a,Foo)True>>> isinstance(a,type(a))True>>> isinstance(a,type(b))False>>> hasattr(a,'bar')True

Ruby

Type introspection is a core feature of Ruby. In Ruby, the Object class (ancestor of every class) provides Object#instance_of? and Object#kind_of? methods for checking the instance's class. The latter returns true when the particular instance the message was sent to is an instance of a descendant of the class in question. For example, consider the following example code (you can immediately try this with the Interactive Ruby Shell):

$ irbirb(main):001:0> A=Class.new=> Airb(main):002:0> B=Class.newA=> Birb(main):003:0> a=A.new=> #<A:0x2e44b78>irb(main):004:0> b=B.new=> #<B:0x2e431b0>irb(main):005:0> a.instance_of?A=> trueirb(main):006:0> b.instance_of?A=> falseirb(main):007:0> b.kind_of?A=> true

In the example above, the Class class is used as any other class in Ruby. Two classes are created, A and B, the former is being a superclass of the latter, then one instance of each class is checked. The last expression gives true because A is a superclass of the class of b.

Further, you can directly ask for the class of any object, and "compare" them (code below assumes having executed the code above):

irb(main):008:0> A.instance_of?Class=> trueirb(main):009:0> a.class=> Airb(main):010:0> a.class.class=> Classirb(main):011:0> A>B=> trueirb(main):012:0> B<=A=> true

ActionScript

In ActionScript (as3), the function flash.utils.getQualifiedClassName can be used to retrieve the class/type name of an arbitrary object.

// all classes used in as3 must be imported explicitlyimportflash.utils.getQualifiedClassName;importflash.display.Sprite;// trace is like System.out.println in Java or echo in PHPtrace(flash.utils.getQualifiedClassName("I'm a String"));// "String"trace(flash.utils.getQualifiedClassName(1));// "int", see dynamic casting for why not Numbertrace(flash.utils.getQualifiedClassName(newflash.display.Sprite()));// "flash.display.Sprite"

Alternatively, the operator is can be used to determine if an object is of a specific type:

// trace is like System.out.println in Java or echo in PHPtrace("I'm a String"isString);// truetrace(1isString);// falsetrace("I'm a String"isNumber);// falsetrace(1isNumber);// true

This second function can be used to test class inheritance parents as well:

importflash.display.DisplayObject;importflash.display.Sprite;// extends DisplayObjecttrace(newflash.display.Sprite()isflash.display.Sprite);// truetrace(newflash.display.Sprite()isflash.display.DisplayObject);// true, because Sprite extends DisplayObjecttrace(newflash.display.Sprite()isString);// false

Meta-type introspection

Like Perl, ActionScript can go further than getting the class name, but all the metadata, functions and other elements that make up an object using the flash.utils.describeType function; this is used when implementing reflection in ActionScript.

importflash.utils.describeType;importflash.utils.getDefinitionByName;importflash.utils.getQualifiedClassName;importflash.display.Sprite;varclassName:String=getQualifiedClassName(newflash.display.Sprite());// "flash.display.Sprite"varclassRef:Class=getDefinitionByName(className);// Class reference to flash.display{{Not a typo|.}}Sprite// eg. 'new classRef()' same as 'new  flash.display.Sprite()'trace(describeType(classRef));// return XML object describing type// same as : trace(describeType(flash.display.Sprite));

See also

Related Research Articles

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. It is a kind of lazy evaluation that refers specifically to the instantiation of objects or other resources.

In software engineering, the mediator pattern defines an object that encapsulates how a set of objects interact. This pattern is considered to be a behavioral pattern due to the way it can alter the program's running behavior.

In software design and engineering, the observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

In object-oriented (OO) and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change, but the object's state appears unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

In computer science, reflective programming or reflection is the ability of a process to examine, introspect, and modify its own structure and behavior.

<span class="mw-page-title-main">ActionScript</span> Object-oriented programming language created for the Flash multimedia platform

ActionScript is an object-oriented programming language originally developed by Macromedia Inc.. It is influenced by HyperTalk, the scripting language for HyperCard. It is now an implementation of ECMAScript, though it originally arose as a sibling, both being influenced by HyperTalk. ActionScript code is usually converted to bytecode format by a compiler.

In computer programming, run-time type information or run-time type identification (RTTI) is a feature of some programming languages that exposes information about an object's data type at runtime. Run-time type information may be available for all types or only to types that explicitly have it. Run-time type information is a specialization of a more general concept called type introspection.

<span class="mw-page-title-main">Method overriding</span> Language feature in object-oriented programming

Method overriding, in object-oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. In addition to providing data-driven algorithm-determined parameters across virtual network interfaces, it also allows for a specific type of polymorphism (subtyping). The implementation in the subclass overrides (replaces) the implementation in the superclass by providing a method that has same name, same parameters or signature, and same return type as the method in the parent class. The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed. This helps in preventing problems associated with differential relay analytics which would otherwise rely on a framework in which method overriding might be obviated. Some languages allow a programmer to prevent a method from being overridden.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

In computing based on the Java Platform, JavaBeans is a technology developed by Sun Microsystems and released in 1996, as part of JDK 1.1.

In the Java programming language, the final keyword is used in several contexts to define an entity that can only be assigned once.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, parameters and Java packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from Java class files generated by the Java compiler. This allows annotations to be retained by the Java virtual machine at run-time and read via reflection. It is possible to create meta-annotations out of the existing ones in Java.

<span class="mw-page-title-main">Java collections framework</span> Collections in Java

The Java collections framework is a set of classes and interfaces that implement commonly reusable collection data structures.

Jakarta Mail is a Jakarta EE API used to send and receive email via SMTP, POP3 and IMAP. Jakarta Mail is built into the Jakarta EE platform, but also provides an optional package for use in Java SE.

typeof, alternately also typeOf, and TypeOf, is an operator provided by several programming languages to determine the data type of a variable. This is useful when constructing programs that must accept multiple types of data without explicitly specifying the type.

Smart Pascal is an Object Pascal programming language that is derived from Delphi Web Script and is adapted for Smart Mobile Studio for generating commercial JavaScript machine code. As a rapid application development (RAD) language, it contains a library of classes and components. The Smart Pascal compiler is a source-to-source compiler generating server-independent applications which are compliant with HTML5. Compiled Smart applications can be executed in a modern HTML5-capable browser. A compiled program is then typically embedded within a DIV container element or alternatively set to occupy the entire display.

Apache Commons Logging is a Java-based logging utility and a programming model for logging and for other toolkits. It provides APIs, log implementations, and wrapper implementations over some other tools.

<span class="mw-page-title-main">Strongly typed identifier</span>

A strongly typed identifier is user-defined data type which serves as an identifier or key that is strongly typed. This is a solution to the "primitive obsession" code smell as mentioned by Martin Fowler. The data type should preferably be immutable if possible. It is common for implementations to handle equality testing, serialization and model binding.

References