comp.lang.ada
 help / color / mirror / Atom feed
* What's it's name again?
@ 2002-07-29 23:13 chris.danx
  2002-07-29 23:32 ` Larry Elmore
  2002-07-29 23:47 ` Robert A Duff
  0 siblings, 2 replies; 11+ messages in thread
From: chris.danx @ 2002-07-29 23:13 UTC (permalink / raw)


Hi,

What do you call private types whose declaration is found in the 
specification but whose definition is found in the body?  I remember 
reading/hearing that they have a name (or term) associated with them, 
but can't remember what it is.

Are there any complications with moving type definitions to the body? 
(e.g. with controlled types?).  Cohens' book is at the ready, just need 
their name or a pointer!


I currently have some packages which look like

   package some_kind_of_data_structure is

     type data_structure is private;

   private

     type data_structure is Ada.Finalized.Controlled with record
       ...
     end record;

   end some_data_structure;

but have been wondering what would happen if the definitions were moved 
(the obvious benefit is that the package specification does not need to 
be recompiled when the representation is changed, but is that really a 
benefit when small numbers of files are involved?)

This kind of design was mentioned in passing in a Software Design 
course, and I wondered why people prefer one way over the other (most of 
the ada code I've seen uses the spec to complete the definition of a 
type).  Just curious, that's all!


Regards,
Chris

-- 

to reply change 'spamoff' to 'chris'




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-29 23:13 What's it's name again? chris.danx
@ 2002-07-29 23:32 ` Larry Elmore
  2002-07-30  0:08   ` chris.danx
  2002-07-29 23:47 ` Robert A Duff
  1 sibling, 1 reply; 11+ messages in thread
From: Larry Elmore @ 2002-07-29 23:32 UTC (permalink / raw)


chris.danx wrote:
> Hi,
> 
> What do you call private types whose declaration is found in the 
> specification but whose definition is found in the body?  I remember 
> reading/hearing that they have a name (or term) associated with them, 
> but can't remember what it is.
> 
> Are there any complications with moving type definitions to the body? 
> (e.g. with controlled types?).  Cohens' book is at the ready, just need 
> their name or a pointer!

I think what you want is covered in 11.2 of Cohen (p. 465 in my copy), 
and they're called incomplete type declarations.

I'm re-learning Ada and just happened to cover that section last night. :)

--Larry




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-29 23:13 What's it's name again? chris.danx
  2002-07-29 23:32 ` Larry Elmore
@ 2002-07-29 23:47 ` Robert A Duff
  2002-07-30  0:50   ` chris.danx
                     ` (2 more replies)
  1 sibling, 3 replies; 11+ messages in thread
From: Robert A Duff @ 2002-07-29 23:47 UTC (permalink / raw)


"chris.danx" <spamoff.danx@ntlworld.com> writes:

> What do you call private types whose declaration is found in the 
> specification but whose definition is found in the body?  I remember 
> reading/hearing that they have a name (or term) associated with them, 
> but can't remember what it is.

That's not quite legal.  I think you mean a private type completed by an
access type, where the access type points to an incomplete type
completed in the body.  Like this:

    package P is
        type T is private;
    private
        type R; -- completed in body
        type T is access R;
    end P;
    
    package body P is
        type R is
            record
                ...

I call R an "stt incomplete type", and I call T an "stt access type",
named after Tucker Taft (initials "stt"), who invented them around 1982
or so, just before Ada 83 was standardized.  Jean Ichbiah called them
"Taft Amendment Types".

> Are there any complications with moving type definitions to the body? 
> (e.g. with controlled types?).

None other than the fact that you have to have a pointer type involved.
If I need a pointer type anyway, then I use stt access types, but I
don't normally introduce *extra* pointers just to be able to use this
feature.

Introducing extra pointers causes the obvious problems: how do you
allocate and deallocate the pointed-to things?

> I currently have some packages which look like
> 
>    package some_kind_of_data_structure is
> 
>      type data_structure is private;
> 
>    private
> 
>      type data_structure is Ada.Finalized.Controlled with record
>        ...
>      end record;
> 
>    end some_data_structure;
> 
> but have been wondering what would happen if the definitions were
> moved

If you did the obvious thing of moving "type data_structure is
Ada.Finalized.Controlled with record..." to the body, then you would get
an error at compile time.  To make it work, you have to introduce an
incomplete type, and a pointer to it.

> (the obvious benefit is that the package specification does not need to 
> be recompiled when the representation is changed, but is that really a 
> benefit when small numbers of files are involved?)

Yes, that's the obvious benefit, and yes, the benefit depends on how
much code might need to be recompiled.  It could be a lot -- the
transitive closure of the with's of that package spec.

----------------

The main reason normal types need to be completed in the private part
(and not the body) is that the compiler wants to know their size.  For
example, ":=" on a private type needs to know how big it is.  If it were
declared in the body, the size would be a run-time quantity, resulting
in an efficiency hit.  (Consider also, records containing that private
type.  And consider pragma Pack on such records.)

In fact, this sort of thing is the reason for the existence of private
parts.

It's OK for an incomplete type (declared in a *private part*) to be
completed in the body, because, in theory, nobody outside the package
cares about its size.  And pointers to it are always the size of one
address.  (At least that's the theory -- in practise, some compilers
like to have different-sized pointers depending on the designated type,
and stt access types are a headache for them.  Another unexpected
headache is caused by stt-incomplete types that have discriminants.)

Another reason to insist on "normal" types being completed in the
private part might be that the parameter passing mechanism (by copy
vs. by reference) depends on whether the full type is "elementary".  One
would not want that to be a run-time decision.

The whole model here depends on the idea that the compiler can look at
the specs of all with'ed packages (including private parts), but not
their bodies.  Pragma Inline breaks that model, which IMHO makes the
whole model suspect.

- Bob



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-29 23:32 ` Larry Elmore
@ 2002-07-30  0:08   ` chris.danx
  0 siblings, 0 replies; 11+ messages in thread
From: chris.danx @ 2002-07-30  0:08 UTC (permalink / raw)


Larry Elmore wrote:
 > chris.danx wrote:
> 
> I think what you want is covered in 11.2 of Cohen (p. 465 in my copy), 
> and they're called incomplete type declarations.
> 
> I'm re-learning Ada and just happened to cover that section last night. :)

Thanks, that's the right thing.


Chris




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-29 23:47 ` Robert A Duff
@ 2002-07-30  0:50   ` chris.danx
  2002-07-30  8:21   ` Dmitry A. Kazakov
  2002-07-30 18:55   ` Richard Riehle
  2 siblings, 0 replies; 11+ messages in thread
From: chris.danx @ 2002-07-30  0:50 UTC (permalink / raw)


Robert A Duff wrote:
> "chris.danx" <spamoff.danx@ntlworld.com> writes:
> 
> That's not quite legal.  I think you mean a private type completed by an
> access type, where the access type points to an incomplete type
> completed in the body.  

[snip]

I must have misunderstood the code in the course.

> I call R an "stt incomplete type", and I call T an "stt access type",
> named after Tucker Taft (initials "stt"), who invented them around 1982
> or so, just before Ada 83 was standardized.  Jean Ichbiah called them
> "Taft Amendment Types".

:)

[snip loads of useful info]

> The whole model here depends on the idea that the compiler can look at
> the specs of all with'ed packages (including private parts), but not
> their bodies.  Pragma Inline breaks that model, which IMHO makes the
> whole model suspect.

Thanks for that Bob, I understand the issues a bit better now!

The interest in this came from a discussion about coupling & 
encapsulation - it got me thinking about how much information given away 
to developers in the package spec.  If incomplete types are used, 
virtually no information is given to the client developer, but for 
"normal" types the representation of the type is there for the any 
developer to see.  Maybe giving such information leads *some* developers 
to make assumptions about the representation, which may not hold 
throughout the packages lifetime.  Since the types are private, it's not 
a big deal - what information could the developer rely on?  they're 
private after all!

Sometimes I'd just like to be able to say "don't worry about how it 
works, just know that it does and satisfies these requirments, and don't 
peek!". :)


> - Bob

Chris

p.s. I'm not critising Ada :)

-- 
to reply by personal email change 'spamoff' to 'chris'




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-29 23:47 ` Robert A Duff
  2002-07-30  0:50   ` chris.danx
@ 2002-07-30  8:21   ` Dmitry A. Kazakov
  2002-07-30 18:53     ` Robert A Duff
  2002-07-30 18:55   ` Richard Riehle
  2 siblings, 1 reply; 11+ messages in thread
From: Dmitry A. Kazakov @ 2002-07-30  8:21 UTC (permalink / raw)


On Mon, 29 Jul 2002 23:47:38 GMT, Robert A Duff
<bobduff@shell01.TheWorld.com> wrote:

>The whole model here depends on the idea that the compiler can look at
>the specs of all with'ed packages (including private parts), but not
>their bodies.  Pragma Inline breaks that model, which IMHO makes the
>whole model suspect.

I find it too, but simply cannot imagine how one could do it
otherwise. Do you have any idea? 

---
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-30  8:21   ` Dmitry A. Kazakov
@ 2002-07-30 18:53     ` Robert A Duff
  2002-08-01  0:11       ` Dmitry A.Kazakov
  0 siblings, 1 reply; 11+ messages in thread
From: Robert A Duff @ 2002-07-30 18:53 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> On Mon, 29 Jul 2002 23:47:38 GMT, Robert A Duff
> <bobduff@shell01.TheWorld.com> wrote:
> 
> >The whole model here depends on the idea that the compiler can look at
> >the specs of all with'ed packages (including private parts), but not
> >their bodies.  Pragma Inline breaks that model, which IMHO makes the
> >whole model suspect.
> 
> I find it too, but simply cannot imagine how one could do it
> otherwise. Do you have any idea? 

I'm not sure which part you think is hard.  You could put procedure
bodies in specs (like in C++) and make inlining easier.  Or you can put
the completion of private types in the package body, making generation
of efficient code harder.  But not impossible -- the compiler has to
assume the worst (e.g. treat the size of a private type as a dynamic
quantity, or else peek into the body.

The issue is that in order to generate efficient code, the compiler
needs to see some part of the "implementation" of something.  In the
case of a type, the compiler would often like to know the size of that
type (if static), so it can allocate variables and record components and
whatnot efficiently.  In the case of a procedure, the most efficient
implementation is sometimes inlined code, so the compiler needs to see
the procedure body.

I'm assuming the language supports some sort of separate interface
vs. implementation.  By "separate" I mean some combination of "stored in
separate source files" and "split clearly syntactically" and "processed
separately by the compiler."  (The Ada RM doesn't say anything about
source files, but it heavily implies some things, and this issue is
important: one would like the CM system to control interface and
implementation separately.)

But we don't want to include this efficiency information in the
interface definition (the "spec", in Ada).

Types and procedures are the main thing, but there are other analogous
features: e.g., you don't want the *value* of a deferred constant to be
part of the spec, but you want the compiler to take advantage of that
value, if it can.

There are several possible solutions.  My objection in the Ada case is
lack of uniformity -- solving two similar problems with completely
different solutions.  That is, the "private type" solution is different
from the "pragma inline" solution.

Here are the solutions that come to mind:

1. Make the private information part of the spec.  This is what Ada does
   for private types -- the compiler can see the full type declaration.
   This is also what C++ uses for the inlined-call case: to inline
   something, you include the "body" in the "spec" of the class.
   (Please correct me if my memory of C++ is hazy.)

2. Put the private info in the body.  But let the compiler "peek" into
   the body in some cases (pragma Inline present, inlining-enabled
   switch turned on, phase of moon is blue, etc).  This is what Ada does
   for the inlined-call case.  I would claim Ada *could* do something
   similar for the private type case.  (Note that in languages where
   "everything's a pointer", you get this kind of (lack of) efficiency.)

   This idea seems nice in that it gives the programmer control over the
   compile-time speed vs. run-time speed trade-off.  (By the way, I
   claim that computers are many years away from being so fast that this
   tradeoff doesn't matter.  Especially since every hardware gain is
   offset by more software bloat.)

3. Define packages as *three* parts: the interface, the
   efficiency-critical parts of the implementation, and the
   implementation.
   The second part is really the "private part" of Ada, but split
   out into a separate syntactic unit (probably in a separate file).
   In the traditional Ada compiler dependency setup, a change to the
   second part would trigger recompilation of all with-ing compilation
   units.

I claim that any of these 3 possibilities is suitable for the
private-type case, and the inline-procedure case, and every other case.
I also claim that it would simplify the language to choose one of the
above, and use it for all such interface-vs-impl kinds of features.

I lean toward 2, but 3 also has merit.  Number 1, as in Ada private
types, has a severe disadvantage: you can't put the full type in a
different file from the private type.  It doesn't get a different
revision number in the CM system.  And if you have multiple versions
(say, for different target hardware), you have to duplicate the visible
part.

- Bob



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-29 23:47 ` Robert A Duff
  2002-07-30  0:50   ` chris.danx
  2002-07-30  8:21   ` Dmitry A. Kazakov
@ 2002-07-30 18:55   ` Richard Riehle
  2 siblings, 0 replies; 11+ messages in thread
From: Richard Riehle @ 2002-07-30 18:55 UTC (permalink / raw)


The question about completing an incomplete type in the package
body has lots of interesting history.   The name is, opaque type, and
it comes from Modula-2.

If Ada had followed the Modula-2 language design, there would
be no private part in the package specification (Modula-2's Definition
Module).   All complete type definitions would be in the package
body (Implementation Module).

This design decsion created a problem for Modula-2 when trying
to do separate compilations.   The Modula-2 solution was to create
"opaque types" that were referenced through a pointer mechanism.
Modula-3 continues to follow some of the Modula-2 rules but simplifies
this feature with some new language syntax.

Ada's solution was to include a private part in the specification.  This
allowed the compiler developers enough information to do separate
compilation at the specification level without resorting to opaque
types.

The example below, contributed by Robert Duff, is an example of
creating an opaque type in Ada.    This idiom is becoming more and
more common in reusable components at some of our client sites.

With Ada 83, opaque types were not too problematic.   With the
need for extensible types in Ada 95 a new problem arose: how
to create extensible opaque types?   There is a solution to this
problem, but it requires additional levels of indirection.  I am
including some sample code at the end of this message for
anyone who wants to play with it.



Robert A Duff wrote:

> "chris.danx" <spamoff.danx@ntlworld.com> writes:
>
> > What do you call private types whose declaration is found in the
> > specification but whose definition is found in the body?  I remember
> > reading/hearing that they have a name (or term) associated with them,
> > but can't remember what it is.
>
> That's not quite legal.  I think you mean a private type completed by an
> access type, where the access type points to an incomplete type
> completed in the body.  Like this:
>
>     package P is
>         type T is private;
>     private
>         type R; -- completed in body
>         type T is access R;
>     end P;
>
>     package body P is
>         type R is
>             record
>                 ...
>
> I call R an "stt incomplete type", and I call T an "stt access type",
> named after Tucker Taft (initials "stt"), who invented them around 1982
> or so, just before Ada 83 was standardized.  Jean Ichbiah called them
> "Taft Amendment Types".
>
> > Are there any complications with moving type definitions to the body?
> > (e.g. with controlled types?).
>
> None other than the fact that you have to have a pointer type involved.
> If I need a pointer type anyway, then I use stt access types, but I
> don't normally introduce *extra* pointers just to be able to use this
> feature.
>
> Introducing extra pointers causes the obvious problems: how do you
> allocate and deallocate the pointed-to things?
>
> > I currently have some packages which look like
> >
> >    package some_kind_of_data_structure is
> >
> >      type data_structure is private;
> >
> >    private
> >
> >      type data_structure is Ada.Finalized.Controlled with record
> >        ...
> >      end record;
> >
> >    end some_data_structure;
> >

From Richard Riehle.

This code will compile, but we don't have it totally
implemented in this sample.    You can implement
the Controlled type procedures as you wish, and don't
forget to handle potential memory leaks.


First we show the package body.

-- Example of an Opaque Controlled Type
-- Author:  Richard Riehle,   AdaWorks Software Engineering
-- Permission to use this as you wish for any purpose at all.
with Ada.Finalization;
use  Ada;
package Opaque_Tagged_Type is

   type Opaque is tagged private;

   procedure Create     (Data : in out Opaque);

private

  type Opaque_Data;
  type Data_Reference is access all Opaque_Data;
  type Opaque is new Ada.Finalization.Controlled with
     record
        Value : Data_Reference;
     end record;

  procedure Initialize(Data : in out Opaque);
  procedure Finalize  (Data : in out Opaque);
  procedure Adjust    (Data : in out Opaque);

end Opaque_Tagged_Type;

-- ======================================================

Now we provide the stubbed-out code for the package body.

package body Opaque_Tagged_Type is

   type Opaque_Data is new Ada.Finalization.Controlled with record
       X : Integer;
       Y : Integer;
   end record;

   procedure Initialize(Data : in out Opaque_Data);
   procedure Finalize  (Data : in out Opaque_Data);
   procedure Adjust    (Data : in out Opaque_Data);

   procedure Create(Data : in out Opaque) is
      Temp : Data_Reference := new Opaque_Data'(Ada.Finalization.Controlled
                                                with X => 0, Y => 0);
   begin
      Data.Value := Temp;
   end Create;


   procedure Initialize (Data : in out Opaque) is
   begin
      Data.Value.X := 0;
      Data.Value.Y := 0;
   end Initialize;

   procedure Finalize  (Data : in out Opaque)is
   begin
      null;
   end Finalize;


   procedure Adjust    (Data : in out Opaque)is
   begin
      null;
   end Adjust;

      procedure Initialize (Data : in out Opaque_Data) is
   begin
      null;
   end Initialize;

   procedure Finalize  (Data : in out Opaque_Data)is
   begin
      null;
   end Finalize;


   procedure Adjust    (Data : in out Opaque_Data)is
   begin
      null;
   end Adjust;

end Opaque_Tagged_Type;








^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-08-01  0:11       ` Dmitry A.Kazakov
@ 2002-07-31 20:38         ` Robert A Duff
  2002-08-02  2:21           ` Dmitry A.Kazakov
  0 siblings, 1 reply; 11+ messages in thread
From: Robert A Duff @ 2002-07-31 20:38 UTC (permalink / raw)


Dmitry A.Kazakov <mailbox@dmitry-kazakov.de> writes:

> > I'm not sure which part you think is hard.  You could put procedure
> > bodies in specs (like in C++) and make inlining easier.
> 
> C++ is awful! All that idiotic rules that inlined function are compiled as 
> if all class declarations were appear before the function body. Then header 
> files of 1K+ lines long ...

I'm not familiar with the details of these rules.  I'm willing to
believe that they are awful.

> I see, but there is also a difference. The body of a subroutine is not a 
> part of its declaration, so you can continue compilation of specifications 
> no matter how the body looks like.

Not if you're trying to inline the code.

>... In contrary to this the size of a type 
> is a function of its declaration. So there might be no difference when some 
> other comilation unit is being compiled, but for a compilation the 
> package's specification I think there is a difference.

I don't see any difference, in principle.  If the compiler doesn't know
the size of the type, it has to generate less efficient code.

> > Here are the solutions that come to mind:
> > 
> > 1. Make the private information part of the spec.  This is what Ada does
> >    for private types -- the compiler can see the full type declaration.
> >    This is also what C++ uses for the inlined-call case: to inline
> >    something, you include the "body" in the "spec" of the class.
> >    (Please correct me if my memory of C++ is hazy.)
> 
> Something like:
> 
> package ... is
>    ...
>    procedure Foo; -- To be inlined (no extra pragma)
>    ...
> private
>    ...
>    procedure Foo is -- Implementation here
>    begin
>       ...
>    end Foo;
>    ...

Yes, something like that.  This is essentially what C++ does for
inlining.

> There is a problem that Foo will see no package body, which might contain 
> some implementation-dependent things it needs.

Everything Foo references must *also* be moved to the spec for this idea
to work.  That's annoying, but it is not in principle different from the
fact that everything a private type refers to must be in the spec:

    type T is private;
    
    ...
    Max: constant := 1234;
    type My_Int is range 1..Max;
    function F return My_Int;
    type T is
        record
            X: My_Int := F(...);

Because Ada requires the full type of T to occur in the spec, it also
implicitly requires Max, My_Int, and F to be declared in the spec.

> > 2. Put the private info in the body.  But let the compiler "peek" into
> >    the body in some cases (pragma Inline present, inlining-enabled
> >    switch turned on, phase of moon is blue, etc).  This is what Ada does
> >    for the inlined-call case.  I would claim Ada *could* do something
> >    similar for the private type case.  (Note that in languages where
> >    "everything's a pointer", you get this kind of (lack of) efficiency.)
> > 
> >    This idea seems nice in that it gives the programmer control over the
> >    compile-time speed vs. run-time speed trade-off.  (By the way, I
> >    claim that computers are many years away from being so fast that this
> >    tradeoff doesn't matter.  Especially since every hardware gain is
> >    offset by more software bloat.)
> 
> Sort of pragma Inline for incomplete types and values (deferred constants)? 

Yeah.

> Do you think it is technically possible?

Yes.  It would cause some pretty slow code without the Inline_Type, but
that's the programmer's choice (compile-time efficiency vs run-time
efficiency).

>... I has not much thought about it, 
> but we must ensure absence of any circular dependencies, which could 
> prevent compiler from calculation of the object size.

Yes.  Ada already has a rule that type T cannot have a [sub]component of
type T (the programmer has to insert a level of indirection).  This rule
would have to be removed, because the compiler doesn't always see the
full type.  This would mean that the *compiler* would be responsible for
inserting the extra level of indirection.  (This is similar to what
happens in Java and other "everything's a pointer" sorts of languages --
in those languages, there is *always* an extra level of indirection.)

Another problem is parameter passing mechanisms.  Ada defines it to be
by-copy for some types, by-reference for some types, and compiler-choice
for some types.  It would be pretty disgusting (from an efficiency point
of view) if this choice had to be made at run time.  But this is an
Ada-specific issue.  I don't like the Ada rules here, and we're talking
about languae design (an Ada-like language that is not Ada), so it's
fair for me to ignore this issue.

> > 3. Define packages as *three* parts: the interface, the
> >    efficiency-critical parts of the implementation, and the
> >    implementation.
> >    The second part is really the "private part" of Ada, but split
> >    out into a separate syntactic unit (probably in a separate file).
> >    In the traditional Ada compiler dependency setup, a change to the
> >    second part would trigger recompilation of all with-ing compilation
> >    units.
> 
> This is attractive, because with tagged types [especially when you need to 
> add some public and some private components] the specifications get too 
> long. It is also good because then one could require that the compiler 
> never ever looks in *.adb. But does not it also suffer the problem of 
> not-seeing *.adb?

No big problem -- as I said above, it just means that everything
referenced in the second part (transitively) has to be declared in the
second part.  Not necessarily their "bodies" (or "full types"), unless
you want *those* inlined, too.  No such thing as a free lunch.  ;-)

> > I claim that any of these 3 possibilities is suitable for the
> > private-type case, and the inline-procedure case, and every other case.
> > I also claim that it would simplify the language to choose one of the
> > above, and use it for all such interface-vs-impl kinds of features.
> > 
> > I lean toward 2, but 3 also has merit.  Number 1, as in Ada private
> > types, has a severe disadvantage: you can't put the full type in a
> > different file from the private type.  It doesn't get a different
> > revision number in the CM system.  And if you have multiple versions
> > (say, for different target hardware), you have to duplicate the visible
> > part.
> 
> What if to allow something like:
> 
> package X
>    ...
> private is separate;
> end X;
> 
> Then there should be X-XX.ads containing a completion of X.

Right.  I think I remember the GNAT folks talking about implementing
something like this.  The idea was that the RM doesn't define the
"source representation" of compilation_units, so there's nothing wrong
with an implementation allowing (or requiring?!) the private part to be
in a different file.  Good idea, but if the language were designed with
that in mind, it would work more smoothly in practise.

The language heavily *implies* that each compilation_unit be represented
as a contiguous piece of text in one file.  For example, the private
part syntax doesn't include the package name at the front.

Also, there's the issue of with_clauses.  It would be nice to attach
with_clauses to the private_part.

- Bob



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-30 18:53     ` Robert A Duff
@ 2002-08-01  0:11       ` Dmitry A.Kazakov
  2002-07-31 20:38         ` Robert A Duff
  0 siblings, 1 reply; 11+ messages in thread
From: Dmitry A.Kazakov @ 2002-08-01  0:11 UTC (permalink / raw)


Robert A Duff wrote:

> Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>> On Mon, 29 Jul 2002 23:47:38 GMT, Robert A Duff
>> <bobduff@shell01.TheWorld.com> wrote:
>> 
>> >The whole model here depends on the idea that the compiler can look at
>> >the specs of all with'ed packages (including private parts), but not
>> >their bodies.  Pragma Inline breaks that model, which IMHO makes the
>> >whole model suspect.
>> 
>> I find it too, but simply cannot imagine how one could do it
>> otherwise. Do you have any idea?
> 
> I'm not sure which part you think is hard.  You could put procedure
> bodies in specs (like in C++) and make inlining easier.

C++ is awful! All that idiotic rules that inlined function are compiled as 
if all class declarations were appear before the function body. Then header 
files of 1K+ lines long ...

> Or you can put
> the completion of private types in the package body, making generation
> of efficient code harder.  But not impossible -- the compiler has to
> assume the worst (e.g. treat the size of a private type as a dynamic
> quantity, or else peek into the body.
> 
> The issue is that in order to generate efficient code, the compiler
> needs to see some part of the "implementation" of something.  In the
> case of a type, the compiler would often like to know the size of that
> type (if static), so it can allocate variables and record components and
> whatnot efficiently.  In the case of a procedure, the most efficient
> implementation is sometimes inlined code, so the compiler needs to see
> the procedure body.
> 
> I'm assuming the language supports some sort of separate interface
> vs. implementation.  By "separate" I mean some combination of "stored in
> separate source files" and "split clearly syntactically" and "processed
> separately by the compiler."  (The Ada RM doesn't say anything about
> source files, but it heavily implies some things, and this issue is
> important: one would like the CM system to control interface and
> implementation separately.)
> 
> But we don't want to include this efficiency information in the
> interface definition (the "spec", in Ada).
> 
> Types and procedures are the main thing, but there are other analogous
> features: e.g., you don't want the *value* of a deferred constant to be
> part of the spec, but you want the compiler to take advantage of that
> value, if it can.
> 
> There are several possible solutions.  My objection in the Ada case is
> lack of uniformity -- solving two similar problems with completely
> different solutions.  That is, the "private type" solution is different
> from the "pragma inline" solution.

I see, but there is also a difference. The body of a subroutine is not a 
part of its declaration, so you can continue compilation of specifications 
no matter how the body looks like. In contrary to this the size of a type 
is a function of its declaration. So there might be no difference when some 
other comilation unit is being compiled, but for a compilation the 
package's specification I think there is a difference.

> Here are the solutions that come to mind:
> 
> 1. Make the private information part of the spec.  This is what Ada does
>    for private types -- the compiler can see the full type declaration.
>    This is also what C++ uses for the inlined-call case: to inline
>    something, you include the "body" in the "spec" of the class.
>    (Please correct me if my memory of C++ is hazy.)

Something like:

package ... is
   ...
   procedure Foo; -- To be inlined (no extra pragma)
   ...
private
   ...
   procedure Foo is -- Implementation here
   begin
      ...
   end Foo;
   ...

There is a problem that Foo will see no package body, which might contain 
some implementation-dependent things it needs.
 
> 2. Put the private info in the body.  But let the compiler "peek" into
>    the body in some cases (pragma Inline present, inlining-enabled
>    switch turned on, phase of moon is blue, etc).  This is what Ada does
>    for the inlined-call case.  I would claim Ada *could* do something
>    similar for the private type case.  (Note that in languages where
>    "everything's a pointer", you get this kind of (lack of) efficiency.)
> 
>    This idea seems nice in that it gives the programmer control over the
>    compile-time speed vs. run-time speed trade-off.  (By the way, I
>    claim that computers are many years away from being so fast that this
>    tradeoff doesn't matter.  Especially since every hardware gain is
>    offset by more software bloat.)

Sort of pragma Inline for incomplete types and values (deferred constants)? 
Do you think it is technically possible? I has not much thought about it, 
but we must ensure absence of any circular dependencies, which could 
prevent compiler from calculation of the object size.

> 3. Define packages as *three* parts: the interface, the
>    efficiency-critical parts of the implementation, and the
>    implementation.
>    The second part is really the "private part" of Ada, but split
>    out into a separate syntactic unit (probably in a separate file).
>    In the traditional Ada compiler dependency setup, a change to the
>    second part would trigger recompilation of all with-ing compilation
>    units.

This is attractive, because with tagged types [especially when you need to 
add some public and some private components] the specifications get too 
long. It is also good because then one could require that the compiler 
never ever looks in *.adb. But does not it also suffer the problem of 
not-seeing *.adb?

> I claim that any of these 3 possibilities is suitable for the
> private-type case, and the inline-procedure case, and every other case.
> I also claim that it would simplify the language to choose one of the
> above, and use it for all such interface-vs-impl kinds of features.
> 
> I lean toward 2, but 3 also has merit.  Number 1, as in Ada private
> types, has a severe disadvantage: you can't put the full type in a
> different file from the private type.  It doesn't get a different
> revision number in the CM system.  And if you have multiple versions
> (say, for different target hardware), you have to duplicate the visible
> part.

What if to allow something like:

package X
   ...
private is separate;
end X;

Then there should be X-XX.ads containing a completion of X.

-- 
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: What's it's name again?
  2002-07-31 20:38         ` Robert A Duff
@ 2002-08-02  2:21           ` Dmitry A.Kazakov
  0 siblings, 0 replies; 11+ messages in thread
From: Dmitry A.Kazakov @ 2002-08-02  2:21 UTC (permalink / raw)


Robert A Duff wrote:

> Dmitry A.Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>> I see, but there is also a difference. The body of a subroutine is not a
>> part of its declaration, so you can continue compilation of
>> specifications no matter how the body looks like.
> 
> Not if you're trying to inline the code.

In a specification? OK if the function is called to determine a 
constraint for some subtype, should that be made legal...

>>... In contrary to this the size of a type
>> is a function of its declaration. So there might be no difference when
>> some other comilation unit is being compiled, but for a compilation the
>> package's specification I think there is a difference.
> 
> I don't see any difference, in principle.  If the compiler doesn't know
> the size of the type, it has to generate less efficient code.

The question is how big will be the impact. If a function is not inlined it 
is not a disaster. If objects will be allocated in the heap instead of 
stack and all that depending on things looking very innocent to an 
untrained eye?

>> There is a problem that Foo will see no package body, which might contain
>> some implementation-dependent things it needs.
> 
> Everything Foo references must *also* be moved to the spec for this idea
> to work.  That's annoying, but it is not in principle different from the
> fact that everything a private type refers to must be in the spec:

This means that a decision to inline or not should be met very early. 
Presently it is just an option that has no big impact on the design.

>>... I has not much thought about it,
>> but we must ensure absence of any circular dependencies, which could
>> prevent compiler from calculation of the object size.
> 
> Yes.  Ada already has a rule that type T cannot have a [sub]component of
> type T (the programmer has to insert a level of indirection).  This rule
> would have to be removed, because the compiler doesn't always see the
> full type.  This would mean that the *compiler* would be responsible for
> inserting the extra level of indirection.  (This is similar to what
> happens in Java and other "everything's a pointer" sorts of languages --
> in those languages, there is *always* an extra level of indirection.)

In other words, all types completed in the package body are wrapped by 
pointers. Would not it be easier to make sort of transparent pointers?

package ... is
   type X is access all; -- Do not know which target type
   procedure Foo (A : X); -- A primitive operation
   ...
end ...;

package body ... is
   type T is ...;
   type X renames access all T;
   ...
end ...;

Then for a transparent pointer any its use is an equivalent to ".all".

> Another problem is parameter passing mechanisms.  Ada defines it to be
> by-copy for some types, by-reference for some types, and compiler-choice
> for some types.  It would be pretty disgusting (from an efficiency point
> of view) if this choice had to be made at run time. But this is an
> Ada-specific issue.  I don't like the Ada rules here, and we're talking
> about languae design (an Ada-like language that is not Ada), so it's
> fair for me to ignore this issue.

You mean, that wrapped pointers are always by-copy no matter what is the 
target type? That's OK.

> Also, there's the issue of with_clauses.  It would be nice to attach
> with_clauses to the private_part.

Oh, yes.

-- 
Regards,
Dmitry Kazakov
www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2002-08-02  2:21 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-29 23:13 What's it's name again? chris.danx
2002-07-29 23:32 ` Larry Elmore
2002-07-30  0:08   ` chris.danx
2002-07-29 23:47 ` Robert A Duff
2002-07-30  0:50   ` chris.danx
2002-07-30  8:21   ` Dmitry A. Kazakov
2002-07-30 18:53     ` Robert A Duff
2002-08-01  0:11       ` Dmitry A.Kazakov
2002-07-31 20:38         ` Robert A Duff
2002-08-02  2:21           ` Dmitry A.Kazakov
2002-07-30 18:55   ` Richard Riehle

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