From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,c52c30d32b866eae X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,2ea02452876a15e1 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,c52c30d32b866eae X-Google-Attributes: gid1108a1,public From: donh@syd.csa.com.au (Don Harrison) Subject: Re: Real OO Date: 1996/05/01 Message-ID: X-Deja-AN: 152375506 sender: news@assip.csasyd.oz references: organization: CSC Australia reply-to: donh@syd.csa.com.au newsgroups: comp.lang.eiffel,comp.lang.ada,comp.object Date: 1996-05-01T00:00:00+00:00 List-Id: Robert Dewar writes: :Don Harrison said : :> :Simply this: Classwide operations can be defined anywhere by anyone. :> :They do not have to be defined along with the primitive types in :> :their packages. : :> In OO software, you would want to define them with their types :> (except that in Eiffel, you assign the operation to a particular :> type - whichever is most appropriate). Otherwise, you would end up :> with spaghetti, IMO. : :It's always surprising how people get carried away with one narrow view :of programming paradigms. It very much reminds me of the old saying that :"if the only tool you have is a hammer, then all problems start to :resemble nails". : :The idea that you should package operations with types is a very useful :(and very old one). The particular enbodiment that we refer to as object :oriented programming is in particular a very useful (and also very old) :idea. : :But going one step further and saying that this idea is so effective that :ALL software must be organized this way, and that any other organization :is defective is simply not justified. : :As I say, this seems a common affliction in the programming languages :field: : : o Functional programming is very useful, but disallowing notions of : implicit state completely seems to be going much too far. : : o Proof of correctness is very useful, but insisting that programming : languages be designed so that only programs with integral proofs : can be written seems to be going much too far. : : o Strong typing is very useful, but insisting that separate types be : used for every separate notion, no matter on how small a scale, is : going too far. Isn't this pure OO rather than strong typing? If you consider consistency important, it is not. : o Top-down structured design is very useful, but insisting that ALL : programs use only this design approach is going too far. : : etc. : :To me the "pure" OO view that Don expresses is yet another example of this :excess of zeal. : :There are many instances in which it makes sense to package operations :by classifying operations, rather than types. For example, It seems quite :appropriate to have a set of procedures for matrix diagonalization packaged :up together, rather than bundled in with the matrix type (indeed the idea :of bundling all possible matrix operatoins up with the matrix type is :untenable). Similarly, it makes sense to have trig functions for various :floating-point types bundled up in a package, rather than scattered around. : :The world of operations and types can be though of as a matrix: : : type 1 type 2 type 3 ... : : op1 x - x : op2 - x - : op3 x x - : ... : :Roughtly speaking, the OO approach organizes by columns, which is often :fine, but the operation organization by rows also often makes sense. :For example, if op3 represents some complex numerical procedures, :understood only by a small group of experts, it may well be better :to bundle up op3 rather than distributing the op3 code around the :separate types. : :A maximally effective programming language will be friendly to either the :"row" view or the "column" view, or flexible mixtures of the two. : :P.S. spaghetti code doesn't just mean code you don't like. It is a rather :specific term used to described the non-nested chaotic control structures :caused by undisciplined use of gotos or equivalent transfers of control. :I think it is useful to keep this sense. This may surprise you, but I actually agree with most of what you've said. I've been thinking about the symmetry issue and think that the most elegant approach may be to separate operations from the objects they act on. But, before you get excited, this doesn't mean that I think that I think that the Ada model is the right one. I think that the operations should 'float' around in operation space just as classes 'float' around in class space. What I mean is that rather than ascribing ownership of an operation to a specific class, it may be better to allow co-ownership by each class corresponding to parameters. In such a model, the parameters are all symmetric and the semantic encapsulation boundaries would overlap. The semantic boundary of a class would cease to correspond to a syntactic structure, but tools would generate a view of the class in which the semantic and syntactic structures coincide. This would appear the same as an Eiffel class. The difference is that the common operations would be duplicated in the classes that share them and all the operations (primitive and 'classwide') would appear (some filtering may be necessary). Here is an example: class A feature p: P q: Q r: R is once ... end invariant ... end class B feature s: S t: T invariant ... end Looks the same, so far. But, isn't. Now, define some operations ... do_x (a: frozen A; b: B) is -- a is 'classwide': it may not be redefined do -- b may be redefined ... end do_y (a: A; b: B) is -- multiple dispatching require a.p > 0 and b.s > 0 do ... end do_z (a: separate A; b: B) is -- concurrency: a is locked require a.p > 0 and -- synchronisation condition b.s > 0 -- correctness condition do ... end next_p (a: A): P -- function require a /= Void do Result := a.p ensure Result /= Void end do_w (a: A; b: like A) is -- anchored parameter do ... end ----------------------------------------------------------------------------- The output of the merging tool would be: Class A ------- class A feature p: P q: Q r: R is once ... end do_x (a: frozen A; b: B) is -- a is 'classwide': it may not be redefined do -- b may be redefined ... end do_y (a: A; b: B) is -- multiple dispatching require a.p > 0 and b.s > 0 do ... end do_z (a: separate A; b: B) is -- concurrency: a is locked require a.p > 0 and -- synchronisation condition b.s > 0 -- correctness condition do ... end next_p (a: A): P -- function require a /= Void do Result := a.p ensure Result /= Void end do_w (a: A; b: like A) is -- anchored parameter do ... end invariant ... end Class B ------- class B feature s: S t: T do_x (a: frozen A; b: B) is -- a is 'classwide': it may not be redefined do -- b may be redefined ... end do_y (a: A; b: B) is -- multiple dispatching require a.p > 0 and b.s > 0 do ... end do_z (a: separate A; b: B) is -- concurrency: a is locked require a.p > 0 and -- synchronisation condition b.s > 0 -- correctness condition do ... end invariant ... end Class P ------- class P feature ... next_p (a: A): P -- function require a /= Void do Result := a.p ensure Result /= Void end invariant ... end ----------------------------------------------------------------------------- Comparison with Eiffel: 1) Each parameter to an operation has the same status: there is no Current object and attributes of each parameter object may be updated directly eg. a.y := ... b.x := ... This is more permissive than Eiffel. 2) Multiple dispatching permitted. 3) Freezing occurs at finer granualarity: at the parameter level rather than the routine level. Freezing all parameters is equivalent to freezing the routine. 4) Operations must preserve the invariant of each parameter. 5) Functions redefined as attributes simply cease to appear as functions and appear as attributes. 6) Concurrency mechanism is more symmetrical. 7) Whatever other adaptations are necessary ... What have I missed? The intention is that the same safeguards as Eiffel would be maintained while offering higher modelling integrity and slightly more flexibility (direct access to all parameters and multiple dispatching FWIW). I suspect translation of Eiffel programs into this language would be quite straightforward. Would the reverse be more difficult? BTW, I'm not proposing a new language. Just playing with ideas. But, just in case you want a name, let's see ... Blackpool? No. ... Pisa? No. ... Babel? No. ... How about 'Ziggy' (short for ziggurat: the same kind of Mesopotamian tower as the tower of Babel (because it reflects an arrogant idealism and adds to the confusion of myriad programming languages)). Comments? Do you love it? Hate it? Don't care? Don.