Inversion of control
![]() | This article needs attention from an expert in Computer science. Please add a reason or a talk parameter to this template to explain the issue with the article.(November 2008) |
Inversion of Control, or IoC, is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to the traditional architecture of software libraries.
Control flow is expressed in imperative programming in the form of a series of instructions or procedure calls. Instead of specifying a sequence of decisions and procedures to occur during the lifetime of a process, the user of an IoC framework writes the desired responses linked to particular events or data requests. External entities then take control over the precise calling order and additional maintenance that are to be carried out to execute the process [1]. In a sense, inversion of control follows what has been referred to as the "Hollywood Principle"—"don't call us, we will call you".
In practice, Inversion of Control is a style of software construction where reusable, generic code controls the execution of problem-specific code with the strong connotation that the reusable code and the problem-specific code are developed independently and the result often being a single integrated application.
Background
Traditionally, computers were programmed with hand-written sequences of instructions for a particular machine. This concept existed well before computers, starting from cooking recipes and screenplays to the formal definition of a Turing Machine. As software grew more and more complex, common tasks were factored out into procedures, where a "main" procedure may run specific instructions or call upon auxiliary procedures for the more general tasks. Some procedures may be application-specific ("user" procedures), or they may be taken from a previously prepared library. This style of programming was the subject of extensive research in the 1960s and 1970s under the discipline of "structured programming".
Over time, it was discovered that certain routines would follow similar idioms. E.g., a command-line menu usually revolves around the cycle of:
display prompt get user command process user command
It is desirable to factor out this common functionality and place it in a library. However, unlike traditional library procedures, this procedure does not know how to complete the task in its entirety. It defines only a general structure and must call user code to perform lower-level tasks such as "process user command". It is not known in advance which user code will be called. User procedures must be supplied to the library procedure (directly or indirectly) at runtime in a form of function pointers or similar constructs.
Definition
Traditional control flow occurs when user procedures call library procedures. Library procedures may call other library procedures, but they never call back into the user code.
Inversion of control occurs when a library procedure calls user procedure(s). Usually this happens when the library defines an abstract solution to a problem and must rely on user code to perform lower-level tasks.
IoC serves as a guiding rule to design the architecture of software systems. The distinguishing feature is which module is expected to perform the control calls: in traditional libraries the client is expected to call the reusable library functions, whereas in an IoC framework the reusable code is the one which calls the application-specific client code.
The following programming concepts are direct applications of the IoC principle:
- Event-driven programming
- Dependency injection - the process of supplying an external dependency to a software library.
- In functional languages a monad can be seen as a structure exhibiting IoC, since monads are reusable entities that call user-defined functions in arbitrary order as building blocks for complex processes.
Example
A simple example to illustrate the precise meaning of inversion in inversion of control would be software that takes the user's name and then displays a greeting containing the name.
A basic command-line application might look like this:
>> Please enter your name: Mohammed Hi there, Mohammed!
A similar GUI application would consist of a text field, labeled Name, and a button labeled Greeting, upon the pressing of which the user would receive a message saying, Hi there, <name>!.
The important distinction between the above two examples is how the user interaction happens. In the first case, the flow is always the same: the user receives a prompt, types in a name, and receives a greeting in response. This corresponds in a straightforward manner to the following pseudocode:
def display_greeting(name):
print "Hi there, " + name + "!"
name = read_name()
display_greeting(name)
exit()
In comparison, in the second case, the user could input a name, then change it to something else before clicking the button, then click it several times in succession without changing the provided name. It could be sketched with the following pseudocode:
def display_greeting(name):
popup_message("Hi there, " + name + "!")
button.connect("clicked", display_greeting,
argument=text_field.contents()) # connect display_greeting to the "clicked" event
# and pass the text_field contents as an extra argument
wait_for_events() # Loop for indefinite amount of time, waiting for events
In the first example, the control flow is explicitly set by the order of function calls (read_name()
etc.). However, in the second example, the programmer defines what will happen when a certain event occurs and wraps this functionality into a procedure. This procedure is then "connected" to the button's clicked
event by passing the procedure to a separate procedure called button.connect
(the details of which are not shown). Inversion of control is this process of passing code into a procedure rather than having the procedure hard-coded to call a particular external procedure.
Advantages and disadvantages of inversion of control
The first example, despite its simplicity, hints at some very significant implications of inversion of control. In the straight style, one can easily trace the control flow given a sequence of inputs. However, it is very difficult to write code in this style that can handle an arbitrary sequence of events. If the programmer wanted to allow the user to correct the name before it's submitted, or to display the greeting twice, each such scenario would need to be coded for and supported separately.
In the second example, infinitely many possible scenarios can be realized. The price paid for that additional flexibility is greatly increased complexity and the fact that the program is no longer deterministic: it's no longer possible to tell what functions will be called just by looking at the code; one needs to consider the code and the environment to be able to determine the order of events. The code is also much harder to write and reason about, and computations that are naturally sequential (A needs to happen before B, such as User name must be provided before the login can be successful) can be much harder to write and understand.
Applications of inversion of control
Inversion of control can be applied wherever it is not possible to give a definitive answer to "what does a proper session look like?". For situations in which it's not practical to specify every possible sequence of interactions, inverted control might be applicable and useful. Examples of such situations include, amongst others, graphical user interfaces, network servers, daemons listening to events from the system/hardware, etc.
References
- ^ Designing Reusable Classes,Ralph E. Johnson & Brian Foote - Journal of Object-Oriented Programming June/July 1988, Volume 1, Number 2, pages 22-35
See also
- Asynchronous I/O
- Callback (computer science)
- Closure (computer science)
- Continuations in Web development
- Delegate (.NET)
- Dependency injection
- Dependency inversion principle
- DOM events
- Event-driven programming
- Implicit invocation
- Interrupt handler
- libsigc++, a callback library for C++
- Monad (functional programming)
- Observer pattern
- Publish/subscribe
- Service locator pattern
- Signal (computing)
- Software framework
- Strategy pattern
- User exit
- Visitor pattern
- XSLT is a data-driven scripting language, meaning that the input data controls which templates (methods) are executed and in what order. Templates automatically return control to the input data upon completion or by using the <xsl:apply-templates /> command.