Agents versus Adapters

by Colin LeMahieu (modified: 2010 May 12)

This really applies to all incarnations in all languages of higher order functions in Object Oriented languages. At a high level, this article is a case for using adapter classes in place of agents.

Agents provide two main things, the ability to pass around a routine (higher order function) and the ability to fill in parameters at different points in execution (closure/continuation).

Agents as higher order functions: The functionality of agents as higher order functions is not orthogonal to other language constructs. The role of agents can simply be replaced with polymorphism and in fact, a polymorphic class better satisfies the role because contracts can be associated with a class, whereas they cannot be associated with an agent.

An agent of the form: agent_ex: FUNCTION [ANY, TUPLE [one: STRING; two: LIST [NATURAL]], NATURAL] Would be equivalent to the polymorphic class: class ADAPTER feature function_one (one: STRING; two: LIST [NATURAL]): NATURAL deferred end end

Agents as closures/continuations: Using agents as closures and continuations is also not orthogonal with other language constructs. An ADT will satisfy this requirement: class ADAPTER feature function_one: NATURAL require closed deferred end one: detachable STRING assign one_set two: detachable LIST [NATURAL] assign two_set one_closed: BOOLEAN two_closed: BOOLEAN one_set (one_a: detachable STRING) do one := one_a one_closed := True ensure one_closed end two_set (two_a: detachable LIST [NATURAL]) do two := two_a two_closed := True ensure two_closed end closed: BOOLEAN do Result := one_closed and two_closed end end

Another consideration to take in to account is the extensibility of agents. It's one thing if you need a single higher order function but what if you need a grouping of functions to be passed around together, possibly with some ancillary data. With agents you might group them together in a TUPLE: agent_ex: TUPLE [one_f: FUNCTION [ANY, TUPLE [one: STRING; two: LIST [NATURAL]], NATURAL]; two_f: PROCEDURE [one: INTEGER]; three: STRING] But with a class, you simply add another deferred function class ADAPTER feature function_ex (one: STRING; two: LIST [NATURAL]): NATURAL deferred end function2_ex (one: INTEGER) deferred end three: STRING end

One definite difference between the agent and class implementations is the terseness of the agent implementation. There's a lot of boilerplate code that needs to be added to adapters in order to make them work when the agent syntax is so seductively simple. The terseness of creating an agent loses some ground against the verboseness of handling them and of course they are not as expressive as adapters.

As above, handling a complex container of agents might look like: agent_ex: TUPLE [one_f: FUNCTION [ANY, TUPLE [one: STRING; two: LIST [NATURAL]], NATURAL]; two_f: PROCEDURE [one: INTEGER]; three: STRING] but this becomes trivial as an adapter class like: adapter_ex: ADAPTER

To make better use of adapters and help with boilerplate code, I would suggest an EiffelStudio tool that allows adapter class generation with the following method.

- Add an additional item to the "Refactoring" toolbar named "Generate Adapter".
- This button accepts a class stone of the deferred adapter class from which to generate a implementation.
- The dialog would then present a window listing classes in the system.
- Classes containing the necessary feature signatures to fully create an adapter would appear completely opaque while classes not containing the necessary features would appear partially translucent to indicate some features will need to be implemented manually.
- A group exists for each deferred function that needs to be implemented by the target class
- Each group would have a check box option to create closure setters, BOOLEANs, and contracts for the routine, and a selection box listing the possible routines to use to use with signatures matching the deferred feature.
- The tool would then generate the desired class.

Below is an embarrassingly simple and ugly example of the proposed tool's dialog window.