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. --