[comp.lang.misc] Functional and Object Oriented Languages compared

budd@mist.CS.ORST.EDU (Tim Budd) (06/15/89)

On the surface, functional programming as in ML and object oriented
programming as in Smalltalk or C++ often seem to be emphasizing different
sides of the same coin.  Let me give a specific example.  Suppose we want
to talk about vehicles as a general category, with specific examples being
cars, trucks and bikes.   Furthermore, we need a function to compute
the weights of such things.  In ML (footnote (1)) we define a union type, 
and a function, as in:

datatype VEHICLE = Car of kind * weight | Truck of weight * kind | Bike;
fun 	weight(Car(_, w)) = w
	| weight(Truck(w,_)) = w
	| weight Bike = 15;

In OOPLS (generic object oriented programming languages) we define a
class Vehicle with subclasses Car, Truck and Bike, and a function weight in 
each.  Now in either case given an instance of a vehicle we can compute its 
weight.  ML chooses to group around functions, while OOPLS group around
classes, but it would seem that the same behavior is available in both. (2)

EXCEPT - there is one very important facility that we can use in functional
languages that we seem not to have available in OOPLS.  Suppose we have
an array of vehicles, and a functional sum that takes a plus reduction of
an array using a user supplied function on each element of the array.
We can compute the sum of the weights of the vehicles using something
like  ``sum (vehiclearray, weight)''.  Since message selectors, such as
``weight'' are not first class entities in OOPLS, there does not seem to
be any similar technique that can be used.  (Before someone else mentions
it, yes I know we could use 
``vehiclearray inject: 0 into: [:x :y | x + y weight]'' in smalltalk, 
but this doesn't seem quite the same and my point that message selectors
are not first class is still valid).

So, the topic for debate today is the question whether method selectors,
such as ``weight'', which are implemented in several classes, should
be considered to be first class objects in their own right.  That is,
should we be able to pass ``weight'' as an argument to another function?
Should be various ``weight'' functions, although implemented in different
classes, be considered to be part of a single entity?
If the answer is yes, what is a reasonable way that this can be implemented?
(3)

footnotes
(1) syntax may not be exactly right, I hope ideas are, however.
(2) given this superficial analysis, there would been to be a slight
efficiency advantage of OOPLS over ML.  OOPLS can select the appropriate
function to execute using a single index into a table (the vtable trick),
but ML seems to require a more general pattern matching facility.
Does anybody have a reference to how exactly ML like languages go about
selecting the right function to execute?  That is, what the code
generated actually looks like?  The best I can see looks like nested
if then else statements.
(3) I have my own ideas, involving stub functions generated on the fly,
but would be interested in seeing if anybody else comes up with something
better.

new@udel.EDU (Darren New) (06/15/89)

In article <11213@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
>On the surface, functional programming as in ML and object oriented
>programming as in Smalltalk or C++ often seem to be emphasizing different
>sides of the same coin.  
>In ML (footnote (1)) we define a union type, 
>and a function, as in:
>
>datatype VEHICLE = Car of kind * weight | Truck of weight * kind | Bike;
>fun 	weight(Car(_, w)) = w
>	| weight(Truck(w,_)) = w
>	| weight Bike = 15;
>
>In OOPLS (generic object oriented programming languages) we define a
>class Vehicle with subclasses Car, Truck and Bike, and a function weight in 
>each.  Now in either case given an instance of a vehicle we can compute its 
>weight.  ML chooses to group around functions, while OOPLS group around
>classes, but it would seem that the same behavior is available in both. (2)

Certainly. The difference is in the organization. In ML, if I add a new
type (say, boat), I must find all functions that boat uses and change them.
In complex cases this could break much code (if you are careless).
In Smalltalk, I add the new class and then I must define in that class all 
functions (messages) which I want to use (like weight, size, speed, ...).
In either case, I can forget to change something and when that function
is used with the new object I will get an error. In truth, these
are different sides of the coin. Both languages have types and functions.
In ML, functions talk about types and in ST types talk about functions.

>EXCEPT - there is one very important facility that we can use in functional
>languages that we seem not to have available in OOPLS.  Suppose we have
>an array of vehicles, and a functional sum that takes a plus reduction of
>an array using a user supplied function on each element of the array.
>We can compute the sum of the weights of the vehicles using something
>like  ``sum (vehiclearray, weight)''.  Since message selectors, such as
>``weight'' are not first class entities in OOPLS, there does not seem to
>be any similar technique that can be used.  (Before someone else mentions
>it, yes I know we could use 
>``vehiclearray inject: 0 into: [:x :y | x + y weight]'' in smalltalk, 
>but this doesn't seem quite the same and my point that message selectors
>are not first class is still valid).

