Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!pasteur!ames!think!barmar From: barmar@think.COM (Barry Margolin) Newsgroups: comp.lang.lisp Subject: Re: CLOS: is it OOP? Message-ID: <29573@news.Think.COM> Date: 16 Sep 89 21:24:28 GMT References: <19582@mimsy.UUCP> <29564@news.Think.COM> <11815@polya.Stanford.EDU> Sender: news@Think.COM Distribution: usa Organization: Thinking Machines Corporation, Cambridge MA, USA Lines: 77 In article <11815@polya.Stanford.EDU> pallas@Neon.Stanford.EDU (Joe Pallas) writes: >I'm inclined to agree that protection is not absolutely required for >an object-oriented language (although I wouldn't want to use one >without it). But I would argue that it is precisely because of >generic functions that CLOS CANNOT have protection. To have >protection, you must have a clearly defined protection boundary. >Method invocations establish such a boundary, but generic functions do >not. I don't understand this; perhaps we are talking about different kinds of protection. What kind of boundary is established by (send object :foo) that is not established by (foo object)? My definition of encapsulation and protection is that methods for a particular class may only access instance variables defined by that class. Flavors and CLOS permit methods to access any of the object's instance variables directly, even instance variables defined by a sibling class. Flavors, at least, has options such as :REQUIRED-INSTANCE-VARIABLES, which permit such dependencies to be documented and checked at instantiation time, but CLOS doesn't. >>In >>a message-sending system, programs that accept messages generally >>don't accept functions and vice-versa; you end up writing >> #'(lambda (x) (send x 'foo)) >>alot. > >I can't say for sure, but I don't think this is true unless you spend >a lot of time writing named helper functions in CommonLisp. I just >scanned through my Smalltalk sources and couldn't find any such >trivial lambda expressions (blocks, in Smalltalk parlance). You >almost always want to do more than just send a simple message in such >a case. So you either have to write a special purpose method/generic >function, or you use a lambda expression anyway. I've done it many times. Often you want to send a single message to every element of a list, e.g. (mapc #'(lambda (stream) (send stream :close)) *all-open-streams*) In a generic function system this becomes simply. (mapc #'close *all-open-streams*) In Smalltalk (which I only have the most meagre experience, and I can't find my reference book here at home, so excuse any syntax errors), I think this would look something like allOpenStreams :MapList [stream | stream :Close] This particular case isn't much of a problem, because you can use a DO loop to get reasonable code in the message system: (dolist (stream *all-open-streams*) (send stream :close)) However, another example that is harder to rewrite without the lambda expression is: (find "foo" *all-open-streams* :test #'string-equal :key #'(lambda (stream) (send stream :file-name))) which becomes (find "foo" *all-open-streams* :test #'string-equal :key #'file-name) in a generic function system. Trivial little accessors are used all the time in code like this. Perhaps Smalltalk doesn't have as many utility routines like this that take functional arguments, which would explain why you don't find so many trivial blocks in your code. Barry Margolin Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar