comp.lang.ada
 help / color / mirror / Atom feed
From: "Randy Brukardt" <randy@rrsoftware.com>
Subject: Re: Studying and Maintaining GNAT, Is There Any Interest in a New Group?
Date: Fri, 31 Aug 2018 17:42:54 -0500
Date: 2018-08-31T17:42:54-05:00	[thread overview]
Message-ID: <pmcg9f$7tv$1@franka.jacob-sparre.dk> (raw)
In-Reply-To: pmavco$u5d$1@gioia.aioe.org

"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> 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. (:-))

<Grin>.

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.


  reply	other threads:[~2018-08-31 22:42 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-25 12:27 Studying and Maintaining GNAT, Is There Any Interest in a New Group? patrick
2018-08-25 13:56 ` Dan'l Miller
2018-08-25 16:00   ` patrick
2018-08-25 16:16 ` Luke A. Guest
2018-08-25 17:42   ` patrick
2018-08-25 19:25     ` Simon Wright
2018-08-25 20:24       ` patrick
2018-08-25 21:48         ` Luke A. Guest
2018-08-25 21:53           ` patrick
2018-08-25 22:05             ` Luke A. Guest
2018-08-26 19:54           ` Dan'l Miller
2018-08-26 20:14             ` Dan'l Miller
2018-08-26 22:52             ` Lucretia
2018-08-27  2:38               ` Dan'l Miller
2018-08-27 14:46                 ` Lucretia
2018-08-27 15:42                   ` Dan'l Miller
2018-08-27 21:27               ` Randy Brukardt
2018-08-28  7:26                 ` Dmitry A. Kazakov
2018-08-29  0:16                   ` Randy Brukardt
2018-08-29  8:20                     ` Dmitry A. Kazakov
2018-08-29 21:43                       ` Randy Brukardt
2018-08-30  7:55                         ` Dmitry A. Kazakov
2018-08-30 23:25                           ` Randy Brukardt
2018-08-31  8:48                             ` Dmitry A. Kazakov
2018-08-31 22:42                               ` Randy Brukardt [this message]
2018-09-02  8:02                                 ` Dmitry A. Kazakov
2018-09-04 22:18                                   ` Randy Brukardt
2018-08-29  3:02                 ` Paul Rubin
2018-08-29  6:18                   ` Luke A. Guest
2018-08-29 19:00                     ` Paul Rubin
2018-08-30  5:54                       ` Luke A. Guest
2018-08-30  6:29                         ` Paul Rubin
2018-08-27 21:18             ` Randy Brukardt
2018-08-27  9:37           ` Simon Wright
2018-08-27 16:54             ` Bill Findlay
2018-08-27 17:42               ` Shark8
2018-08-31 21:23                 ` Robert A Duff
2018-08-31 22:51                   ` Randy Brukardt
2018-09-01 19:42                     ` Robert A Duff
2018-09-02  8:04                       ` Dmitry A. Kazakov
2018-09-02 10:11                     ` AdaMagica
2018-09-02 12:10                       ` Jeffrey R. Carter
2018-09-02 14:30                         ` AdaMagica
2018-09-04 22:05                           ` Randy Brukardt
2018-09-01  7:41               ` Simon Wright
2018-09-01 17:27                 ` Bill Findlay
2018-08-27 17:35         ` Shark8
2018-08-25 21:17       ` Luke A. Guest
2018-08-25 23:16       ` Paul Rubin
2018-08-26  8:03         ` Rene
2018-08-26 10:09         ` Simon Wright
2018-08-25 16:43 ` Jeffrey R. Carter
2018-08-25 17:38   ` patrick
2018-08-25 17:39     ` Luke A. Guest
2018-08-25 17:45       ` patrick
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox