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: 109fba,b87849933931bc93 X-Google-Attributes: gid109fba,public X-Google-Thread: f43e6,b87849933931bc93 X-Google-Attributes: gidf43e6,public X-Google-Thread: fac41,b87849933931bc93 X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,b87849933931bc93 X-Google-Attributes: gid103376,public X-Google-Thread: 114809,b87849933931bc93 X-Google-Attributes: gid114809,public X-Google-Thread: 1108a1,b87849933931bc93 X-Google-Attributes: gid1108a1,public From: "Norman H. Cohen" Subject: Re: OO, C++, and something much better! Date: 1997/01/27 Message-ID: <32ED2930.3B92@watson.ibm.com> X-Deja-AN: 212713025 references: <32DF458F.4D5C@concentric.net> <32DF94DC.6FF8@watson.ibm.com> <32DFD972.37E4@concentric.net> <32E4FC5B.242C@watson.ibm.com> <32E6862D.608B@parcplace.com> <32E788D4.4B91@watson.ibm.com> content-type: text/plain; charset=us-ascii organization: IBM Thomas J. Watson Research Center mime-version: 1.0 reply-to: ncohen@watson.ibm.com newsgroups: comp.lang.c++,comp.lang.smalltalk,comp.lang.eiffel,comp.lang.ada,comp.object,comp.software-eng x-mailer: Mozilla 3.0 (Win95; I) Date: 1997-01-27T00:00:00+00:00 List-Id: traymond@craftedsmalltalk.com wrote: > > In <32E788D4.4B91@watson.ibm.com>, "Norman H. Cohen" writes: > [stuff deleted] > :For example, suppose a program has an array of "producer companies" that > :manufacture a particular product and an array of "consumer companies" > :that buy that product. Suppose the program manipulates both integers > :meant to index into the first array and integers meant to index into the > :second array. Mistakenly using a variable holding an integer of the > :first kind to index into the second array could produce subtle errors > :that might be hard to track down, or might just silently produce > :incorrect answers. In a strongly typed language such as Ada, one could > :write > : > : type Producer_Number is range 1 .. Max_Producer_Count; > : type Consumer_Number is range 1 .. Max_Consumer_Count; > : Producers : array (Producer_Number) of Company; > : Consumers : array (Consumer_Number) of Company; > : > :Producer_Number and Consumer_Number are distinct integer types whose > :uses cannot be intermixed without an explicit type conversion. (This is > :a degree of type protection unavailable in C or C++). Certain variables > :can be declared to be of type Producer and others of type Consumer. An Oops. I meant to say "Certain variables can be declared to be of type Producer_Number and others of type Consumer_Number." Sorry if this caused any confusion. > :attempt to use a variable of type Producer_Number to index into the > :array Consumers will produce a compile-time type error. > : > :As you said, "Smalltalk does not lend itself to 'type' errors of that > :nature." Smalltalk programmers are no less likely than other > :programmers to use an integer variable to index into the wrong array, > :but since Smalltalk does not have the means to express such distinctions > :as type distinctions, I would imagine that most Smalltalk programmers > :would think of this as a "general logic error" rather than as the kind > :of problem that would be caught by compile-time type checks. (When you > :don't have a hammer, none of your problems look like nails.) > > Sure, smalltalk programmers can index into the wrong array. > However, your example appears to be formulated for a procedural > style of programming. When smalltalk programmers want to > separate consumers and producers they usually use different > objects which reduces the tendency to produce the type of > errors you refer to. When you say "different objects" do you really mean "different classes"? If so, the Ada analog would be "different types", and that's just what I've done above: used different types for consumer numbers and producer numbers. However, with static checking, this does more than simply "reduce the tendency to produce" this kind of error; it causes the compiler to catch this kind of error and point it out to the programmer even before the program is tested. I presume you are using the word "procedural" to mean "not object oriented". However, there is nothing in the example above that suggests this. Perhaps it is the presence of a built-in array type that looks unSmalltalk-like to you. Fine, replace the two integer types with two classes called producerID and consumerID, make Producers an object belonging to some collection class with an extract method that takes a producerID object, and make Consumers an object belonging to some collection class with an extract method that takes a consumerID object. My argument remains the same: It is easy to inadvertently send an extract message with a producerID argument to Consumers or an extract message with a consumerID argument to Producers. The incorrect call might occur only on some obscure path that testing fails to exercise. Strong typing allows such errors to be caught at compile time. > Part of the power of smalltalk is the use of interface polymorphism. > Classes do not have to inherit from the same root to be able > to use the same message interface. When designing the > software for your problem one can compose methods that use > polymorphism so that a single method can "operate" on producers > and consumers without having to know what it is operating on. > As a matter of fact a programmer reading the method may not > even be able to tell if it processes consumers or producers > because both will work. This is s red herring. The benefits of interface polymorphism are not lost (in fact they are made safer) if classes must be declared to support a given message, and any attempt to send a message to an object not declared to support it is caught as an error at compile time. In Java, we could write interface Company is { abstract public void someMethod(); } class ConsumerCompany implements Company { public void someMethod () { ... }; ... } class ProducerCompany implements Company { public void someMethod () { ... }; ... } and a call X.someMethod() where X is declared to be of class Company might invoke either the ConsumerCompany or ProducerCompany version of someMethod, but an attempt to apply someMethod to an object whose class does implement the Company interface would be flagged as an error at compile time. In Ada, we could write package Companies is type Company is abstract tagged private; procedure Some_Method (C: in out Company) is abstract; ... end Companies; package Companies.Consuming is type Consumer_Company is new Company with private; procedure Some_Method (CC: in out Consumer_Company); ... end Companies.Consuming; package Companies.Producing is type Producer_Company is new Company with private; procedure Some_Method (PC: in out Producer_Company); ... end Companies.Producing; and a call Some_Method(X) where X is of type Company'Class might invoke either the Producer_Company or Consumer_Company version of Some_Method, but an attempt to call Some_Method with a parameter that does not belong to the class rooted at type Company would be flagged as an error at compile time. The issue is not whether or not to have interface polymorphism--every OO language does--but rather whether or not to impose some discipline and structure on interface polymorphism, by making the interfaces explicit and checking at compile time that they are used consistently. -- Norman H. Cohen mailto:ncohen@watson.ibm.com http://www.research.ibm.com/people/n/ncohen