1: \documentclass[times, 10pt,twocolumn]{article}
2: \usepackage{times,latex8,epsfig,graphicx,amssymb,latexsym,lscape}
3: \newcommand{\pr}{\vspace{4mm}}
4: \newcommand{\mr}{\hbox{{\it merge}}}
5: \newcommand{\spl}{\hbox{{\it split}}}
6: \newcommand{\cc}{\hbox{{\tt C}}}
7: \newcommand{\cpp}{\hbox{{\tt C++}}}
8:
9: \hyphenation{Data-stream}
10: \hyphenation{Data-pipe}
11: \hyphenation{par-a-digms}
12: \hyphenation{Ash-croft}
13: \hyphenation{mul-ti-par-a-digm}
14: \hyphenation{object-ori-en-ta-tion}
15: \hyphenation{pro-ce-dure-ori-ent-ed}
16:
17: \begin{document}
18:
19: %\title{Model the Paradigm; the Application Will Take Care of Itself}
20: \title{Object-Oriented Modeling of Programming Paradigms}
21:
22: \author{
23: M.H. van Emden\\
24: University of Victoria\\
25: Victoria, B.C., Canada
26: \and
27: S.C. Somosan\\
28: NewHeights Software Corporation\\
29: Victoria, B.C., Canada
30: }
31:
32: \maketitle
33: \thispagestyle{empty}
34:
35: \begin{abstract}
36: For the right application, the use of programming paradigms such as
37: functional or logic programming can enormously increase productivity
38: in software development. But these powerful paradigms are tied to exotic
39: programming languages, while the management of software development
40: dictates standardization on a single language.
41:
42: This dilemma can be resolved by using object-oriented programming in a
43: new way. It is conventional to analyze an \emph{application} by
44: object-oriented modeling. In the new approach, the analysis identifies
45: the paradigm that is ideal for the application; development starts with
46: object-oriented modeling of the \emph{paradigm}. In this paper we
47: illustrate the new approach by giving examples of object-oriented
48: modeling of dataflow and constraint programming. These examples
49: suggest that it is no longer necessary to embody a programming paradigm
50: in a language dedicated to it.
51: \end{abstract}
52:
53: \Section{Introduction}
54:
55: What programming language should we use? The answer to this question
56: has changed over the decades. In the 1970s the answer was: ``The Right
57: One''. Since then it has become: ``What Everyone Else Is Using''. For
58: example, in the 1970s one company embarked on the design and
59: implementation of a language that was to be ideal for developing
60: telephone switch software. Although they were successful, in the 1990s
61: they judged it more important to use a standardized language with
62: multiple and competing vendors. Accordingly, the ideal language was replaced by
63: {\tt C} and {\tt C++}, much to the detriment of their subsequent software
64: development.
65:
66: Not only in this company, but in almost every other organization, a
67: similar shift has occurred. In this paper, we want to re-examine the
68: now discarded answer, ``The Right One.'' Why was this ever considered
69: the right answer?
70:
71: We believe it was based on the observation that with
72: the languages such as Prolog, Scheme or ML, some problems become
73: miraculously easy to program. But that depends on the problem: if it is
74: easy in Scheme or ML, it may not be so in Prolog, and vice versa. Thus, the
75: effect depends on the \emph{programming paradigm} on which the language
76: is based: functional programming in the case of Scheme and ML; logic
77: programming in the case of Prolog.
78:
79: The fact that, with the right choice of language some problems become
80: miraculously easy to program we call the \emph{Whitehead effect},
81: inspired by the following quote from
82: Alfred North Whitehead (1861-1947):
83: \begin{quote}
84: ``By relieving the brain of unnecessary work, a good notation sets it free to
85: concentrate on more advanced problems, $\ldots$ ''
86: \end{quote}
87: Whitehead goes on to claim that the effect is to increase the mental capacity
88: of those who use the notation.
89:
90: In this connection one should also note the \emph{Sapir-Whorf
91: hypothesis}, stating that what one can think is determined by one's
92: language. In this form the hypothesis is vague in the extreme. Though
93: various attempts at making it concrete have been discredited, the
94: hypothesis may have something to do with the fact that, with the right
95: language, some things become miraculously easy to program.
96:
97: \SubSection{Radical Software Development}
98: The Whitehead effect suggests that one first determines the
99: programming paradigm that makes the application miraculously easy to
100: program and that one then uses a language that embodies the paradigm.
101: This we call \emph{Radical Software Development}.
102:
103: It is easy to see why this approach is not practical:
104: Radical Software Development tends to lead to different paradigms, as
105: required by the different applications. As it is, paradigms are locked up in
106: programming languages. As a result Radical Software Development
107: requires writing modules in several programming languages.
108:
109: \SubSection{A One-Language World}
110: Meanwhile, in the real world, companies are increasingly under pressure
111: to ``stick to their knitting''. For example, this means that a company
112: making telephone switches gets out of developing and maintaining its
113: own ideal programming language. Managers want to cut costs of training
114: new hires and insist on a widely used, standardized language. For
115: further economies, such a language should come with tools and multiple,
116: competing vendors. This explains why the world of programming has
117: become a one-language world, or at least has been trying to.
118:
119: It is not just managers who are opposed to multiple programming
120: languages. The Right Language tends to be an exotic one, and does not
121: sit well on the resume of the programmer who may soon need to look for
122: another job. Another problem with The Right Language is what we call
123: the \emph{Ninety-Percent Phenomenon}, which we will now explain by an
124: example.
125:
126: Suppose one finds that logic programming is the paradigm that makes the
127: application miraculously easy. At present, this means using Prolog. A
128: browse of the manual shows that ninety-percent of it is taken up by
129: matters that have nothing to do with \emph{logic} programming. This
130: ninety-percent is taken up with the mundane infrastructure that all
131: languages seem to require, regardless of paradigm: what characters are
132: allowed in names, what kind of numbers there are, how you write them,
133: strings, characters, I/O, and so on. To their credit, the designers of
134: {\tt C++} and Java have been careful to do this as much as possible as
135: it has been done in {\tt C}. In Prolog it has been done independently
136: of {\tt C}, or of any other language. As a result, Prolog does it
137: sometimes the way you guess it will do it, and sometimes not. Rather
138: time consuming, and frustrating.
139:
140: \Section{OO modelling of the paradigm}
141: In object-oriented programming (OOP) it is routine to model an
142: \emph{application} from the ground up in terms of objects.
143: In one widely used approach \cite{wbww90}, one notes the nouns and
144: the verbs of a description of the application in English. The nouns are
145: then considered as candidates for the classes, the verbs as candidates
146: for the methods.
147: If one can do this for transactions, invoices, customers,
148: $\ldots$, why not for the key concepts that make a particular
149: programming paradigm miraculously effective for the application?
150: In this
151: paper we argue that OOP can be used to do this for programming
152: \emph{paradigms}.
153:
154: Let us consider functional programming. In procedure-ori\-ent\-ed
155: languages, numbers are privileged in that one can (1) give them names,
156: (2) assign them to variables, and (3) return them as function results.
157: In these languages, functions are underprivileged in that they share
158: with numbers property (1), but not (2) and (3). The motivation for
159: functional programming languages is to accord to them all the
160: privileges of numbers, and thus make them ``first-class objects'', as
161: was the going terminology in functional programming \cite{sto77}.
162:
163: Thus it was apparently common to regard functions as objects before
164: 1977. It was only a matter of time to work out the consequences of this
165: view. In fact, it happened twenty years later in Friedman and
166: Felleisen's \emph{A Little Java, A Few Patterns} \cite{frfl97}.
167: However, it took the form of a cryptic one-page appendix.
168:
169: From this page, it is apparent that the absence of generics in Java
170: makes the modelling of higher-order functional programming a tiresome
171: exercise. To overcome this limitation, one could have followed {\tt
172: C++} and added templates. However, Wadler and Odersky judged the
173: Hindley-Milner type system, used in ML, as a superior alternative. They
174: extended Java to include this type system. This resulted languages such as Pizza
175: and GJava
176: \cite{drskwdlr97,bosw98} that directly allow higher-order functional
177: programming, without the need for object-oriented modelling in the
178: sense of this paper.
179: The Java extended in this way became the standard in 2004 under the name
180: ``Java 2 Platform, Standard Edition 5''.
181:
182: Pizza and GJava are examples of Multi-Paradigm Object Oriented
183: Programming Languages. Here the object-orienta\-tion of Java is used to
184: extend it to include another programming paradigm. Several other
185: projects in this direction were reported at MPOOL 2001 \cite{dvsmst01},
186: a workshop in conjunction with the ECOOP conference.
187:
188: As we explained, there is a strong tendency for one language to
189: dominate practical programming. Although a multi-para\-digm OO language
190: can be more elegant and powerful, it is unlikely to be accepted in
191: practice in the foreseeable future. It is therefore of interest to see
192: how far one can go in the direction of multiparadigm programming within
193: a programming language that is widely used in practice. In this paper
194: we show by worked examples in {\tt C++} that multi-paradigm
195: programming is not only possible, but can be quite simple and elegant.
196: To fit the paper's format, we need to restrict ourselves to
197: small paradigms. As we will see, dataflow and constraints are
198: small enough to exhibit as worked examples here.
199:
200: \Section{Dataflow programming}
201:
202: In the dataflow paradigm all computation happens in a network
203: consisting of nodes connected by unidirectional datapipes. Thus each
204: node has zero or more input pipes (when the output end of the pipe is
205: connected to the node), and zero or more output pipes (when the input
206: end of the pipe is connected to the node). A pipe is used by repeatedly
207: placing data items at its input end. These items can be retrieved from
208: its output end in the same order in which they entered at the opposite
209: end. Abstractly viewed, the pipes behave like the abstract data
210: structure referred to as a {\em queue}.
211:
212: The dataflow paradigm is justified by the class of problems that it
213: makes easy to solve. For example, such problems arise in business
214: process re-engineering. Such processes are naturally analyzed and
215: re-designed in terms of workflow \cite{jcktwd97}. The automation of
216: workflow then naturally translates to dataflow.
217:
218: An older method is Structured Systems Analysis (also called SADT, for
219: Structured Analysis and Design Technique), which was at one time widely
220: applied in commercial dataprocessing \cite{ganeSarson79}. However,
221: Structured Systems Analysis was a world unto itself, apparently not
222: aware of the larger context of dataflow programming. However,
223: Structured Systems Analysis was a world unto itself, apparently not
224: aware of the larger context of dataflow programming.
225:
226: Structured Systems Analysis discovered dataflow by inspired thinking
227: about commercial dataprocessing applications. Ashcroft and Wadge
228: \cite{ashcrWadge85} arrived at the idea starting from studies in
229: semantics of programming languages. Dennis, Arvind and others at MIT
230: have arrived at the dataflow paradigm from computer architecture
231: \cite{veen86}. Dataflow has been identified as a Software Architecture
232: \cite{shwgrln96}.
233:
234: As early as 1977 the paradigm was already sufficiently compelling that
235: a programming language was designed to make dataflow programming as
236: natural as possible \cite{kahnmcq77}. The paper just mentioned also
237: contains some simple and widely appealing examples showing the paradigm
238: at its best. Note that the paradigm was independently arrived at from
239: disparate areas: business applications, semantics, and architecture
240: (hardware and software). This suggests that it's ``real'' in some
241: sense.
242:
243: \SubSection{Hamming's problem solved in dataflow}
244: A good introduction to the dataflow paradigm is {\em Hamming's problem}
245: \cite{kahnmcq77}:
246: \begin{quote}
247: to print out in increasing order
248: all positive integers that have no prime factors other than
249: 2, 3, or 5.
250: \end{quote}
251: Thus, the sequence starts with 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15,
252: $\ldots$
253: This problem is attributed to R.W. Hamming by Dijkstra \cite{djk76},
254: who provided an ingenious solution. It is more efficient than, but is
255: not as easy to understand as, the dataflow version given by
256: Kahn and McQueen \cite{kahnmcq77}, which we follow here.
257:
258: One approach to a solution starts with the observation that the infinite
259: sequence $x$ of numbers required by Hamming's problem satisfies the
260: following equation:
261: $$ x = 1 \circ \mr(\mr(t_2(x),t_3(x)),t_5(x)) $$
262: where
263: \begin{itemize}
264: \item
265: the meaning of $\circ$ is defined by
266: $u \circ v$ being the result of prefixing the sequence $v$ by the
267: element $u$
268: \item
269: $\mr$ is the result of merging its two sorted input sequences
270: into a sorted output sequence, suppressing duplicates
271: \item
272: $t_2$ is result of multiplying by 2 its input sequence, element by
273: element; similarly for $t_3$ and $t_5$
274: \end{itemize}
275:
276: The question whether the solution to Hamming's problem is the {\em only}
277: solution to the equation is addressed by the methods developed in Kahn
278: \cite{kahn74}.
279:
280: To turn this observation into a dataflow network, we take the above
281: equation with a complex expression and turn it into a system of simple
282: equations by introducing auxiliary variables. We do this in two steps.
283: In the first step, we get rid of nested expressions:
284:
285: \begin{eqnarray*}
286: &&a = t_2(x_2) \;\;\;\; b = t_3(x_2) \;\;\;\; d = t_5(x_2) \\
287: &&c = \mr(a,b) \;\;\;\; x_1 = \mr(c,d) \\
288: &&x_2 = 1 \circ x_1
289: \end{eqnarray*}
290:
291: The resulting equations can, if considered in isolation, each be
292: translated directly into a node of a dataflow network. Each of $a$,
293: $b$, $c$, $d$, and $x_1$ correspond to a datapipe because, in the above
294: set of equations, they have exactly one occurrence in a left-hand side
295: and exactly one occurrence in a right-hand side. An occurrence on the
296: left-hand (right-hand) side corresponds to the output (input) side of
297: the datapipe.
298:
299: However, $x_2$ has too many occurrences in right-hand sides. We can
300: avoid this problem by making these occurrences into different
301: variables, say $f$, $g$, and $h$. But how do we tell that these are the
302: same sequence? To do that, we introduce a node type, with one input
303: and two output pipes, that outputs two identical copies of each item
304: that it removes from the input pipe. Let us call this node $\spl$.
305:
306: \begin{eqnarray*}
307: &&i = x_2 \;\;\;\; h = x_2\;\;\;\; f = i\;\;\;\; g = i \\
308: &&a = t_2(f) \;\;\;\; b = t_3(g)\;\;\;\; d = t_5(h) \\
309: &&c = \mr(a,b) \;\;\;\; x_1 = \mr(c,d) \\
310: &&x_2 = 1 \circ x_1
311: \end{eqnarray*}
312:
313: The entire top two lines each correspond each to a $\spl$ node;
314: the remaining six equations correspond to a node each. This makes eight
315: nodes in all. See the network diagram in Figure \ref{fig:network}.
316:
317: \begin{figure}[htbp]
318: \begin{center}
319: \epsfig{file=hamming_dataFlow.eps}
320: %\includegraphics{dataflow.pdf}
321: \end{center}
322: \caption{\label{fig:network} Dataflow network for Hamming's problem in
323: the initial state, where all pipes are empty except a 1 in {\tt x1}.}
324: \end{figure}
325:
326: \SubSection{An object-oriented implementation of Hamming's problem}
327: The most widely known principle of object-oriented modelling is to
328: consider the nouns of the specification as candidates for classes.
329:
330: In any dataflow network, particularly conspicuous nouns are {\em node}
331: and {\em datapipe}. As observed before, datapipes behave like queues,
332: a commonly used class.
333:
334: According to the principle just mentioned, we should consider a class
335: suitable for creating all required nodes as instances. The principle,
336: though a good first approximation, needs some refinement. This is
337: because objects of the same class should have states of the same form,
338: though not necessarily of the same content. The state of a node object
339: includes the states of the abutting datapipes. And of course, instances
340: of the same class should have the same behaviour.
341:
342: These considerations suggest that the $\mr$ nodes are instances of the
343: same class ({\tt merge}; the individual instances are {\tt m1} and {\tt
344: m2}), as are the $\spl$ nodes (of the class {\tt split}, with instances
345: {\tt sp1} and {\tt sp2}), as are the nodes $t_2$, $t_3$, and $t_5$ (of
346: the class {\tt times}, with instances {\tt t1}, {\tt t2}, and {\tt
347: t3}).
348:
349: \begin{figure}[htbp]
350: \begin{verbatim}
351: 01: int main() {
352: 02: const int MaxTimes = 50;
353: 03: queue a(10), b(10), c(10), d(10),
354: 04: x1(10), x2(10),
355: 05: f(10), g(10), h(10), i(10);
356: 06: merge m1(&a,&b,&c), m2(&c,&d,&x1);
357: 07: times t2(2,&f,&a), t3(3,&g,&b),
358: 08: t5(5,&h,&d);
359: 09: split sp1(&x2,&h,&i), sp2(&i,&f,&g);
360: 10: print p(&x1,&x2);
361: 11:
362: 12: node* ar[] = { &m1, &m2, &t2, &t3,
363: 13: &t5, &sp1, &sp2, &p };
364: 14: int arSz = sizeof(ar) / sizeof(node*);
365: 15:
366: 16: x1.add(1);
367: 17: for ( int i=0; i < MaxTimes; i++ )
368: 18: for ( int j=0; j < arSz; j++ )
369: 19: ar[j]->run();
370: 20: return 0;
371: 21: }
372: \end{verbatim}
373: \caption{\label{fig:dataFlowProg} {\tt C++} code for the dataflow network
374: for Hamming's problem. The node {\tt print} has been added to allow the
375: solution to be printed.}
376: \end{figure}
377:
378: Lines 3--5 create instances of class {\em queue} to act as datapipes,
379: each with a maximum size arbitrarily set at 10. Given these pipes,
380: lines 6--10 create the nodes, with the correct pipe connections.
381: \emph{These lines seem the most succinct possible textual
382: representation of the diagram in Figure~\ref{fig:network}. In so far
383: as this is true, $\cpp$ comes close to the best possible dataflow
384: programming language.}
385:
386: Lines 3--10 {\em create} the dataflow network; they do not cause it to
387: execute its computation. The attraction of the dataflow paradigm is
388: to avoid the difficulty of conventional programming, namely to ensure
389: that events happen in the right sequence. To execute a dataflow
390: network, each node executes, independently of the others, the following
391: simple computation:
392: \begin{quote}
393: \emph{If any of the input datapipes is empty, or if any of
394: the output datapipes is full, do nothing. Otherwise, remove the next
395: item from each of the input pipes, perform on them the specialized
396: computation characteristic for the type of node, and place the
397: results, if any, on the output pipes.
398: }
399: \end{quote}
400: The computation just described is invoked by a method called {\tt run},
401: which is defined for each of the classes {\tt merge}, {\tt times}, and
402: {\tt split}.
403:
404: To execute the entire network, one invokes the {\tt run} method for
405: each node, as in lines 18--19 of Figure~\ref{fig:dataFlowProg}.
406: Typically several of these
407: invocation have no effect because of full output or empty input pipes.
408: But if the network can do anything at all, then at least one node will
409: do something. In large networks it is worth optimizing the invocations
410: of the {\tt run} method. One can keep track of which nodes are
411: blocked. A blocked node connected to a pipe of which the content
412: changed may no longer be blocked and becomes a candidate for being {\tt
413: run}. Such an optimization is reminiscent of the constraint propagation
414: algorithm of D. Waltz \cite{wltz75}.
415:
416: Note that in lines 12--13 the nodes of the dataflow are placed into an
417: array. The order of the nodes in this array gives the order in which the
418: {\tt run} methods are called (line 19). However, this order does not
419: matter, since in dataflow the order in which things are done matters less
420: than it does in conventional programming.
421:
422: Space limitations prevent us from listing the entire program, which is
423: about a hundred lines, including the queue implementation. We just
424: add some representative code:
425: \begin{verbatim}
426: class node {
427: public:
428: virtual void run() = 0;
429: };
430:
431: class times : node {
432: private:
433: int mult; queue *in, *out;
434: public:
435: times(int Mult, queue *In,
436: queue *Out) {
437: mult = Mult;
438: in = In;
439: out = Out;
440: }
441: void run() {
442: if (in->empty()
443: || out->full())
444: return;
445: out->add(mult*(in->next()));
446: in->remove();
447: }
448: };
449: \end{verbatim}
450: An attractive characteristic of dataflow is that the nodes can run
451: concurrently subject to mutual exclusion on the datapipes.
452: We have considered doing this example in Java to make it easy to have
453: every instance of {\tt node} run in its own thread.
454: But although threads are simple to use, the result is still not as simple
455: as doing without. To find Hamming numbers, threads are not essential.
456: So we make our point better by showing a simpler program that just gets
457: the numbers.
458:
459: \Section{Constraint programming}
460:
461: Many problems in resource planning and numerical computation can be
462: solved in a \emph{declarative} way: one states the relations that are
463: to hold between the unknowns; a suitable solver then finds values such
464: that all relations are satisfied. The relations are referred to as
465: \emph{constraints}\/; the method is known as \emph{constraint
466: programming} \cite{mrrst98,jln01}.
467:
468: Constraint programming is useful because systems can be solved that
469: contain thousands of constraints. Here we will of course illustrate with
470: a very small example.
471:
472: \SubSection{Complex constraints}
473: A particular constraint programming method is \emph{interval
474: constraints}. Specific for interval constraints is that the unknowns
475: are real numbers and that their domains are intervals. As an example
476: consider the problem of finding the intersection points of the
477: circle $x^2+y^2=1$ and the parabola $y=x^2$. This means finding values
478: for $x$ and $y$ such that both relations are satisfied.
479:
480: Of course a student in secondary school will identify $y$ as
481: $(\surd 5 -1)/2$, and $x$ accordingly.
482: The point here is to develop a system that determines solutions
483: directly from the set of constraints as given,
484: for a wide class of constraints.
485:
486: Suppose that
487: initially all we know is that $x$ and $y$ are in $[-\infty,+\infty]$.
488: Considering each of the two given relations separately would already
489: remove some values for $x$ or $y$ from consideration. For example, it
490: is clear from the constraint $x^2+y^2=1$ that $x$ and $y$ have to be in
491: $[-1,+1]$. Whatever it is that allows us to reduce the original
492: intervals $[-\infty,+\infty]$ to $[-1,+1]$ we call a \emph{contraction
493: operator}. It is an operator associated with the constraint that allows
494: one to make such an inference. In constraint programming, one applies
495: in turn the contraction operators associated with the constraints until
496: no more contraction results. The remaining intervals for the variables
497: then give all information about the solutions of the problem that this
498: method can give.
499:
500: To make this method practical, contraction operators have to be widely
501: applicable and efficiently implementable. Such operators have only been
502: discovered for a relatively small repertoire of \emph{primitive}
503: constraints. These include constraints with binary relations such as $x
504: \leq y$, $x = y$, and $ y = x^2$. There are also constraints with
505: ternary relations such as $x+y=z$ and $x \times y = z$. The primitive
506: constraints do not include the constraint $x^2+y^2=1$, as it does not
507: occur sufficiently often to justify its presence in a general-purpose
508: solver. This complex constraint is therefore decomposed into primitive
509: constraints with the aid of auxiliary variables. In this way the
510: circle-and-parabola problem is expressed by the system \begin{equation}
511: \label{eq:diss} x^2=x_2, \: y^2=y_2, \: x_2+y_2=1, \: x_2=y
512: \end{equation}
513:
514: \SubSection{Contraction operators}
515: To introduce contraction operators, let us look at an example of one in
516: action: the one for primitive constraints of the form $x+y=z$. Such a
517: constraint expresses that the variables are in a ternary relation that
518: we call \emph{sum}. If it is known initially that $x$ and $y$ are in
519: $[0,2]$ and that $z$ is in $[3,5]$, then it is clear that neither $x$
520: nor $y$ can be near $0$ and that $z$ cannot be near $5$. In fact the
521: contraction operator reduces the intervals for $x$ and $y$ to $[1,2]$
522: and the one for $z$ to $[3,4]$.
523:
524: This is optimal and can be computed in a few floating-point
525: operations. One can solve complex systems of nonlinear equations and
526: inequalities by first reducing them to primitive constraints, and by
527: then applying contraction operators until nothing changes. Typically,
528: the remaining intervals are too large to be useful, in which case one
529: interval is split and the constraint propagation is repeated.
530:
531: \SubSection{OO modelling of interval constraints}
532: Let us now do a perfectly straightforward exercise in
533: object-oriented modelling in the spirit of \cite{wbww90}.
534: Clearly, ``constraint'' is an important noun, so justifies a class of
535: that name. The same holds for ``variable''. However, this is a
536: dangerously ambiguous concept: in programming languages, in logic, and
537: in calculus it means different things. The role of $x$ in the example
538: can be stated precisely: it is the name of a real number that we do not
539: know. Thus $x$ is an instance of a class of which the instances represent
540: real numbers. This suggests the following class definition:
541: \begin{verbatim}
542: class real {
543: private:
544: FLPT lb, ub;
545: public:
546: real();
547: real(FLPT lb, FLPT ub);
548: };
549: \end{verbatim}
550: {\tt FLPT} is a generic floating-point number type; it could be of
551: single or double length. The class {\tt real} is a classic example of
552: object-oriented modelling. It stands for an abstract concept, in this
553: case a real number. It hides the representation, which is the
554: description of a set of real numbers to which the real number belongs.
555: The set is restricted to the form of an interval {\tt [lb,ub]}, which
556: has the floating-point numbers {\tt lb} and {\tt ub} as lower and upper
557: bounds.
558:
559: In the case of real numbers this distinction between the abstract
560: concept, which is public, and its hidden representation is especially
561: valuable because most real numbers do not even have a finite
562: representation. So far, this perfectly ordinary piece of
563: object-oriented modelling has been, as far as we know, the only
564: practical way to directly compute with mathematical models involving
565: continuously varying quantities.
566:
567: The zero-argument constructor creates a real of which nothing is
568: known. Accordingly it is represented by the interval
569: $[-\infty,+\infty]$, which is the set of all real numbers. If more is
570: known about the real number, then it is represented by a smaller
571: interval. In our example we need the real numbers 1 and 0.5, which are
572: represented by the intervals only containing these numbers and are
573: created by the constructor calls \verb+real _1(1.0,1.0)+ and
574: \verb+real _0(0.5,0.5)+.
575:
576: To model constraints, we note that their indentity is determined both
577: by the relation and by the variables connected by the relation. Each
578: instance of a constraint needs to record the variables of that
579: instance. It is essential that different constraints be able to share
580: reals. This sharing is modelled by members that are pointers to
581: instances of class {\tt real}. The relation is represented by ensuring
582: that constraints are instances of the same class if, and only if, they
583: have the same relation. In this way the contraction operator for that
584: relation can be a method of that class. This method is named {\tt
585: shrinc}\footnote{ It is intended to shrink intervals. Moreover, the
586: class is part of a system called ``Sound High-Resolution Interval
587: Numeric Calculator''. }.
588: As all constraints need to go into the same container, and as they all
589: have a {\tt shrinc()} method, all constraint classes derive from an
590: abstract class named {\tt constraint}. These considerations are
591: embodied in the code in Figure~\ref{fig:headers}.
592:
593: \begin{figure}[htb]
594: \begin{verbatim}
595: class constraint {
596: public:
597: virtual bool shrinc() = 0;
598: virtual ~constraint {}
599: // Applies contraction operator.
600: // Returns false iff
601: // an empty interval results.
602: };
603: // constraint is x <= y
604: class leq: public constraint {
605: real *x, *y;
606: public:
607: leq(real *x, real *y);
608: bool shrinc();
609: };
610: // constraint is x == y
611: class eq: public constraint {
612: real *x, *y;
613: public:
614: eq(real *x, real *y);
615: bool shrinc();
616: };
617: // constraint is x+y = z
618: class sum: public constraint {
619: real *x, *y, *z;
620: public:
621: sum(real *x, real *y, real *z);
622: bool shrinc();
623: };
624: // constraint x^2=y
625: class square: public constraint {
626: real *x, *y;
627: public:
628: square(real *x, real *y);
629: bool shrinc();
630: };
631: \end{verbatim}
632: \caption{\label{fig:headers}
633: Definitions for the {\tt constraint} classes.
634: }
635: \end{figure}
636:
637: Now that we have the interface with the interval constraint machinery,
638: let us use it to express the system (\ref{eq:diss}) for the
639: circle-and-parabola problem; see Figure~\ref{fig:propCode}.
640:
641: \begin{figure}[htb]
642: \begin{verbatim}
643: 00: int main () {
644: 01: //solve {x^2=x2, y^2=y2, x2+y2=1, y=x2}
645: 02: //create variables:
646: 03: real x, y, x2, y2, _1(1.0,1.0);
647: 04: //real _0(0.5,0.5);
648: 05:
649: 06: //create constraint system:
650: 07: constraint* array[] = {
651: 08: new square(&x,&x2), new square(&y,&y2),
652: 09: new sum(&x2,&y2,&_1), new eq(&y,&x2)
653: 10: //, new leq(&_0,&x)
654: 11: };
655: 12: //propagate:
656: 13: const int MAX = 1000;
657: 14: int size =
658: sizeof(array)/sizeof(constraint*);
659: 15: for (int i=0; i < MAX; i++)
660: 16: for (int j=0; j < size; j++)
661: 17: array[j].shrinc();
662: 18: cout << "x: " << x << endl;
663: 19: cout << "y: " << y << endl;
664: 20: for (int j=0; j < size; j++)
665: 21: delete array[j];
666: 22: }
667: \end{verbatim}
668: \caption{ \label{fig:propCode}
669: $\cpp$ code for finding the intersection of a circle with a parabola
670: using the interval constraints method.}
671: \end{figure}
672:
673: In line 3 the variables of system (\ref{eq:diss}) are created.
674: Lines 7 through 11 create the constraints of this system
675: and place them in a container. At the same time, this specifies
676: the interconnections of the constraints via the shared variables.
677:
678: After the constraint system has been built, contraction operators are
679: applied. This is done in a simplistic way in lines 13 through
680: 18. In actual practice, it is done by means of a constraint
681: propagation algorithm. These algorithms have a long and interesting
682: history; see \cite{aptEssence} for recent contributions and a history.
683:
684: The result of the propagation is printed on lines 18
685: and 19 with the result: $x \in [-1,1]$ and $y \in [0,1]$.
686: This result is large enough to contain both
687: solutions to (\ref{eq:diss}). If one is interested in one solution,
688: say, with
689: positive $x$, then one can add a constraint as in line 10, using a
690: constant created as in line 4.
691: In that case there is one solution, enclosed in a narrow interval:
692: \begin{eqnarray*}
693: x \in [\overline{0.78615137775742}29,\overline{0.78615137775742}36] \\
694: y \in [\overline{0.61803398874989}44,\overline{0.61803398874989}54].
695: \end{eqnarray*}
696:
697: We include this example because we believe
698: that it shows that a special-purpose constraint programming language
699: would not be able to specify the system (\ref{eq:diss})
700: in a clearer or more succinct way.
701: At the same time,
702: a special-purpose language
703: would probably not have any original insights
704: on how to do containers, nor on how to do control primitives,
705: so that these aspects of the program would be the same
706: or gratuitously different.
707: Hence, this straightforward exercise
708: in object-oriented modelling of constraint programming
709: is probably as well as one can do in the form of text.
710:
711: \Section{Object-oriented frameworks}
712:
713: The foregoing examples suggest that a distinctive programming paradigm
714: need not have a language of its own. It is adequately supported
715: by a suitable class library.
716: Both our examples include an abstract class and a generic algorithm
717: expressed in terms of that class. Programming in the paradigm requires
718: one to define derived class suitable to the application. In our
719: dataflow example, each type of node and its specific activity becomes
720: a class derived from {\tt node}.
721: Similarly, in the constraint example, each type of constraint and its
722: specific contraction operator becomes a class derived from {\tt
723: constraint}.
724:
725: But the library, with its abstract classes and generic algorithms is
726: not enough. If it indeed embodies a distinctive programming paradigm,
727: it comes with a view of how to do things, a mindset. This can be
728: expressed by a set of tutorial examples. The collection of these things
729: is what is called a \emph{framework} by Gamma, Helm, Johnson, and
730: Vlissides \cite{ghjv94}.
731:
732: The trend towards frameworks rather than dedicated programming languages
733: may have started with Puget's approach to constraint programming.
734: At first, constraint programming followed the conventional route with a
735: dedicated programming language. It grew out of logic programming, which
736: had Prolog as dedicated programming language.
737: Accordingly, constraint programming was implemented in various dialects
738: of Prolog: Prolog II and III, CHIP and its descendants, BNR Prolog,
739: and Prolog IV. However, Puget adopted Saraswat's comprehensive view of
740: constraint programming \cite{srswt93} called
741: \emph{Concurrent Constraint Programming}, dropped the concurrency,
742: and based a {\tt C++} class library on it \cite{pgt94,pgtlcnt95}.
743:
744: Design Patterns and object-oriented frameworks seemd equally promising when these
745: ideas first arose.
746: Design patterns found wide acceptance. However, to quote Erich Gamma
747: \cite{gmm02}
748: \begin{quote}
749: When we wrote ``Design Patterns''
750: we were excited about frameworks
751: and forecast that there would be lots of them in the near future.
752: Time has shown, however, that frameworks aren't for everyone.
753: Developing a good framework is hard
754: and requires a large up-front investment that doesn't always pay off.
755: \end{quote}
756: Originally, frameworks were intended to help specific applications,
757: such as graphical user interfaces or document processing.
758: Like design patterns, object-oriented frameworks
759: are defined as systems of customizable co-operating classes.
760: What one obtains as a result of modelling a programming paradigm
761: also answers to this description, but is not a design pattern.
762: Instead, it is useful as a new way of discovering
763: useful systems of customizable co-operating classes.
764:
765: One of the most important advantages of design patterns
766: is as an aid to documentation:
767: just because the pattern has a name,
768: the use of this name in the documentation
769: speeds up understanding of the part of the code concerned.
770: The object-oriented frameworks arising from programming paradigms
771: have this same advantage.
772:
773: \Section{Conclusions}
774:
775: So far there has been little scope in practice for the Whitehead
776: effect to ease software development. Applying the paradigm that's
777: right for the application seemed to require switching to a different
778: programming language. Practical concerns necessitate sticking to a
779: single language.
780:
781: This situation has changed since the single language is
782: object-oriented. Programming paradigms such as dataflow or
783: constraints, which once were thought to need a dedicated language, are
784: easily modelled in an object-oriented language. In fact, as easily as
785: the textbook example of object-oriented modelling of simple
786: applications. Thus it is not overly ambitious to model the ideal
787: programming paradigm, rather than the application.
788: This modelling typically takes the form of an OO framework.
789:
790: In this we can distinguish between minor and major paradigms. The minor
791: ones are those that can be modelled in one of the few languages most
792: widely accepted in industry. We saw that dataflow and constraint
793: programming fit in this category. J\"arvi and Powell \cite{jrpw01}
794: implement partial function application in this way in {\tt C++}. The
795: fact that functional programming can be characterized by functions
796: being first-class objects, suggests that functional programming is no
797: harder to do. It has turned out that it is and that it seems to require
798: a new programming language. Apparently, functional programming is a
799: major paradigm. However, even in this case OO programming has made a
800: difference. The new language turned out to be an extension of Java that
801: was needed anyway, independently of functional programming.
802:
803: The question remains whether logic programming, so far sequestered in
804: Prolog and other dedicated languages, is a major paradigm requiring a
805: language extension or a minor one that can easily be modelled in an
806: existing OO language. The work of combining Smalltalk with logic
807: programming by symbiotic reflection \cite{wtsdcs01} seems to transcend the
808: simplistic criterion used to distinguish between minor and major
809: paradigms.
810:
811: It used to be that not only paradigms, but certain applications got
812: their own programming languages. We have argued that this is something
813: of the past. It was even the case that one application, namely
814: simulation, had several languages devoted to it. One of these was
815: Simula, and the rest is history.
816:
817: %\bibliographystyle{plain}
818: %\bibliography{article,book,collection,proceedings,techreport,thesis,unpublished}
819: %\bibliography{cs}
820:
821: \begin{thebibliography}{10}
822:
823: \bibitem{aptEssence}
824: K.R. Apt.
825: \newblock The essence of constraint propagation.
826: \newblock {\em Theoretical Computer Science}, 221(1-2):179--210, 1999.
827:
828: \bibitem{bosw98}
829: Gilad Bracha, Martin Odersky, David Stoutamire, and Philip Wadler.
830: \newblock Making the future safe for the past: Adding genericity to the {J}ava
831: programming language.
832: \newblock In {\em OOPSLA 98}, 1998.
833:
834: \bibitem{dvsmst01}
835: Kei Davis, Yannis Smaragdakis, and J\"org Striegnitz, editors.
836: \newblock {\em Multiparadigm Programming with Object-Oriented Languages}. John
837: van Neumann Institute for Computing, 2001.
838: \newblock ISBN 3-00-007968-8.
839:
840: \bibitem{djk76}
841: E.W. Dijkstra.
842: \newblock {\em A Discipline of Programming}.
843: \newblock Prentice Hall, 1976.
844:
845: \bibitem{frfl97}
846: Matthias Felleisen and Daniel~P. Friedman.
847: \newblock {\em A Little Java, a Few Patterns}.
848: \newblock MIT Press, 1997.
849:
850: \bibitem{gmm02}
851: Erich Gamma.
852: \newblock Design patterns --- ten years later.
853: \newblock In Manfred Broy and Ernest Denert, editors, {\em Software Pioneers},
854: pages 688--700. Springer-Verlag, 2002.
855:
856: \bibitem{ghjv94}
857: Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
858: \newblock {\em Design Patterns}.
859: \newblock Addison-Wesley, 1994.
860:
861: \bibitem{ganeSarson79}
862: Chris Gane and Trish Sarson.
863: \newblock {\em Structured Systems Analysis}.
864: \newblock Prentice-Hall, 1979.
865:
866: \bibitem{jcktwd97}
867: Michael Jackson and Graham Twaddle.
868: \newblock {\em Business Process Implementation: Building Workflow Systems}.
869: \newblock Addison-Wesley, 1997.
870:
871: \bibitem{jrpw01}
872: J.~J\"arvi and G.~Powell.
873: \newblock Side effects and partial function application in {C}++.
874: \newblock In Kei Davis, Yannis Smaragdakis, and J\"org Striegnitz, editors,
875: {\em Multiparadigm Programming with Object-Oriented Languages Workshop},
876: pages 43--60, Budapest, Hungary, June 2001.
877:
878: \bibitem{jln01}
879: Luc Jaulin, Michel Kieffer, Olivier Didrit, and \'Eric Walter.
880: \newblock {\em Applied Interval Analysis}.
881: \newblock Springer-Verlag, 2001.
882:
883: \bibitem{kahn74}
884: Gilles Kahn.
885: \newblock The semantics of a simple language for parallel processing.
886: \newblock In {\em Information Processing 74}. North Holland, 1974.
887: \newblock Proceeding of the {IFIP} Congress.
888:
889: \bibitem{kahnmcq77}
890: Gilles Kahn and David~B. MacQueen.
891: \newblock Coroutines and networks of parallel processes.
892: \newblock In B.~Gilchrist, editor, {\em Information Processing 77}. North
893: Holland, 1977.
894: \newblock Proceeding of the {IFIP} Congress.
895:
896: \bibitem{mrrst98}
897: Kim Marriott and Peter~J. Stuckey.
898: \newblock {\em Programming With Constraints : An Introduction}.
899: \newblock The MIT Press, 1998.
900:
901: \bibitem{drskwdlr97}
902: Martin Odersky and Philip Wadler.
903: \newblock {P}izza into {J}ava: Translating theory into practice.
904: \newblock In {\em Proc. 24th {ACM} Symposium on Principles of Programming
905: Languages (POPL)}, 1997.
906:
907: \bibitem{pgt94}
908: Jean-Fran\c{c}ois Puget.
909: \newblock A {C}++ implementation of {CLP}.
910: \newblock In {\em SPICIS94}, 1994.
911:
912: \bibitem{pgtlcnt95}
913: Jean-Fran\c{c}ois Puget and Michel Leconte.
914: \newblock Beyond the glass box: Constraints as objects.
915: \newblock In {\em Proc. Int. Logic Programming Symposium}. MIT Press, 1995.
916:
917: \bibitem{srswt93}
918: Vijay~A. Saraswat.
919: \newblock {\em Concurrent Constraint Programming}.
920: \newblock MIT Press, 1993.
921:
922: \bibitem{shwgrln96}
923: Mary Shaw and David Garlan.
924: \newblock {\em Software Architecture: Perspectives on an Emerging Discipline}.
925: \newblock Prentice-Hall, 1996.
926:
927: \bibitem{sto77}
928: Joseph~E. Stoy.
929: \newblock {\em Denotational Semantics: The Scott-Strachey approach to
930: Programming Language Theory}.
931: \newblock MIT Press, 1977.
932:
933: \bibitem{veen86}
934: A.H. Veen.
935: \newblock Dataflow machine architecture.
936: \newblock {\em Computing Surveys}, pages 365--396, 1986.
937:
938: \bibitem{ashcrWadge85}
939: William~W. Wadge and Edward~A. Ashcroft.
940: \newblock {\em Lucid, the Dataflow Language}.
941: \newblock Academic Press, 1985.
942:
943: \bibitem{wltz75}
944: D.~Waltz.
945: \newblock Understanding line drawings in scenes with shadows.
946: \newblock In Patrick~Henry Winston, editor, {\em The Psychology of Computer
947: Vision}, pages 19--91. McGraw-Hill, 1975.
948:
949: \bibitem{wbww90}
950: Rebecca Wirfs-Brock, Brian Wilkerson, and Lauren Wiener.
951: \newblock {\em Designing Object-Oriented Software}.
952: \newblock Prentice-Hall, 1990.
953:
954: \bibitem{wtsdcs01}
955: Roel Wuyts and St\'ephane Ducasse.
956: \newblock Symbiotic reflection between and object-oriented and a logic
957: programming language.
958: \newblock In Kei Davis, Yannis Smaragdakis, and J\"org Striegnitz, editors,
959: {\em Multiparadigm Programming with Object-Oriented Languages Workshop},
960: pages 81--96, Budapest, Hungary, June 2001.
961:
962: \end{thebibliography}
963:
964: \end{document}
965: