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.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,953e1a6689d791f6 X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,953e1a6689d791f6 X-Google-Attributes: gid103376,public From: eachus@spectre.mitre.org (Robert I. Eachus) Subject: Re: Eiffel and Java + Ada dispatching Date: 1996/11/15 Message-ID: #1/1 X-Deja-AN: 196796983 references: organization: The Mitre Corp., Bedford, MA. newsgroups: comp.lang.eiffel,comp.lang.ada Date: 1996-11-15T00:00:00+00:00 List-Id: I said: : In Ada, the default for generics is that you get the "predefined" :operations for the class. But if you explicitly pass the operation as :a generic formal, you can override the standard definition. No :surprise there either. In article donh@syd.csa.com.au (Don Harrison) writes: > Okay. If it made sense, I think I would prefer to encapsulate > behaviour of related operations into a type and define descendants > covering the variants. Then the parent type bundled with its > operations can be used as a formal generic parameter. That way, > you simplify the generic interface. Don't know whether this fits > at all. Exactly, and that is the usual case. But there are cases where you want to have several very similar methods/functions/operations (choose your term) that are slightly different. In Ada you can do this tailoring with generic formal subprogram parameters. For a hackneyed example say you want to write a Runge-Kutta integration routine. It is nice to be able to make it a generic (with respect to the type of the integrand) and to call it with values for the function to be integrated and the bounds. In Ada you get to choose between THREE places where parameters and methods can be fixed: At the point where generic definition appears, at the point where the generic instantiation occurs, and at the point of the call. The "tricky bit" is that you can also have overridable defaults bound at any of those three locations. I don't know why you would want to provide a RK routine where the default number of steps was set during instantiation, but you can do it if you want to. > If you were writing this now in Ada95, would you be able to reduce > the complexity by using OO stuff? No, and no! First, the complexity is not in the code, it is in the understanding of the requirements. Second, if those are the requirements, the same solution is probably the simplest in Ada 83 and Ada 95. This is a symptom of a general problem for OO programmers learning Ada. In Ada generics are often a much simpler, and hugely more maintainable solution to many problems that can only be solved with inheritance in other OO languages. As a result in well written Ada 95 code, it is rare for a class to have grandchildren. (Hmmm. Better stated as almost all grandchildren are descended from Controlled or Limited_Controlled.) But it is not uncommon for a derived tagged type declaration to be followed by several generic instantiations that would have be done in some other languages by multiple inheritance. My favorite illustration of this uses lists. In Ada if you create a class by specialization, and want to be able to make lists of the members you will almost certainly use a generic. In other languages you would inherit from both the general class and a list class. Is this because you can't do it the other way? No, it is because it usually turns out to be cleaner to have both list objects and objects which can be members of lists. Ada makes it easy to do this, and without loss of generality in the list class, so that is usually the best way to do it. (Why is it better to have two types? Overloading again. If the types are different, then it is possible to provide (with one, one-line instantiation) among other operations: function "&" (L,R: Element) return List; function "&" (L: Element; R: List) return List; function "&" (L: List; R: Element) return List; function "&" (L,R: List) return List; ...and get the expected semantics. If the types are the same, then there is no way to distinguish between a list containing one element and an element. > I'll interpret 'powerful' to mean 'esoteric'. :) No, I meant powerful. Just like working with rocket fuel or high-voltage electicity or what have you. When you are working with constructs where the change of one word, say a parameter name, can have a global effect on modules which never use that name, you have to use design principles and configuration manangement tools very different from the run of the mill. (Just so I don't scare anyone off, what I usually do is when overloading operations or overriding methods, I use the same parameter names. This makes it clear that you never intend to use parameter names in overload resolution, just to match parameter values to formals.) -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is...