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=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,d0490497bd8e3f95 X-Google-Attributes: gid103376,public From: mheaney@ni.net (Matthew Heaney) Subject: Re: Syntax for tagged record types Date: 1997/05/25 Message-ID: X-Deja-AN: 243877258 References: Organization: Estormza Software Newsgroups: comp.lang.ada Date: 1997-05-25T00:00:00+00:00 List-Id: In article , dewar@merv.cs.nyu.edu (Robert Dewar) wrote: ><kludge, and obfuscates declarations. Ada 95 doesn't have constructors, so >let's not try to fight the language.>> > >Most people find the use of discriminants as "constructor arguments" a >natural and powerful feature in Ada (though naturally they don't think >in terms of this terminology). > >You can declare that "I think X is a kludge" for any X, but such a statement >is only helpful to discussion if you give some idea *why* you think this. I say this because "discriminant" should mean "tag in a disjoint union." Records are Cartesian product, and discriminated records are disjoint union. And that's all discriminate record should mean. But "tag of a disjoint union" is a far different thing than "arguments to a constructor." And when you use discriminants for the latter, the declaration is ambiguous, and I the maintanence programmer have to do work to figure out what you mean. It's not unlike another sin commited by many Ada programmers. That's when you use "and then" in predicates, when you really mean "and." Many Ada programmers do this in a naive attempt at some sort of optimization, but it should only be used when you want to enforce an order dependence on evaluation of the parts of the predicate. Now when I see a predicate with "and then," it's ambiguous, because I don't know whether you're making (an unnecessary) optimization, or whether there really is an order dependence. You, the writer of that code, are being unthoughtful to me, the maintainer of that code, because you have abrogated your responsibility to tell me what you mean explicitly and unambiguously, and therefore I am put in the unwanted position of having to guess. That Ada evaluates all the parts of a predicate, even if one early part evaluates to false (say, in a complex Boolean expression with more than one "and"), is an _essential_ characteristic of the language. When a programmer uses "and then" everywhere, he is really wishing that the language were some other way, and is desperately trying to somehow "fix" the language. But this is no fix at all. And I the poor maintanence programmer am the victim of your thoughtlessness. The language is the way it is. Accept that. If it doesn't do exactly what you want, stay within the spirit of the language anyway, and justify it by realizing that Ada gives you a lot a things you wouldn't have if you were programming in another language, so you're still operating in the red. Respecting the spirit of the language means not using a discriminant as a constructor parameter. Norm stated in his book that "In Ada, the role of these [constructor] parameters can be played by discriminants." (p. 579) Now, I like Norm, and I thank him a thousand times over every time I can pick up his book and answer a question, but this is horrible advice. When you use a discriminant as a constructor parameter, the purpose of the discriminant is now ambiguous. And I the poor maintanence programmer have to figure out what you mean. So I have to guess, and I might guess wrong. Respecting the spirit of the language means not using short-circuit control forms as an optimization. When you do that, the short-circuit form is ambiguous, and I have to figure out whether you meant "this is an optimization" or "this is an order-of-evaluation dependency." I have to guess what you mean, and I might guess wrong. It's not unlike Ada 83 programmers who, in their zeal to "repair" Ada, "simulated" inheritance hierarchies. I can tell you this causes nothing but obfuscation of the code, and any supposed benefits of "reusability" or "being more object-oriented" were more than offset by the attendent complexity of trying to use a solution not directly supported in the language. The whole point of software engineering is to _minimize_ complexity. You must be _unrelenting_ in seeking out techniques to _simplify_ the software. So when you make your code more complex by "simulating" inheritance, in some sort of quixotic attempt to be "more object-oriented" - because you've been led to believe that "more" object-oriented is "better" - then I have to ask myself what kind of engineering this is. Ada 83 is not object-oriented. Accept this. Use the tools provided by the language _as_is_. Because when you try to bend the language to "repair" it, you distort the clarity of your solution too, because it's expressed in a way that isn't natural for the language. And when your solution isn't crystal clear, then I the maintenance programmer have to figure out what you mean. I don't want to figure out what you mean; I want you to tell me, unambiguously. This doesn't mean being object-oriented isn't good. It's just that Ada 83 doesn't have inheritance (technically, "type extension") or polymorphism. So respect that "limitation." Rationalize this by saying to yourself that the language has many other good features that aren't in other languages, so you're still ahead in the game. One nascent (maybe not-so-nascent) phenonmenon that I've observed is a dissatisfaction with the fact that, in Ada, a module is not a type, "you know, like in other languages." I've seen programmers name their abstract data type "object" or "instance," so that the "real" name is only obtained by qualifying the type name with the package name, as in The_Stack : Stack.Object; This is a horrible naming convention. It represents a desperate attempt to repair the language, by trying to force the package to be a type. What are you going to name the iterator for the stack? "Object" has already been used within that namespace. What you'll probably do is create a child package, so you can again name your iterator type Stack.Iterator.Object. This too is a mistake: the point is that the language was _designed_ so that you can declare closely related abstract data types _together_ in the _same_ package. This proliferation of packages - as many packages as there are ADTs - is a complete mistake, and is orthogonal to the intended usage of the language. The whole point is to prevent getting lost in a sea of types (as you do in other languages, where the module is a type), by using packages as a higher-level organizing principle. If you have as many packages as types, then what have you gained by having packages at all? In Ada, a package is a module. It is not a type. It is a language tool to give the programmer explicit control of namespace - nothing more, and nothing less. Accept this, and respect the language, by giving the type itself the name of the abstraction. Respect the intended usage of Ada by putting the data structure ADT and its active iterator ADT togther in the same package. Yes, I know this isn't how it is in other languages, but rationalize it by saying that there are plenty of things you do have in Ada that you don't have in other languages. And plently things you don't have to do. (Example: In Ada, you don't need a "friend" construct, because visibility is implied by the colocation of types in the same package.) It's not unlike the German language. Those silly Germans, they put all the verbs at the end of the sentance. So let's all try to "fix" German, but putting all the verbs where they "should" be. Obviously, this would be horrible thing to do. That verbs go at the end of the sentance is an _essential_ characteristic of the German language. Somehow, the Germans manage to speak with each other just fine, thank you very much. Imagine that! You must think in the paradigm of the computer language to effect the most elegant solution to a problem. It does no one any good (least of all the poor maintenance programmer) when you fight Ada by trying to incorporate "better" features (say, automatic short-circuiting) found in other languages, without those features being directly supported. Here's a quote from Jean Ichbiah, on the nature of design: "One can only reach a harmonious integration of several features by immersing oneself into the logic of the existing parts." It means that the language is the way it is, and you must immerse yourself in the language, warts and all, to achieve beauty and harmony. So when I say using discriminants as a constructor is a "kludge," I'm saying that you're fighting the language. Ada 95 doesn't have constructors. That is (for now) an essential characteristic of the language. Use discriminants as discriminants (that is, as the tag in a disjoint union), and accept that you don't have constructors, and rationalize this by realizing that the language is pretty good even without them. -------------------------------------------------------------------- Matthew Heaney Software Development Consultant (818) 985-1271