This is exactly how the plus-reduction would be done. The '+' symbol above
represents not a particular method but rather a message (function name,
rather than function body). Also, the 'weight' symbol represents a message
and not a method. In both cases, the method (body) used for the function
call is looked up by the interpreter based on the class (type) of x or
y respectively.  The inject:into: message is used precisely for doing this.
In the above paragraph, the ``sum (vehiclearray, weight)'' line seems
to be a function call, whereas the inject:into: would be equivalent
to the body of the function sum.  Maybe this is your confusion?
These two seem the same to me except for the coding of the weight function
itself.

>So, the topic for debate today is the question whether method selectors,
>such as ``weight'', which are implemented in several classes, should
>be considered to be first class objects in their own right.  That is,
>should we be able to pass ``weight'' as an argument to another function?
>Should be various ``weight'' functions, although implemented in different
>classes, be considered to be part of a single entity?
>If the answer is yes, what is a reasonable way that this can be implemented?

Again, I think you are confusing the issue by trying to force smalltalk into
the ML mold. You seem to be confused, in particular, about the difference
between messages and methods: a message plus a class -> a method. Thus,
speaking of "various weight functions" is confusing. It is either the
weight message, which returns the weight of the object to which it is
sent, or it is the weight method of the bike class, which returns 15.
The methods are different entities, and the message is the means by which
a method of a particular class is accessed and invoked. In terms of
being able to pass "weight" as an argument itself, to define your sum function,
you could say (this is off-hand, so no flames if wrong...):

plusRed: aSymbol
"This is in class Array"
| i |
i _ 0.
self do: [: j | i _ i + (j perform: aSymbol)].
^ i

Thu, the call "sum(vehiclearray, weight)" would become
vehiclearray plusRed: #weight.

This seems pretty first-class to me.  Note that in Smalltalk, methods as
well as messages are first-class. (Actually, messages are not objects
at all, but the names of messages are first-class (symbols) and going
from the name to the message is done via perform:).

Hope this clarifies. The point of OOPLs is to separate everything that
a bike does from everything that a car does. Thus, weight gets split
up instead of put all in one function. This makes it easy to reuse
bike code in some other program without dragging along cars, trucks,
boats, etc.  In ML, it would be tedious to pull all that apart, I suspect.

Note that little if any of this holds true for C++, as C++ does not have
dynamic binding except for an extra level of indirection when virtual
functions are used. The "object oriented" part of C++ could quite
easily be done by hand while coding. However, it is still OO in the 
sense of the previous paragraph.
      
			       - Darren New
				 UDel's Smalltalk Programmer
				 (Amongst several???)

alan@oz.nm.paradyne.com (Alan Lovejoy) (06/16/89)

In article <11213@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
>So, the topic for debate today is the question whether method selectors,
>such as ``weight'', which are implemented in several classes, should
>be considered to be first class objects in their own right.  That is,
>should we be able to pass ``weight'' as an argument to another function?
>Should be various ``weight'' functions, although implemented in different
>classes, be considered to be part of a single entity?

1) You have raised an important topic of discussion.
2) The fact that messages are not first class objects in Smalltalk and
   other OOPLs does impair the functionality of those languages.  I have
   been aware of this problem for many years.
