Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!mcsun!ukc!pyrltd!tetrauk!rick From: rick@tetrauk.UUCP (Rick Jones) Newsgroups: comp.lang.eiffel Subject: Re: Old confusion Keywords: old, ensure, postconditions Message-ID: <1170@tetrauk.UUCP> Date: 30 May 91 08:57:00 GMT References: <1991May21.040742.1520@syacus.acus.oz.au> <1166@tetrauk.UUCP> <1991May23.212347.23486@leland.Stanford.EDU> Reply-To: rick@tetrauk.UUCP (Rick Jones) Distribution: comp Organization: Tetra Ltd., Maidenhead, UK Lines: 85 In article <1991May23.212347.23486@leland.Stanford.EDU> craig@self.stanford.edu writes: > [ concering functions with or without side-effects ] > >I have two questions of Eiffel converted. > >1. How often do functions make benevolent side-effects to the concrete >state that do not affect the abstract state? If much of the system >relies on functions being side-effect-free (e.g. assertions), then >wouldn't the advantages of compiler-enforced purity of functions >outweigh the advantages of allowing benevolent side-effects? I don't think I've ever written a function which does this in the way that OOSC illustrates the possibility - i.e. a POINT class whose internal representation is either cartesian or polar according to the most recent usage. However, there is a whole category of functions which are essential and do change the state of the whole system, if not directly the state of the object on which they are called. These are functions which create and return new objects. An example is a user interface, where some class contains a function to generate and return a new window. Part of the operation is to add the new window to the current display tree, so the total state is changed. (You can't always do this conveniently using direct calls to "Create", for various reasons.) You can of course write a procedure to create the object and attach it to an attribute, then refer to the attribute to get the result. But if the semantics of the class is that every caller should be guaranteed to get a new window, you just create opportunities for error. >2. Do you actually believe that functions should be side-effect-free? >My view is that side-effecting procedures (even of the abstract state) >that return a result are too useful to forgo. For example, when I >call Stack.Pop I want to get back the element popped off the stack; I >don't want to have to call Stack.Top, save the result somewhere, and >then call Stack.Pop to remove it from the stack. This is very much a matter of personal opinion on style. The no-side-effect rule makes Stack.Top a repeatable call, so that if you want to refer to the top element more than once successive calls will get the same result - i.e. you don't need to save it anywhere at all (you might want to for efficiency reasons, but that's another story!). When you've finished with it, Stack.Pop removes it. Having a "pop" operation as the only way to access the top element is, IMO, even worse - it means you can't get a value without changing the state even if you want to. Having both operations, and allowing Stack.Pop to also return the value as a convenience is a reasonable view; I don't have a religious dogma on the subject. >Also, I believe that >somewhere in OOSC (I can't find it now) is described a technique >whereby instead of writing a side-effecting function (a procedure that >returns a result) the programmer writes a procedure that stores its >result in some instance variable which can then be accessed by a >corresponding function. This approach seems silly; it's more verbose >for the programmer (both the class implementor and the client) and >less efficient since I assume an extra word of storage needs to be >allocated in every such object. Sometimes it's a bit silly - in particular the example I gave of returning a booean to indicate success - but sometimes not. It really comes down to considering carefully the semantics of the class. Is the result of the procedure an intrinsic property of the object, or a transient value? The success/failure indication is arguably a transient condition - having the object retain "success/failure of last procedure" may be of value, but in most cases probably not. The converse is that of a sequential file class, where an object represents an open file. One attribute of such an object is "current line". Accessing it should not cause it to change, and moving to the next line is done with a procedure. This is noticeably different from the traditional treatment of sequential files where "get line" both reads a line and moves on to the next one. In fact the reason for the traditional approach has little to do with programming techniques and a lot to do with the influence of historic hardware (when you are controlling a paper tape reader the only way you get the next item is to make the tape move!). >Perhaps an intermediate step would be to support both procedures that >can return results *and* compiler-enforced side-effect-free functions; >only the latter could be used in assertions. This is an interesting idea, and seems to be worth considering as an addition to the compiler. Do the compiler writers have any comment on this? -- Rick Jones, Tetra Ltd. Maidenhead, Berks, UK rick@tetrauk.uucp Any fool can provide a solution - the problem is to understand the problem