Reflective programming
In computer science, reflection (or computational reflection) is the ability of a program to observe and possibly modify its high level structure. Typically, reflection refers to runtime or dynamic reflection, though some programming languages support compile time or static reflection. It is most common in high-level virtual machine programming languages like Smalltalk, and less common in lower-level programming languages like C.
More generally, reflection is an activity in computation that reasons about its own computation. The programming paradigm driven by reflection is called reflective programming.
When program source code is compiled, information about the structure of the program is normally lost as lower level code (typically assembly language code) is produced. If a system supports reflection, the structure is preserved as metadata with the emitted code.
Depending on the implementation, code with reflection tends to run slower than that without it.
In languages that do not make distinction between runtime and compile-time (Lisp and its variants, for example), there is no difference between compilation or interpretation of code and reflection.
Implementation
A language supporting reflection provides a number of features available at runtime that would otherwise be very obscure or impossible to accomplish in a lower-level language. Some of these features are the abilities to:
- Discover and modify source code constructions (such as code blocks, classes, methods, protocols, etc.) as first-class objects at runtime.
- Convert a string matching the symbolic name of a class or function into a reference to or invocation of that class or function.
- Evaluate a string as if it were a source code statement at runtime.
These features can be implemented in different ways. Interpreted programming languages, such as Ruby and PHP, are ideally suited to reflection, since their source code is never lost in the process of translation to machine language— the interpreter has the source readily available. Compiled languages rely on their runtime system to provide information about the source code. A compiled Objective-C executable, for example, records the names of all methods in a block of the executable, providing a table to correspond these with the underlying methods (or selectors for these methods) compiled into the program.
Reflective programming languages and platforms
Known platforms typically supporting reflection are: dynamically typed languages (e.g., Objective-C, Ruby, Smalltalk), scripting languages (e.g., Perl, PHP, Python, Ruby); and the Maude system of rewriting logic.
- Aspect-oriented
- Befunge
- ColdFusion MX
- Curl
- ECMAScript a.k.a. ActionScript, DMDScript, JavaScript, JScript
- Eiffel
- Forth
- Java
- Lisp
- Lua
- Maude system
- .NET Common Language Runtime
- Oberon
- Objective-C
- Perl
- PHP
- Pico
- Pliant
- POP-11
- Poplog
- Prolog
- Python
- REBOL
- Ruby
- Scheme
- Smalltalk
- Snobol
- Tcl
Example
The following is an example in Java. Consider two pieces of code
// Without reflection Foo foo = new Foo (); foo.hello ();
// With reflection Class cl = Class.forName ("Foo"); Method method = cl.getMethod ("hello", null); method.invoke (cl.newInstance (), null);
Both code fragments create an instance of a class 'Foo' and call its 'hello' method. The difference is that, in the first fragment, the names of the class and method are hard-coded; it is not possible to use a class of another name. In the second fragment, the names of the class and method can easily be made to vary at runtime. Another major difference is that the second fragment is harder to read.
(See java.lang.reflect for more of this feature.)
Here is an equivalent example in Perl:
# without reflection Foo->new->hello;
# with reflection my $class = "Foo"; my $method = "hello"; $class->new->$method;