|
Imperative programming:
a programming style that uses explicit
- mutable state (mutable variables) and
- control flow (goto, for-loops, branches, etc.).
Conceptually, you perform a computation by changing the state of
the computer.
A procedural language adds functions and procedures on top of this
foundation, and then you get C and Pascal.
For example, here's an imperative function to find the factorial of an
integer:
define function factorial
(n :: <integer>)
=> (n! :: <integer>)
let n! :: <integer>= 1;
while (n >0)
n! := n! * n;
n := n - 1;
end while;
//
n! // return n!
end function factorial;
Functional programming
A programming style that emphasizes an "equational" approach is
taken:
- instead of changing the state of a machine, a program is defined
as the solution to a set of functions.
- in order for mathematical laws to hold, in particular that
a = b => f(a) == f(b)
- mutable state and explicit control flow are avoided.
(For example, if there were mutable global variables referenced
in f, then there would be no guarantee that one call to f(3) would
have the same value as another call f(3).)
The usual definitions of functional programming are also that
- functions should be first-class.
In other words that they can be passed as arguments and created
and returned as values. (Both Smalltalk's blocks and Dylan's
methods are first-class functions.)
For example, you might define factorial as:
define function factorial
(n :: <integer>)
=> (n! :: <integer>)
if (n = 0)
1
else
n * factorial(n - 1)
end if;
end function factorial;
taking the definition of factorial straight from the mathematical
definition.
Object-oriented Programming (OOP)
A style of programming that emphasizes two concepts.
- First, the idea of subtyping:
--- values can belong to more than one type.
- Second the idea of dynamic dispatch
--- a method is selected based on the most specific type of the
arguments.
For example, here's an OO factorial:
define constant <zero> = singleton(0);
// The type <zero> contains only the
// int 0, so <zero> subtypes <integer>.
define method factorial (n :: <zero>)
=> (n! :: <integer>)
// in case of type <zero> return
1
end method factorial;
define method factorial (n :: <integer>)
=> (n! :: <integer>)
// in case of type <integer> which excludes
// the zero return
n * factorial(n - 1)
end method factorial;
We still haven’t handled all the cases of possible argument values. If
the argument is a negative, factorial has been asked to do an
impossible job. We can create a type that consists of a limited
range of integer values and use that to provide a behavior for the
rest of the cases
define method factorial (
n:: limited(<integer>, max: -1))
error ( “facorial: Bad argument“, n )
end method factorial
Note that the factorial method chosen for an argument depends on
the value passed to the function factorial.
The way that Dylan's OO is different from Smalltalk is the way
of selcting a method
- In Smalltalk selecting the method based only on the first
receiver (message-passing OO),
- Dylan selects a method based on *all* of the arguments
(multimethod dispatch OO).
We need two or more arguments to demonstrate multimethods,
and this post has gotten long enough, so I'll leave that for
another day.
|