3) A related problem is that there is a fundamental discrepancy between
   the semantics and usage protocol of the "first argument" of a message
   (which is the receiver of the message) and any subsequent arguments:

     a.  The method that will be executed in response to a message is 
	 determined by the class of the first argument, but not by the
	 class of any subsequent arguments.  Hence, associative expressions
	 are not directly supported in mixed-type expressions (they have to
	 be kludged-in using some device such as double dispatching).
     b.  The code of the executed method can not know or depend on the class 
	 of the subesequent arguments.  But it very definitely can (and 
	 very probably will) depend on the class of the receiver or "first"
	 argument.
     c.  Since method code may depend upon the class of the receiver (i.e.,
	 source code that is valid if the class of the receiver is A may
	 not be valid if the class of the receiver is not A), it is not 
	 possible to safely create procedure (method) abstractions that
	 are independent of the class of any and all arguments (including
	 the "first argument" or receiver).

   Smalltalk compensates for this situation to some degree by making all
   classes subclasses of Class Object.  Methods defined in class Object 
   can provide most of the desired functionality.  But this device is not
   the most elegant of solutions.

   Another solution to the problem is to make the syntax for reading and
   writing state (i.e., instance variables) the same as the syntax for
   evaluating functions (oh, I guess I mean sending messages :-) :-)).
   For example, if class RgbColor has the instance variables 'red', 'green'
   and 'blue,' then the syntax for reading the value of the instance
   variable 'red' should be "self red" instead of just "red" (the latter
   being the current syntax).  Similarly, the syntax for setting the value
   of the instance variable blue should be "self blue: 0.5" instead of
   "blue <- 0.5" (again, the latter being the current syntax).  Given this
   change in syntax, it becomes possible to write instance method code
   in a more class-independent way.  For instance, the method 'initialize'
   in the class AbstractColor (the superclass of RgbColor) can now be
   written as:

   initialize
     "Initialize a color to black."

     self red: 0.0.
     self green: 0.0.
     self blue: 0.0.
     ^self

   Written this way, it does not matter whether or not "self red: 0.0" is a 
   message send to an object whose class does not have the instance variable
   'red.'  So the method will be valid for the other subclass of 
   AbstractColor--HsiColor--which has the instance variables 'hue,' 
   'saturation' and 'intensity' instead of 'red,' 'green' and 'blue' 
   (provided, of course that the appropriate methods 'red:', 'green:' and
   'blue:' have been defined in HsiColor).  Because the same source code
   for the 'initialize' func...uh, method can now be valid for all subclasses 
   of AbstractColor, the method can be defined once in AbstractColor instead
   of in each subclass.

4) If messages were first class values, then one could write code such as
   the following:

     | aMessage aPoint |
     aMessage <- Message for: (x: 0 y: 0).
     aPoint <- Point aMessage.

   The problem with the above is syntactical:  how can the compiler tell
   that "Point aMessage" means "send the message 'x: 0 y: 0' to Point" 
   and not "send the message 'aMessage' to Point"?  There are only two
   solutions to this problem.  Smalltalk uses one of them:  the syntax for 
   sending messages whose value is determined statically at compile time
   and for sending messages whose value is determined dynamically at run
   time is completely different.  For example, the "correct" way to code what
   is intended in the example above is:

     | aMessage anArgumentList aPoint |
     aMessage <- #x:y:.
     anArgumentList <- #(0 0).
     aPoint <- Point perform: aMessage with: anArgumentList.

   The problem with this is that the code is not independent of whether
   or not the message to be sent is static or dynamic.  Therefore, it is
   impossible to abstract over the code with regard to the property of
   static or dynamic message values.  But this is due to the syntax of
   Smalltalk.  It has nothing to do with the inherent properties of OOPLs.
   So the other (better) solution to the problem is to create OOPLs whose
   syntax for sending statically and dynamically determined message values
   is identical.

Alan Lovejoy; alan@pdn; 813-530-2211; AT&T Paradyne: 8550 Ulmerton, Largo, FL.
Disclaimer: I do not speak for AT&T Paradyne.  They do not speak for me. 
______________________________Down with Li Peng!________________________________
Motto: If nanomachines will be able to reconstruct you, YOU AREN'T DEAD YET.

cliff@ficc.uu.net (cliff click) (06/20/89)

In article <6192@pdn.paradyne.com>, alan@oz.nm.paradyne.com (Alan Lovejoy) writes:
> 4) If messages were first class values, then one could write code such as
>    the following:
> 
>      | aMessage aPoint |
>      aMessage <- Message for: (x: 0 y: 0).
>      aPoint <- Point aMessage.
> 
>    The problem with the above is syntactical:  how can the compiler tell
>    that "Point aMessage" means "send the message 'x: 0 y: 0' to Point" 
>    and not "send the message 'aMessage' to Point"?  There are only two
>    solutions to this problem.  Smalltalk uses one of them:  the syntax for 
>    sending messages whose value is determined statically at compile time
>    and for sending messages whose value is determined dynamically at run
>    time is completely different.  

>    So the other (better) solution to the problem is to create OOPLs whose
>    syntax for sending statically and dynamically determined message values
>    is identical.

In the above example "aMessage" is a temporary variable.  The compiler will
generate code to send the contents of the "aMessage" temp as a message to
"Point".  When the interpreter looks up the message in the methods of 
"Point" perhaps it should recognize that the message being passed is itself
a message - in other words do the "perform:with:" inherently in the 
interpreter, and leave the compiler alone.  

i
n
e
w
s

