liz@tove.UUCP (Liz Allen) (02/08/85)
We have had an implementation of a flavors package in Franz lisp now for about 3 years -- we have found that it has nearly transformed the way we write lisp programs. Probably the most useful feature has been the following: The ability to send a message to an object *without* having to know the type of the object. This gives new meaning to the idea of a generic operation. Notice that without this ability, methods would be rather difficult to inherit since lots of methods send messages "self" -- and, even though you know "self" has to mix in the flavor the method is defined for, you don't really know what flavor "self" is. So, what is really necessary is that you somehow know that the flavor of the object has methods for the messages you need to send it. Probably the best way to do this is to know that (1) the flavor mixes in some flavor that does define these methods or that (2) the flavor mixes in a flavor that requires the methods to be defined. An example of (1) is when you send a message like :print-self to an object -- vanilla, which is mixed into every flavor in the system (unless otherwise specified) defines a method for :print-self. An example of (2) is when you define a flavor that is just going to be a mix-in to other flavors. It can give you certain methods (or operations) that depend on the fact that the flavors which mix it in define other methods which (by some necessity) depend on the other flavor. For example, a flavor that defines methods to save information in files may require flavors which mix it in to define methods for retrieving the information to be stored. Another example has to do with a parallel activation net I am implementing. There are different kinds of nodes in the net (eg, connected to other nodes in different manners). Yet there is some common ground between the nodes. However, there isn't enough to define a flavor which will be used to define some nodes *and* be used as a mix-in to other nodes. So, I defined a flavor that will be used as a mix-in to all the nodes. It contains those methods that are common to all the nodes and assumes that some of the methods it sends to "self" will be defined by the node flavors mixing in this common flavor: (defflavor node-mixin ( ; the instance variables name ; name of the node value ; activation level of the node resting-value ; activation level at rest ...) :mixin :required-methods input-arcs ; return a list of the input arcs output-arcs ; return a list of the output arcs :gettable-instance-variables name value :settable-instance-variables value ) (More ideas about doing these kinds of things later.) >> > = Larry Koved >> = Mark Weiser > = Larry Koved >Lisp Flavors (which you mention below) is an example of a lanugage >which has is a combination of object-oriented and non-object-oriented >features in a single language. Lisp is not object oriented, but the >flavors package in lisp is object oriented. I would not classify >Lisp as an object oriented language; only the flavors part is >object oriented (to a degree). I do not know of a language which >only has inheritence, but not objects. Lisp itself is object oriented in the sense that lisp variables are not typed. So, an operation like plus needs to check the types of its arguments before it can execute. That, of course, doesn't give you everything you want in an object oriented language, but I would like to make a couple other points. One is that making *every* procedure into a method (or operation) is probably not the best approach. There are still some routines that seem (at least to me) to want to be just regular functions -- especially those that don't have any arguments at all. Now, I think that Smalltalk does require all procedures to be operations attached to some object; someone *might* be able to convince me this is wise, but I'm not convinced yet and would like to see more development first. My feelings here are connected to a basic feeling that when you're adding new AI tools in lisp, they should be fully integrated with other tools, etc, already available in lisp rather than making you use the new AI tool in isolation from what was already in lisp. (See my paper on YAPS from AAAI-83 for another example of this.) The second point is that there are hooks in flavors that allow messages to be sent to any lisp object. >The degrees of [of an object oriented language] are the degrees to which the >language makes the sharp distinction about object manipulation. >In particular, how well the language protects the objects, their >internal representations and access to the procedures which manipulate >the representation. I'm not sure why you think the amount of protection the language gives the object is that important... I do think it is good to have things set up somehow so it is clear how the objects of a given type are to be handled by outside routines, but other aspects of object oriented programming are much more important in my mind (see the rest of this article!). >> >The performance of the language (instructions >> >per second) is a major consideration in deciding the degree to which >> >a language's design is OO. Being extremely OO is expensive in >> >processing time and/or space. >> >> Now this is an interesting issue. Why should OO be expensive? >> It need not be, because it need not be a runtime feature of a language. >> Smalltalk is mostly interpreted, and so is slow for that reason, >> not because it is OO. The Maryland Flavors Package under Franz >> Lisp allows compiled methods, flavors etc, and so runs not too >> much slower than bare Lisp. And a completely statically checked >> and implemented OO language should be as fast as any other at runtime. Our Maryland flavors package does allow methods, etc, to be compiled, however, determining the appropriate method to use is a runtime operation. When a flavor is defined, every new flavor/message pair is added to a hash table which is used to determine which method should be used when an object is sent a message. This makes run time checking fast -- though not quite as fast as it would be in a statically checked language. But, to go to a statically checked language, in my mind, would be to lose a lot of the nice features of a flavors system (as I state at the beginning of this article!). (One of the people here (Bob Bane) has extended flavors to allow optional type declaration a new package for flavors objects so that method determination can be done at compile time. But, we view that as strictly optional and probably only done once a system is in a production phase. Even then, of course, there would *have* to be some run time checking since any flavor that might be used as a mixin will need it.) >> Might be slow to compile with current technology--but we haven't had >> much practice at building fast OO compilers. Combine time (or compile time) *is* slow in Maryland flavors. But, we win because run time execution is quite good. I know of some things that can be done to speed things up a bit, but it isn't clear (yet) what the best approach really is. The ideas I was thinking about would tighten things up a bit in terms of programming style and clarify (and restrict!) some things about using instance variables to communicate between flavor and other flavors which mix it in. It's not clear that the restrictions involved are appropriate -- indeed some of these ideas would probably make inappropriate restrictions. The question is whether we can figure out what is appropriate and what is inappropriate and take advantage of the appropriate ones to win at combine time. As far as I'm concerned, we need to understand that kind of communication far better before I'm willing to put restrictions in. (Besides, I don't have the time!!!) >Yes, the issue about performance of systems which require protecton >is interesting. If and when type checking can be done statically, >the cost is much lower. You make refrence to flavors. The flavors >part of lisp is object oriented, but the rest of lisp upon which >flavors is implemented is not. I suspect that this makes a difference. >When looking a security (protection) oriented systems, there are costs >incurred due to the protection mechanisms. Once you start to do >multi-programming, then you get many different types of protection >problems which do not occur in uni-programming systems (and languages). >This is also a factor in why protected systems incur a heavy cost >at run-time. Type checking in flavors pretty much winds up meaning simply that an object can handle certain messages appropriately. I've alluded in the beginning of this article to some ways of doing this -- and at compile (or combine) time. Of course, the language can't guarantee that you are using the appropriate mechanisms, but I think the tradeoff here is worth it. Things you can do: - Organize your flavors into families when you have a set of flavors which will be used in similar situations by defining some common flavor which they will all mix in. (Eg, when a connection from one object could lead to an object of any one of several flavors.) - Define as many of the methods that the family is expected to handle in the common mixin flavor as is reasonable. (This even saves work!) - Declare all the other methods that the family is expected to handle as :required-methods of the common mixin flavor. - Declare all the methods which a common mixin flavor needs to call as :required-methods. Note that by declaring a method as a :required-method, the system will complain if non-mixin flavors are created which do not define the method. Also, notice that there are (at least!) two kinds of communication going on here (and this is probably why flavors doesn't distinguish between internal and external methods): 1. Between a flavor and outside routines via messages sent to objects of that flavor (or objects that inherit methods from that flavor). 2. Between a flavor and flavors that mix this flavor in. This is done via messages sent to "self" by both the mixin flavor and the flavor mixing it in. It is also done via a flavor referencing the instance variables of the mixin flavor. Is the latter external or internal? It is external to the individual flavors but may be internal to the family of flavors. What is the scope here? I guess what I'm saying is that object oriented programming in general and flavors in particular are great! There are some areas that could be worked on -- they could be made better -- but there are some complicated issues here that need to be explored. I could easily see people addressing these by adding greater restrictions to a system like flavors -- I would be very reluctant to do this. *Some* restrictions are probably appropriate in the sense that they clean up the communication between flavors. But, at the same time you don't want to "clean up" necessary avenues of communication -- a lot of the power of object oriented programming lies in its flexibility. -- -Liz Allen Univ of Maryland, College Park MD Usenet: ...!seismo!umcp-cs!liz Arpanet: liz@tove (or liz@maryland) "This is the message we have heard from him and declare to you: God is light; in him there is no darkness at all" -- 1 John 1:5