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=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!feeder.eternal-september.org!gandalf.srv.welterde.de!news.jacob-sparre.dk!franka.jacob-sparre.dk!pnx.dk!.POSTED.rrsoftware.com!not-for-mail From: "Randy Brukardt" Newsgroups: comp.lang.ada Subject: Re: Studying and Maintaining GNAT, Is There Any Interest in a New Group? Date: Fri, 31 Aug 2018 17:42:54 -0500 Organization: JSA Research & Innovation Message-ID: References: <309225242.556906218.575482.laguest-archeia.com@nntp.aioe.org> <2145221813.556924687.162377.laguest-archeia.com@nntp.aioe.org> <3892c779-2924-405c-b88d-19389fc5ba3e@googlegroups.com> <1ceec6d8-c5c4-49b1-9808-a3580bba3f8e@googlegroups.com> Injection-Date: Fri, 31 Aug 2018 22:42:55 -0000 (UTC) Injection-Info: franka.jacob-sparre.dk; posting-host="rrsoftware.com:24.196.82.226"; logging-data="8127"; mail-complaints-to="news@jacob-sparre.dk" X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.5931 X-RFC2646: Format=Flowed; Response X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.7246 Xref: reader02.eternal-september.org comp.lang.ada:54304 Date: 2018-08-31T17:42:54-05:00 List-Id: "Dmitry A. Kazakov" wrote in message news:pmavco$u5d$1@gioia.aioe.org... > On 2018-08-31 01:25, Randy Brukardt wrote: > >> They are primitive. That's what forces writing the traversal code into >> every >> operation. Consider the following node: >> type Root_Node is abstract tagged null record; >> type Expr_Tree_Access is access Root_Node'Class; >> >> procedure Fold (Expr : in out Root_Node); -- Fold the tree. >> >> type Binop is new Root_Node with record >> Kind : Op; >> Left, Right : Expr_Tree_Access; >> end record; >> >> and the implementation of the Folding operation: >> overriding >> procedure Fold (Expr : in out Binop); >> >> procedure Fold (Expr : in out Binop) is >> begin >> Fold (Expr.Left.all); >> Fold (Expr.Right.all); >> -- If Expr.Left and Expr.Right are constants, calculate the >> folded value. >> end Fold; >> >> This operation has to do recursive (dispatching calls) on the children. >> And >> so does every other such operation that gets defined (dozens). > > Why isn't Fold class-wide: > > procedure Fold (Expr : in out Binop'Class) is > begin > Fold (Expr.Left.all); > Fold (Expr.Right.all); > Expr.Evaluate; -- This dispatches to the Op's implementation > end Fold; There's not one "evaluate" operation here; there are 6 different phases of tree operations (construction, lookup, resolution, checking, folding, and conversion to low-level IR). Most of these have to be separate because of various Ada rules (for instance, we used to do lookup as part of construction, but it has to be deferred for expressions in pragmas and aspect definitions). One walks the tree at least these times (and more if the tree has to be persisted -- for instance, if it is a default expression in a specification). > BTW, I prefer to fold constants before generating the tree. I.e. when > Evaluate is called it returns either a value ("constant" node) or a new > "dynamic" node. In Ada, you can't do folding until you know what the operations are, and you don't know that until after resolution (that is, "*" could be predefined, which you can fold, or user-defined, which you probably can't fold, and certainly can't treat as static). >>> As a general observation, anything you can do with subtypes of a single >>> type you can also do with a class of a types hierarchy. [There could be >>> some obstacles regarding indefinite vs definite types, but they usually >>> apply to both designs.] >> >> This is true, you just have to write 3 times as much code to make the OO >> design work. And you lose the ability to do agile programming, because >> you >> have to implement so much new code to add a new node or operation >> (probably >> on the order of a week for either in an Ada compiler perspective -- >> dozens >> of operations and dozens of node types are needed there). > > You would possibly save a comparable number of source lines in clients. That wasn't my experience with CBuild, but that's only a single example (and not a compiler, either). >>>> Umm, we're talking about a compiler, and there never is a "final" >>>> version >>>> of a compiler. >>> >>> Final = deployed, of course. >> >> Which is relevant how? It's just a snapshot of a continual evolution. > > Each new release is another program. You might kill the whole package next > time, the code is not stable. With OO I can have stable pieces of code > frozen in separate packages which never change and keep adding volatile > code without rewriting everything each time. Which again is relevant how? You might not have to change some code depending on the code structure, but the number of changes really only matter in true spaggetti code (where everything is everywhere). Expression tree manipulations are only a small part of the compiler (less than 25%, I think). You could make it more by putting statements and declarations into those trees, but that wouldn't buy much and wouldn't add that much code to the tree manipulations, either. A lot of the code is handling the environment (with clauses and the like) as well as symbol table operations. ... >>> 1. To give a contract to this code >>> 2. To refactor and reuse this code >>> 3. To place it in separate compilation units *related* to the types >>> involved. >> >> (1) There is no useful contracts for individual nodes -- all of the >> contracts with any meaning are on the tree as a whole. And it is the >> state >> of the nodes, rather than their kinds, which figure mainly into those >> contracts. (The state being part of the data, not part of the types.) > > But when you fold constants you do that according to the types of the > nodes. The question is if you try to map these types onto Ada types or > not. There's no real types involved here. The actual folding code is quite small, and there's only a handful of node kinds that are even involved. There's simply not enough benefit to extra typing on these things. >> (2) Refactoring isn't any harder with a variant design than it is with a >> OO >> design -- I do those sorts of things all of the time. > > I find using free subprograms more difficult. They have no natural place > to keep in. So I always forget which package holds this or that refactored > subprogram and end up with several instances doing basically same thing. Yes, I agree that's a problem. But it's not a problem with a solution, since almost all compiler operations are cross operations, using symbol table information, expression tree information, and type information to create (three very different and mostly unrelated data structures). Very few of them obviously belong to any particular one, and any choice tends to be arbitrary. ... >> Which does not answer the underlying question: how do you do agile >> development if adding an operation or new kind of node requires 4 days of >> coding? > > I don't buy agile if that means generating false code. When I add an > abstract operation I want the compiler to generate error messages the same > way it does when a new case choice is added. > > BTW, I feel uncomfortable about Ada 2005(?) change that a primitive > function returning the type need not to be always overridden. I do too, but probably for the opposite reason: it's a fragile mechanism tied to a null extension. If you try to program agily, you might very well write the extension first and add the components later. Now you've suddenly got to override a bunch functions that were fine before -- which defeats the purpose of declaring the type first in the first place. This problem is also a substantial one when using generic mix-ins, since the mix-in doesn't know about the functions in question and can't really do so. IMHO, it should work any time all of the components in the extension have well-defined defaults. Then the mix-in case would work with sufficient care, and if you want to force redefinition of everything, just have a component with no default. >> For Ada at least, the only meaningful data structure is the expression >> tree. >> We don't care about the individual nodes outside of a handful of tree >> walking operations. Most everything talks specifically about the tree. > > I'd like to have it reverse, hiding walking and exposing semantics of the > nodes. > >> In any case, I don't expect ever to agree with you on these points. I >> think >> a lot of people take strong typing too far -- but of course the sweet >> spot >> is hard to find. There may be an argument for going further than I do, >> but >> my experience doesn't show much value to that. > > True, I want to push typing and static verification in general as far as > possible. Nothing is too far to me. (:-)) . I have a different vision of static verification than you do; I'm primarily focused on static verification of Ada's dynamic checks. (Since that includes pragma Assert and the like, you can verify almost everything this way.) And I want the compiler to do that - not the least because I would like to show that there are other possible visions for Ada compilers than AdaCore's. (And if it gets people to buy more compilers from me, all the better. :-) Randy.