f
o
d
d
e
r
-- 
Cliff Click, Software Contractor at Large
Business: uunet.uu.net!ficc!cliff, cliff@ficc.uu.net, +1 713 274 5368 (w).
Disclaimer: lost in the vortices of nilspace...       +1 713 568 3460 (h).

edwin@cwi.nl (Edwin Blake) (06/21/89)

I am interested in abstractions for computer graphics, particularly
dynamic graphics such as animation, interactive systems and CAD.  It
seems to me that the leading contenders for an abstraction for computer
graphics are the declarative languages and object oriented (o-o)
languages.  I am reasonably familiar with o-o abstraction, less so with
the functional/logic one, but lets have some reactions!

Functional programming has been used for computer graphics [Arya, 1986,
1989; Henderson, 1982; Salmon & Slater 1987].  (There are so many
references for o-o graphics that I will not be giving any!?! -- they can
be had on request.  I would be interested in further references to PURE
functional graphics.)

From the point of view of the graphics programmer an important benefit
of declarative languages is that they shift the burden of deciding how a
thing has to be done from the programmer to the architecture.
Constraint based o-o programming also has a declarative flavour in this
sense.  Both FUNCTIONAL and LOGIC languages are declarative.  The need
for declarative programming in animation and interaction has long been
recognized [see e.g. Borning & Duisberg, 1986; Zeltzer, 1985]

Pure declarative languages employ no side-effects whatsoever and
assignment of values to variables is impossible.  In object oriented
terms one could say that data is always completely encapsulated.  In
fact, declarative languages lack a notion of `state of computation'.
This is in direct opposition to the idea of self contained objects which
persist over time while their internal configuration changes.  This
seems to lead to CONCEPTUAL difficulties when we consider interactive
graphics and computer animation.

Functional programming derives its power from giving functions first
class status.  Data structures are defined by means of constructor
functions which make abstract data objects.  Access is only via the
operations defined on the data objects.  As in o-o functional
programming also emphasizes polymorphism and concurrency.

Pure functional programs are static objects.  The meaning of an
expression does not change as computation proceeds.  But real, physical,
objects persist while their configurations and attributes change over
time.  Animation, as the mimicking of three-dimensional physical
objects, depends on a notion of STATE.  This meshes rather well with the
concept of actors and objects in object oriented programming.  In
functional graphics the emphasis is shifted to dealing with a sequence
of DIFFERENT objects related by a sequence of transformations.  This
model of computation is found in key frame animation, which is mainly
used for two-dimensional pictures.

Slater also discusses the fact that difficulties arise when using
functional languages for programming interaction and when using
attributes [Salmon & Slater, 1987, pp. 290-291]. 

This does not prevent functional programming from being used in practice
in time dependent situations.  Generally it is possible to ABSTRACT AWAY
the notion of time, and replace it with some idea of sequences over
infinite lists.  Recent developments in lazy functional evaluation make
such infinite lists tractable.

To discover the relation between the figures in the list one refers to
the functions which constructed them.  BUT the conceptual advantages of
functional programs remain limited precisely because such programs
describe a dynamically changing world as a (conceptually) frozen system
of infinite sequences.

The extent to which a (possibly impure) functional approach can be
elaborated for three-dimensional animation needs further investigation.
On the other hand, object oriented animation already seems well suited
to modelling changing objects executing concurrently.


References.
===========
Arya, K.  (1986)  Computer Graphics Forum  vol 5, 4  297-311
"A functional approach to animation."

Borning, A.H. & Duisberg, R.A.  (1986)  ACM Trans.Graphics  vol 5, 4  345-374
"Constraint-based tools for building user interfaces."

Henderson, P.  (1982)  Symposium on Lisp & Functional Programming.  9pp
"Functional geometry."

Salmon, R. & Slater, M.  (1987) Computer Graphics: Systems & Concepts.
Addison-Wesley, Wokingham, England.

Zeltzer, D.  (1985)  The Visual Computer  vol 1 249-259
"Towards an integrated view of 3-D computer animation."

-- 
---------------
Edwin Blake, edwin@cwi.nl   	Phone: +31 20 5924009
Centre for Mathematics and Computer Science (CWI)
Department of Interactive Systems,
Kruislaan 413,  1098 SJ  Amsterdam,  The Netherlands

mhi@edsdrd.eds.com (Mamdouh Ibrahim) (06/23/89)

In article <6192@pdn.paradyne.com>, alan@oz.nm.paradyne.com (Alan Lovejoy) writes:
> In article <11213@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
> >So, the topic for debate today is the question whether method selectors,
> >such as ``weight'', which are implemented in several classes, should
> >be considered to be first class objects in their own right.  That is,
> >should we be able to pass ``weight'' as an argument to another function?
> >Should be various ``weight'' functions, although implemented in different
> >classes, be considered to be part of a single entity?
> 
> 1) You have raised an important topic of discussion.
> 2) The fact that messages are not first class objects in Smalltalk and
>    other OOPLs does impair the functionality of those languages.  I have
>    been aware of this problem for many years.
> 
> ...
>
>    Another solution to the problem is to make the syntax for reading and
>    writing state (i.e., instance variables) the same as the syntax for
>    evaluating functions (oh, I guess I mean sending messages :-) :-)).
>    For example, if class RgbColor has the instance variables 'red', 'green'
>    and 'blue,' then the syntax for reading the value of the instance
>    variable 'red' should be "self red" instead of just "red" (the latter
>    being the current syntax).  Similarly, the syntax for setting the value
>    of the instance variable blue should be "self blue: 0.5" instead of
>    "blue <- 0.5" (again, the latter being the current syntax).  Given this
> ...

We have addressed this problem in our own object-oriented language,
KSL.  In KSL we have implemented messages and other language
expressions as first class objects.  For example,
         (red $target 0.0)
is a message with selector "red" sent to the object identified by the
variable "target" with an argument "0.0". The syntax is the same    
regardless of whether "red" invokes a method or accesses an instance
variable. The selector, target, and arguments of the message expression
are actually objects which are evaluated before the message is resolved
so that any of them can be computed.  A similar message could be
         ($color $target $value) 
where each is computed.  Here they are variable references but they
could as well be more complex expressions.

In addition, methods and instance variables (as well as other
behaviors) are implemented as first class objects.  The implementation
of behaviors as objects has allowed us to extend the language with
specialized behaviors that implement rule-base and logic programming.
For more information on KSL and its reflective properties, see:

  Ibrahim, M.H. and Cummins, F.A., "KSL: A Reflective Object-Oriented
  Programming Language," Proceedings of the International Conference on
  Computer Languages, 1988.
-- 
Mamdouh H. Ibrahim - Electronic Data Systems
                     mhi@edsdrd.eds.com
     USENET:     ... {rutgers!rel,uunet}!edsews!edsdrd!mhi

bap@f.gp.cs.cmu.edu (Barak Pearlmutter) (07/22/89)

There has apparently been some discussion on this newgroup of
combining the advantages of first class functions, as in Scheme, with
the type system and incremental method definitions of object-oriented
languages like Smalltalk.  In fact, such a unification was on our
minds when Kevin Lang and I designed Oaklisp, an object-oriented
superset of Scheme.  In Oaklisp, we attempted to preserve the
desirable properties of Scheme, in particular lexical scoping,
temporal consistency, and universal first classness, while adding
object-oriented features, namely multiple inheritance, instance
variables, and textually dispersed method definitions.

We accomplished these goals by introducing "first class types" into
the language, introducing "operations," which are analogous to
Smalltalk's selectors, and adding the special form ADD-METHOD, which
takes an operation (in an evaluated position), a type (also in an
evaluated position), and a chunk of code.

It turns out that LAMBDA can be defined as a macro in terms of
ADD-METHOD, so the language is build upside-down compared to
temporally inconsistent and non lexically scoped dialects like CLOS
and SCOOPS, namely with the object-oriented stuff on the bottom and
lisp on the top.

For further details, see the papers

    "Oaklisp: an Object-Oriented Dialect of Scheme", Lisp and Symbolic
    Computation, v1n1, published by Klewer Associates in Spring 1988.

    "Oaklisp: an Object-Oriented Scheme with First Class Types",
    Proceedings of the ACM conference OOPSLA-86, published as a
    special issue of SIGPLAN Notices.

There is a highly portable, surprisingly efficient, publicly available
implementation available by FTP from DOGHEN.BOLTZ.CS.CMU.EDU
(128.2.222.37), user anonymous, /usr/ftpguest/oaklisp/release.tar.Z,
be sure to transfer in binary mode.  If you do not have access to FTP,
perhaps someone will somehow make the system available on a Usenet
server.  If you would like a tape, send mail to
Catherine.Copetas@CS.CMU.EDU to make suitable arrangements, which
include a copying fee.  I will ignore requests to email the system.
Free hard copies of the draft language and implementation manuals are
also available by sending your physical address to copetas@CS.CMU.EDU.
-- 

						--Barak.
--