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.4 required=5.0 tests=BAYES_00,FORGED_MUA_MOZILLA autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,81bb2ce65a3240c3 X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Received: by 10.68.223.40 with SMTP id qr8mr3455846pbc.0.1337117732993; Tue, 15 May 2012 14:35:32 -0700 (PDT) Path: pr3ni2844pbb.0!nntp.google.com!news2.google.com!news3.google.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Niklas Holsti Newsgroups: comp.lang.ada Subject: Re: What would you like in Ada202X? Date: Wed, 16 May 2012 00:35:30 +0300 Organization: Tidorum Ltd Message-ID: References: <3637793.35.1335340026327.JavaMail.geo-discussion-forums@ynfi5> <20780405.1069.1336372385458.JavaMail.geo-discussion-forums@pbkc8> Mime-Version: 1.0 X-Trace: individual.net ny85vgDVsmlMWFnVnX5KXweIuJxKR6BDzmMw/9NXX+RZASCNfvLrU3V0K0cIsjy3BJ Cancel-Lock: sha1:e2u2tkkGrPmFPFyjA9OeXADYhhg= User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:12.0) Gecko/20120428 Thunderbird/12.0.1 In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Date: 2012-05-16T00:35:30+03:00 List-Id: On 12-05-12 03:11 , Randy Brukardt wrote: > "Niklas Holsti" wrote in message > news:a12psmFskuU1@mid.individual.net... >> On 12-05-09 01:22 , Randy Brukardt wrote: >>> "Niklas Holsti" wrote in message >>> news:a0rsroFp8lU1@mid.individual.net... >>>> On 12-05-08 03:48 , Randy Brukardt wrote: >>> ... >>> The details are different, but the basic idea (adding more literals) is >>> unchanged. And the use is in adding more literals, the details on exactly >>> how you do that are much less important. >> >> Perhaps I did not describe it well, but I am surprised that you don't see >> more difference between "widening" and "deepening". Note that: >> >> - The "widening" extension only adds literals. The derived type has all >> literals of the parent type, plus the added literals. >> >> - The "deepening" extension *replaces* some parent literals with new >> literals. The derived type need not have any literals in common with the >> parent type. But each parent-type literal corresponds to a range of >> derived-type literals. >> >> A big difference is that for "widening", there is a natural conversion >> (embedding, really) from the parent type to the derived type, while for >> "deepening" the natural conversion goes the other way, from the derived >> type to the parent type. > > You are thinking like a language lawyer, much less like a user (something > I'm often accused of!). It may look like that, but I was trying to explain that the relationship between the parent enumeration type and the derived enumeration type is quite different in the two cases, and this is important also for the user's point of view -- what the derivation "means" for the user. There is also a large difference in the "grip" that operations of the parent type have on values of the derived type. > I'm not paying all that much attention to the > details of your proposal, Since the difference between "widening" and "deepening" is in these so-called :-) details, I now understand why you don't appreciate the difference. I'm going to continue the thread a bit anyway. > but rather trying to look at it as a user would. > In that case, both mechanisms give a way to add/change enumeration literals > for an existing enumeration type. The widening derivation only adds. The deepening derivation changes, by refining. > I think that's the capability that users > would want -- and I doubt that they care particularly much how it is > accomplished. IMO to "add/change enumeration literals" is an abstraction that is not a good description of what the user needs. (If I may be a bit cheeky, this description seems to be thinking of an enumeration type as just a mapping from literals to integers -- "Want add some literals? No problem, there are plenty of integers left!") I think that there are two quite different "use cases", from the user's point of view, which correspond to "widening" and "deepening" respectively. And I think that the "deepening" case is more worthy of language support than the "widening" case. To make the difference clear-cut, I will limit the "deepening" case to the form that only refines literals, and forget about the bybrid case that emulates AI95-261 by permitting the addition of new literals with no relationship to existing literals in the parent type. THE WIDENING CASE In the first case, which corresponds to "widening", the user finds an existing enumeration type that classifies some set of phenomena, but the user needs to handle a larger set. The user wants an enumeration that incorporates the existing enumeration as a subrange, but in addition has new literals that classify the new phenomena. The author of the existing enumeration type has probably not foreseen that the type would be extended in this way, making this derivation/reuse *opportunistic* rather than planned. Following AI95-261, the user derives a "widened" enumeration type that has some new literals following all the original literals. These new literals have no relationship to the original literals, except that of being different: they represent phenomena that were not considered or even anticipated in the design of the parent enumeration. It is quite unlikely that the operations on the parent type could do anything sensible if given one of the new literals as a parameter, and in fact AI95-261 asks for a Constraint_Error if that is attempted. The user must therefore override all these operations for the "widened" type. At best, the overriding operations can be limited to handling the new literals only, while delegating the original literals to the original parent-type operations. Inheriting the parent-type operations does not help much; it only saves a type conversion in the delegating call. Classwide operations that take Parent'Class have the same problem: they will not know what to do with the added literals. In fact, it feels like nonsense to try; for example, a case statement that lists all the Parent literals, and thus seems complete, is no longer complete if the new literals are considered. THE DEEPENING CASE Here, the user sees the existing (parent) enumeration type as a high-level (general, rough, large-grain) classification of some phenomena, and the user needs a more detailed classification for a particular application. It is likely that the designer of the parent type has made it general and undetailed on purpose. In other words, the parent enumeration type is meant to be extended into a more detailed and specialized type. This derivation/reuse is thus planned, not opportunistic as in the "widening" case. (This is analogous to making a type tagged so that it can be the root of a class.) The user derives the "deepened" enumeration type by refining each literal of the parent type into a set of new literals. These new literals represent subcases of the phenomenon represented by the parent literal. For example, the parent literal Request can be refined into a Read request and a Write request. Both Write and Read "are" Requests, and together (in this example) are all the Requests that exist. Now it makes sense to inherit parent-type operations, because an operation that knows what to do for a Request can do that also for a Read or a Write, since they "are" Requests. To call an inherited parent-type operation with a derived-type "in" parameter the "in" parameter is converted to the corresponding parent literal, and the parent-type operation is called. Case-statements in the parent-type operation are still complete, and the only semantic problems arise if the operation has "out" or "in out" parameters or a return value of the parent type, as has been discussed in this thread earlier. If "deepened" enumeration types are further "deepened", we get a forest of related enumeration types that classify the original root phenomena in more and more detailed ways, possibly on different grounds. For example, the Requests could also be divided into Immediate requests and Delayed requests. In a sense, the enumeration literals at the various levels in such a forest correspond to the tags in a tagged-type hierarchy of the same shape. >>>>> but to be really useful, we >>>>> need the equivalent of class-wide operations. Ok, I have come to agree with you on this, at least if class-wide programming is extended to other non-tagged types like Integer. >>> The problem is untagged types are pretty hard to use. >> >> Do you mean they are hard to use in current Ada, or hard to use with >> class-wide operations in the future Ada? > > I was thinking of derived untagged types; I should have said that. > > The issue is that there is virtually no difference between a derived type > and two unrelated types with conversion functions. If you call the > conversion functions "+" (as some people recommend), you're required to > write one whole additional character when using two unrelated types. True for "in" parameters and function return values, but I think not true for "in out" or "out" parameters, check? A user-defined conversion function cannot convert an "out" or "in out" parameter. > It's > hard to imagine designing the huge mechanism of derived types (with all of > its weird problems and compatibility issues) in order to say typing one > character per use. (One could even say that the extra typing makes the > program more understandable, I'm not sure I'd go that far.) Of course one also saves the other type declaration itself. The advantage gained is the proverbial separation of Apple_Count from Orange_Count. If, instead of counts, these are some complex data structures, declaring them twice as separate types creates redundant, duplicated code. Moreover, the conversion functions can become complex and expensive, and perhaps practically impossible if limited types are involved. I like very much that Ada lets me derive a new type from any type. > The only thing that you can get from derived types that can't be done any > other way is inherit operations (and their interfaces). And that's just > short of useless in Ada; the only use you can make of that is via generic > derived types. I think operation inheritance is useful if the purpose of the derivation is to separate Apple_Count from Orange_Count (for complex types). > (Moreover, once you add operations to untagged derived types, > you can no longer specify their representation, meaning that using them > forces you to give up another key Ada feature.) Ha, I've managed to forget about that one, although I have derived record type just to have different representations for the same record. (As I recall, this was done in a project that had bodyless "types" packages, and so no primitive operations.) From my experience, the need to inherit primitive operations *and* have a different representation for the derived type is rare, so I'm not much bothered by this problem. I'll return to class-wide programming with "deepened" enumerations in a future posting. This one has evolved in my "Drafts" folder long enough :-) -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .