(ref.doc)pd130395
Next pd111095
Prev: pd060395
Up: pat
Date: Mon, 13 Mar 1995 10:38:08 -0600
Originator: [email protected]
From: Thomas Kuehne <[email protected]>
Subject: Pattern: Function Closure
I hope this is the correct list for presenting patterns.
I am not sure whether [email protected] still lives so I am repeating
the mail here.
The main reason why I wrote this is that there was no connection between
Iterator and Command in the GOF book.
IMO, there clearly is one and so I take the effort and present a pattern
which is similar to Command but extends it. One might argue it is
a combination of two Patterns: Command (with result) and
Partial Parameterization (not at structural but rather a technique pattern).
In order to make it a good pattern description I should invest more work,
but I want to test the acceptance for a 'variation on Command' first.
Name: Function Closure
Intent: Encapsulate a function as an object, thereby letting you benefit
from many attractive features from functional programming, such
as: Higher order functionality, Currying, lazy evaluation,
infinite data structures.
Note, that Function Closure without partial parameterization
(Currying) and with a function that produces side-effects only,
boils down to the Command pattern.
Reversely Function Closure may also be used where Command is used,
e.g. separate callers and servers and undoing.
Also Known As:
*Agent-Object*, which has been indepently used by me [SIG94] and
Andrew Koenig (for the Booch Components).
In order to avoid confusion with intelligent- or distributed-
Agents I called it *Function Object* [TOOLS94].
In a pattern context the term 'Object' is not necessary and
'Closure' nicely serves to demonstrate the difference to Command.
Motivation:
Choosing an OO-language should not mean that one is deprived of
all goodies of a functional language.
Whereas Smalltalk programmers frequently use blocks for higher
order functionality, C++, Eiffel, etc. programmers are normally forced
to use function pointers or inheritance as substitutes.
Function Closure truncates an object to a single method with
an attribute environment. Thus it can be used just like a
function in a functional language:
o It can be passed to other objects (e.g. pass a compare
predicate to a sorter).
o It can be partially parameterized (e.g. pass "H.G. Wells"
to a predicate you used for sorting books according to titles and
use it to find a book in a binary search tree).
o It can produce other function closures (which is one way
to implement currying).
o It can accept other function closures (e.g. a function
performing actions on books might take a test function closures
that it asks whether to perform the action or not).
o It can be composed of other functions (similar to MacroCommands).
o It can be used to postpone an evaluation until it is needed.
o Data structures may use function closures to defer their
contents to calculation, enabling infinite data structures.
o It can be used where ever Smalltalk blocks are used.
Whereas Smalltalk blocks bind the environment to
free variables implicitely, this has to be done explicitely.
o As it subsumes Command it can be used where ever Command is used
(e.g. Callback function for Window-Interface).
Note, that partial parameterization is handy here as well.
Imagine the interface has changed, that is, more parameters
are needed to control appearance (e.g. consider the change
from textual output to a graphical alert).
The client that calls the Function Closure does not need to
provide the additional parameters and thus needs not to be
changed, since we can pass the additional parameters to
the Function Closure previous to passing it to the client.
Implementation
This is similar to Command but there are options how to
realize partial parameterization.
Either currying is implemented by producing a new Function Closure
as a result of supplying an argument to a Function Closure or
by internally counting the received arguments, dispatching them
to appropiate attributes.
Providing full parameterization (that is any order of supplying
arguments is allowed) widens the interface of Function Closures.
With the reasonable restriction of partial parameterization to
currying Function Closures uniformly support
o 'supply(...)', which takes an argument
o 'evaluate', which produces the function result.
Related Patterns:
The most frequent collaboration will be with Iterator.
Function Closures enable C++, Eiffel, etc. programmers
to benefit from internal iterators as Smalltalk programmers
natively can. Iterator is passed a Function Closure and
passes each of it's elements to the Function Closure subsequently.
Typically the result of each call will be assigned back to the
element, but it is also possible to use side effects on elements.
If there is interest I want to add a short discussion on internal/external
iterations and why I think that Eiffel and Smalltalk should exchange their
philosophies on implementing iteration a) in data structures or b) extra
iteration classes. I'd like to do it now but our sysop shuts down
the system for a while :(
References:
[SIG94] Thomas Kühne "Higher Order Objects in pure Object-Oriented Languages"
ACM SIGPLAN NOTICES Volume 29, Number 7, 1994
[TOOLS94] Thomas Kühne "Inheritance versus Parameterization"
Proceedings of the 15.th conference of Object-Oriented Languages
and Systems: TOOLS Pacific 1994, pages 235-245,
Prentice Hall
"Proceedings contain premature layout version:
For correct versions please address the author"