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:
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 some ancillary data. With agents you might group them together in a TUPLE:
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 adapter.
As above, handling a complex container of agents might look like:
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 row would have a check box option to create closure setters, BOOLEANs, and contracts for the routine. - The tool would then generate the desired class.
Below is an embarrassingly simple and ugly example of the proposed tool's dialog window.