Object-Oriented Programming in Scheme
Total Page:16
File Type:pdf, Size:1020Kb
Massachusetts Institute of Technology Artificial Intelligence Laboratory AI Memo March DRAFT Ob jectOriented Programming in Scheme Norman Adams Jonathan Rees Abstract We describ e a small set of additions to Scheme to supp ort ob ject oriented programming including a form of multiple inheritance The extensions prop osed are in keeping with the spirit of the Scheme lan guage and consequently dier from Lispbased ob ject systems such as Flavors and the Common Lisp Ob ject System Our extensions mesh neatly with the underlying Scheme system We motivate our design with examples and then describ e implementation techniques that yield eciency comparable to dynamic ob jectoriented language implemen tations considered to b e high p erformance The complete design has an almostp ortable implementation and the core of this design comprises the ob ject system used in T a dialect of Scheme The applicative bias of our approach is unusual in ob jectoriented programming systems This rep ort describ es research done at the Articial Intelligence Lab oratory of the Massachusetts Institute of Technology Supp ort for the lab oratorys articial intelli gence research is provided in part by the Advanced Research Pro jects Agency of the Department of Defense under Oce of Naval Research contracts NK and NK This is a revision of a pap er that app eared in the Proceedings of the ACM Conference on Lisp and Functional Programming c Asso ciation for Computing Machinery Introduction and terminology Scheme is nearly an ob jectoriented language This should come as no surprise since Scheme was originally inspired by Actors Hewitts message passing mo del of computation Steele has describ ed the relationship b etween Scheme and Actors at length We take advantage of this rela tionshipand we try not to duplicate functionality that Scheme already providesto add full supp ort for ob jectoriented programming Our exten sions are in keeping with the spirit of Scheme It was designed to have an exceptionally clear and simple semantics and few dierent ways to form expressions We develop examples of how one might program in Scheme using ob ject oriented style Inherited b ehavior is handled in a straightforward manner We show that a new disjoint data type for instances must b e added to Scheme in order to p ermit application of generic op erations to all Scheme ob jects and that making generic op erations anonymous supp orts mo dularity We complete our presentation by showing how to obtain go o d p erformance for generic op eration invocation We use the terms object and instance idiosyncratically an ob ject is any Scheme value an instance is a value returned by a constructor in the ob ject system An operation sometimes called a generic function can b e thought of as a pro cedure whose denition is distributed among the various ob jects that it op erates on The distributed pieces of the denition are called metho ds Ob jectoriented programming using pro cedures Simple ob jects Our rst approximation to ob jectoriented programming in Scheme is straight forward an instance is represented as a pro cedure that maps op erations to metho ds A metho d is represented as a pro cedure that takes the arguments to the op eration and p erforms the op eration on the instance As an example consider the following denition of a constructor for cells define makesimplecell value lambda selector cond eq selector fetch lambda value eq selector store lambda newvalue set value newvalue eq selector cell lambda t else nothandled define acell makesimplecell acell fetch ! acell store ! unsp ecied acell cell ! true acell foo ! error Each call to makesimplecell returns a new cell Abstract op erations are represented by symbols here fetch store and cell An instance is represented by the pro cedure returned by the constructor The lexical variables referenced by the metho ds serve the purp ose of instance variables To p erform an op eration on an instance the instance is called passing the op eration as the argument the resulting metho d is then applied to the arguments of the op eration There is no explicit notion of class but the co de p ortion of the closure constructed for the expression lambda selector serves a similar purp ose it is static information shared by all instances returned by the makesimplecell constructor An instance returns the ob ject nothandled instead of a metho d to indicate it denes no b ehavior for the op eration The particular value of nothandled is immaterial as long as it is identiable as b eing something other than a metho d We will make use of this prop erty later define nothandled list nothandled To improve the readability of op eration invocation we introduce the pro cedure operate define operate selector theinstance args apply theinstance selector args This lets us replace acell store with the somewhat more p erspicuous operate store acell Operate is analogous to send in old Flavors and in CommonOb jects Inheritance The following denes a named cell that inherits b ehavior from a simple cell define makenamedcell lambda value thename let scell makesimplecell value lambda selector cond eq selector name lambda thename else scell selector We say that ob jects returned by makenamedcell have two components the expression makesimplecell yields the rst comp onent and the expression lambda selector yields the second The program mer controls what state is shared by choosing the arguments passed to the constructors and by choosing the expressions used to create the comp onents In this style of inheritance only b ehavior is inherited An instance can name its comp onents but can assume nothing ab out how they are implemented We have single inheritance if the instance consults one comp onent not including itself for b ehavior We have multiple inheritance if the instance consults multiple comp onents not including itself for b ehavior For the ab ove example that might b e done by expanding the else clause as follows else let method scell selector cond eq method nothandled anothercomponent selector else method This is similar to the style of inheritance in CommonObjects in that in stance variables are considered private to the comp onent and cannot b e in herited However CommonObjects forces the comp onents to b e new where our formulation has no such requirement thus distinct instances may share comp onents and in turn the comp onents state Because classes are not explicit and it is p ossible to share state and b ehavior one may say this approach provides delegation rather than inheritance When more than one comp onent denes b ehavior for an op eration the b ehavior from the more sp ecic comp onent the one consulted rst shadows the less sp ecic Op erations on self One frequently wants to write a metho d that p erforms further op erations on the instance For example if we were implementing an op en output le as an instance that supp orted writechar we could implement a writeline op eration as a lo op p erforming writechar op erations on the instance itself In simple cases a metho d can refer to the instance by using letrec in the instances implementation letrec self lambda selector cond eq selector writeline lambda self string operate writechar self char self When inheritance is involved this will not work The variable self will not b e in scop e in the co de for inherited metho ds A comp onent that uses letrec as ab ove will b e able to name its comp onent self but not the comp osite A small change to the proto col for invoking metho ds remedies this the comp osite is passed as an argument to every metho d define operate selector theinstance args apply theinstance selector theinstance args Op erations on comp onents Because comp onents may b e given names a comp osites metho d for a given op eration can b e dened in terms of the b ehavior of one of its comp onents For example we can dene a kind of cell that ignores stores of values that do not satisfy a given predicate define makefilteredcell lambda value filter let scell makesimplecell value lambda selector cond eq selector store lambda self newvalue if filter newvalue operate store scell newvalue else scell selector This practice is analogous to sending to super in Smalltalk and callnextmethod in the Common Lisp Ob ject System CLOS There is a problem here When the comp osite p erforms an op eration on a comp onent the self argument to the comp onents metho d will b e the comp onent not the comp osite While this is sometimes useful we also need some way to p erform an op eration on a comp onent passing the comp osite as the self argument This is the customary op eration of send to sup er and its analogues We can do this using a variant on operate that takes as arguments b oth the comp osite and the comp onent from which a metho d is to b e obtained define operateas component selector composite args apply component selector composite args define operate selector instance args apply operateas instance selector instance args Integration with the rest of the language Op erations on noninstances One often wants to include noninstances in the domain of an abstract op era tion For example the op eration print when p erformed on a noninstance should invoke a printer appropriate to that ob jects type Similarly the abstract op eration cell should apply to any ob ject in the Scheme system returning false if the ob ject is not a cell But given our present denition of operate we cannot meaningfully say operate op x unless x is an in stance We can make print work on noninstances if we can asso ciate metho