Function Object - in Eiffel

In Eiffel

In the Eiffel software development method and language, operations and objects are seen always as separate concepts. However, the agent mechanism facilitates the modeling of operations as runtime objects. Agents satisfy the range of application attributed to function objects, such as being passed as arguments in procedural calls or specified as callback routines. The design of the agent mechanism in Eiffel attempts to reflect the object-oriented nature of the method and language. An agent is an object that generally is a direct instance of one of the two library classes, which model the two types of routines in Eiffel: PROCEDURE and FUNCTION. These two classes descend from the more abstract ROUTINE.

Within software text, the language keyword agent allows agents to be constructed in a compact form. In the following example, the goal is to add the action of stepping the gauge forward to the list of actions to be executed in the event that a button is clicked.

my_button.select_actions.extend (agent my_gauge.step_forward)

The routine extend referenced in the example above is a feature of a class in a graphical user interface (GUI) library to provide event-driven programming capabilities.

In other library classes, agents are seen to be used for different purposes. In a library supporting data structures, for example, a class modeling linear structures effects universal quantification with a function for_all of type BOOLEAN that accepts an agent, an instance of FUNCTION, as an argument. So, in the following example, my_action is executed only if all members of my_list contain the character '!':

my_list: LINKED_LIST ... if my_list.for_all (agent {STRING}.has ('!')) then my_action end ...

When agents are created, the arguments to the routines they model and even the target object to which they are applied can be either closed or left open. Closed arguments and targets are given values at agent creation time. The assignment of values for open arguments and targets is deferred until some point after the agent is created. The routine for_all expects as an argument an agent representing a function with one open argument or target that conforms to actual generic parameter for the structure (STRING in this example.)

When the target of an agent is left open, the class name of the expected target, enclosed in braces, is substituted for an object reference as shown in the text agent {STRING}.has ('!') in the example above. When an argument is left open, the question mark character ('?') is coded as a placeholder for the open argument.

The ability to close or leave open targets and arguments is intended to improve the flexibility of the agent mechanism. Consider a class that contains the following procedure to print a string on standard output after a new line:

print_on_new_line (s: STRING) -- Print `s' preceded by a new line do print ("%N" + s) end

The following snippet, assumed to be in the same class, uses print_on_new_line to demonstrate the mixing of open arguments and open targets in agents used as arguments to the same routine.

my_list: LINKED_LIST ... my_list.do_all (agent print_on_new_line (?)) my_list.do_all (agent {STRING}.to_lower) my_list.do_all (agent print_on_new_line (?)) ...

This example uses the procedure do_all for linear structures, which executes the routine modeled by an agent for each item in the structure.

The sequence of three instructions prints the strings in my_list, converts the strings to lowercase, and then prints them again.

Procedure do_all iterates across the structure executing the routine substituting the current item for either the open argument (in the case of the agents based on print_on_new_line), or the open target (in the case of the agent based on to_lower).

Open and closed arguments and targets also allow the use of routines that call for more arguments than are required by closing all but the necessary number of arguments:

my_list.do_all (agent my_multi_arg_procedure (closed_arg_1, ?, closed_arg_2, closed_arg_3)

The Eiffel agent mechanism is detailed in the Eiffel ISO/ECMA standard document.

Read more about this topic:  Function Object