comp.lang.ada
 help / color / mirror / Atom feed
From: Dmitry A.Kazakov <mailbox@dmitry-kazakov.de>
Subject: Re: Dispatching and generics - language lawyer question
Date: Fri, 2 Aug 2002 03:15:07 +0200
Date: 2002-08-02T03:15:07+02:00	[thread overview]
Message-ID: <aibbth$133ln5$1@ID-77047.news.dfncis.de> (raw)
In-Reply-To: wccsn1z1wjj.fsf@shell01.TheWorld.com

Robert A Duff wrote:

> Dmitry A.Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>> [away from Ada 95] There should be only tagged types and no untagged
>> [ones.
>> Then I suppose the formal derived types will do the whole work, because
>> the set of all available operations will be defined by the root type. All
>> types tagged means only that T'Class exists for all but class-wide types.
>> The tag should be kept in the instances of T'Class and class-wide
>> pointers, but not in the values of T, so no performance hit when objects
>> are specific.
> 
> This is a reasonable idea (not new -- I and probably others have thought
> of it before).
> 
> As you imply, there are two ways to implement tags: (1) Store the tag
> with each object.  Then an access value (or a pass-by-reference
> parameter) can be represented as the address of the object.  Or (2),
> do not store the tag with each object, but gin it up when necessary.
> This requires access values and parameters to be a pair -- the tag, plus
> the address of the object.  When you do X'Access, the compiler creates
> the pair.
> 
> Neither method is uniformly better: there are some programs that will be
> more efficient with method (1), and some more efficient with method (2).
> This indicates that the user should have the option.  I would suggest
> the default (in this hypothetical language) should be (2), and a
> per-type pragma could request (1) for that type and its descendants.
> This preserves the Bauer Principle -- if you never say 'Class, you never
> have any overhead for storing or manipulating tags at run time.
> 
> Of course, having options like that complicates compilers.

I think that (1) would cause many problems with MI. When tag is a part of 
the value and then view conversions are problematic.

> For most of the Ada 9X design, either (1) or (2) were feasible (for
> tagged types).  However, a last-minute change to the language made (2)
> infeasible.  Namely, the fact that all tagged parameters are aliased.

There is also redispatch which is IMO incompatible with (1). I think 
redispatch must be removed, because when object identification is really 
necessary (to redispatch) one could use a solution similar to J.-P. Rosen 
trick.

> As far as I know, all existing compilers use (1).
> 
> Note that the distinction between (1) and (2) is analogous to the
> compiler storing array bounds with the array, or with pointers to the
> array.  Neither one is uniformly better.  I believe GNAT allows a user
> choice, and I think all other compilers store bounds with the array
> (analogous to (1)).

Yes. Same with discriminants. I have only a vague idea, that there should 
be way to separate all things like that from values. The goal is of course 
to make arrays, strings etc user-defined types without additional overhead. 
Then of course you should be able to derive from an abstract array and 
provide an implementation which is internally not an array at all. So the 
client will never know.

>> > I'm disappointed that nobody answered my previous question -- what
>> > should the rules about predefined operators in generics be?  I don't
>> > like the current Ada rules (which require reemergence of the "wrong"
>> > operator), but the alternatives are uncomfortable in various ways.
>> > Christoph Grein, or anybody else want to comment?
>> > 
>> > Here's an interesting case: a generic Sort routine, that takes "<" as a
>> > parameter.  (Or it could be called "Less_Than" -- it doesn't matter
>> > what
>> > it's called, or whether it's an operator symbol.)  The Sort routine
>> > might require that the "<" behave in certain ways (like if A<B and B<C
>> > both return True, then A<C should always return True).  Is there any
>> > way
>> > to specify that (other than via comments)?  Is there some way to design
>> > the language so that the generic Sort could formally require such
>> > properties of "<"?
>> 
>> [far away form Ada 95] You should simply have different root types.
>> Transitive_Ordered should be a[!] root type for "all" types with
>> transitive "<". "All" means the types you want to pass the actual
>> parameter. Of course then the language should allow creating supertypes
>> on-fly, because one cannot foresee all possible root types like Ada tries
>> with its classification of formal types. Let Integer is not a descendant
>> of Transitive_Ordered. Then one could create a "proxy" type which is
>> simultaneously a supertype of Integer and a subtype of
>> Transitive_Ordered.
>> [The compiler should check that "<" be implemented.] So Integer would
>> become a subtype Transitive_Ordered in the given context and thus could
>> be used as an actual parameter of the generic. This of course would
>> require MI and dynamically maintained dispatch tables.
> 
> Again, good ideas.  But they don't solve the problem I was thinking of.
> 
> By the way, I don't see why you need dynamically maintained dispatch
> tables.  To me, "on the fly" means "somewhere later in the code" --
> i.e. in some module other than where the type is first declared.
> That need not imply "at run time", I think.
> 
> The notion of dynamically maintained dispatch tables scares me: I hope
> that "<" on type T does not dispatch to different subprogram bodies
> at different times (for the same type tag)!
>
> It seems like adding new operations to a type should only be allowed at
> the same nesting level as the original type declaration.  I shudder to
> think of the run-time overhead of adding an operation in a recursive
> procedure.  ("Adding new op" is essentially the same thing as "adding a
> new parent type", here.)

Yes, I also do not think that one could override in any context without a 
heavy penalty. I think if that would be allowed then no expression would be 
static when used in a subprogram. No, I meant another thing. If a derived 
type is created in some nested context and overrides, say "<", then the 
dispatching table of "<" should be modified once when the type is 
elaborated and restored when the context is finalized.

> But anyway, as you explain below, none of this solves the problem.  The
> compiler checks that "<" exists with the right parameter types, but that
> doesn't *prove* its transitive (whether or not the Transitive_Ordered
> idea is used).
> 
>> > This is similar to the Text_IO.Integer_IO example, where the code wants
>> > to assume that "mod" behaves according to some mathematical rules.
>> > (I'm not even sure how to state those rules precisely.)
>> 
>> Well, this is about LSP. No one can enforce semantics of an operation.
> 
> Exactly my point.  For *this* issue, all of the above good ideas are
> equivalent to simply changing the language so that predefined operators
> do not reemerge.

One should distinguish overloading and overriding. If ">" is overridden 
then a reemergence would clearly violate LSP. On contrary in the case of 
overloading reemergence would enforce LSP. So logically, the reemergency 
rule is OK so far the type is untagged [but there should be no such (:-))]. 
But look at this:

package Some_Type is
   type X is tagged null record;
   function "<" (A, B : X) return Boolean;
end Some_Type;

package body Some_Type is
   function "<" (A, B : X) return Boolean is
   begin
      return True;
   end "<";
end Some_Type;

with Ada.Text_IO; use Ada.Text_IO;
with Some_Type;   use Some_Type;

procedure Test is
   XX : X;

   generic procedure Compare (A : X);

   procedure Compare (A : X) is
   begin
      if A < A then
         Put_Line ("Reemerged");
      else
         Put_Line ("Overloaded");
      end if;
   end Compare;

   procedure G1 is new Compare;
   procedure N1 (A : X) is
   begin
      if A < A then
         Put_Line ("Reemerged");
      else
         Put_Line ("Overloaded");
      end if;
   end N1;

   function "<" (A, B : X) return Boolean is
   begin
      return False;
   end "<";

   procedure G2 is new Compare;
   procedure N2 (A : X) is
   begin
      if A < A then
         Put_Line ("Reemerged");
      else
         Put_Line ("Overloaded");
      end if;
   end N2;

begin
   G1 (XX); -- Reemerged
   N1 (XX); -- Reemerged
   G2 (XX); -- Reemerged
   N2 (XX); -- Overloaded
end Test;

Is THIS OK? I do not think so. The first thought is to prohibit overloading 
of primitive operations.

>> However, the difference between what we have in Ada now and what I would
>> like to have, is that presently operations of a private formal type are
>> matched by their profiles. This warranties absolutely nothing.
> 
> Right, it warranties nothing.
> 
>>... With generic
>> derived types, you would have a subtype relation which assumes a
>> meaningfull implementation of the root type operations.
> 
> But this also warranties nothing.  One must "assume" that operations do
> what they're supposed to do; the compiler can't prove it.

To some extent it could. Let we introduce, as many proposed, pre-, 
post-conditions and invariants. Then some of requirements on operations of 
Transitive_Order could be expressed in their terms. Then (do not ask me 
how) the compiler could check that a pre-condition of a derived type 
declared to be a "strong subtype" is not stronger than it was for the base 
type etc.

This will still warranty nothing, but it is much like 
Unchecked_Deallocation. How do you warranty that it is not called twice? 
One thing is when the compiler silently uses ">", just because it has a 
right name and profile. Another thing is when the compiler says: sorry guy, 
">" is abstract, please, override it, even if the overriding would be a 
simple renaming, even if some idiot would call a TRAP instruction from the 
overriding.

> That's no
> different from the current case, where "mod" could be redefined to do
> something weird, thus breaking Text_IO.Integer_IO (I mean, if we changed
> the rules to avoid the reemergence).
> 
> You still haven't answered my question: What should the RM say that
> Integer_IO.Put does?  (Or if it were user-defined, what should the
> comment on its spec say?)  I don't care whether the language removes
> reemergence, or all your nice ideas above, including about formal
> derived types, are adopted -- either way, it's difficult to define the
> semantics of Put if it might be calling some user-defined version of
> "mod".

The precondition of Integer_IO is that the generic parameter is of some 
integer type. It means that all what is said about integer types in RM 
should be true for it. RM could say that for an integer type for any x and 
any y/=0 there are d and r of the type that x=y*d+r and etc (*). There is a 
related question: how to make preconditions as weak as possible? 
Definitely, Put does not need *all* integer operations. How to express 
that? To refine further the type hierarchy like with Transitive_Order would 
be a heavy burden for a programmer, because then he/she should instantiate 
each procedure of the package separately depending on what subset of 
operations (subtype) the procedure require.

(*) You can always write in RM: "it is a bounded error if" and a draconian 
requirement follows (:-))

Also any polymorphic solution (generic or class-wide) may face 
substitutability problems because of overriding. Thus for simple things 
like Integer_IO it could be better to have a non-polymorphic one. I mean 
user-defined type conversions and subtyping through conversions. In fact we 
do it manually on daily basis when write something like:

type X is range ...;
A : X;

Put (Integer'Image (Integer (A)));

Let we have some integer type Int_Out which cannot have instances 
(variables). Then let's declare Put on it. Then if I would like to make an 
output for X, I would declare X a subtype of IO_Int by providing a 
conversion X->Int_Out. The compiler would apply the conversion should I 
write Put (X). This suffers no substitutability problems (**), because Put 
will always deal with an Int_Out.

(**) If Int_Out is capable to represent all values of the derived type.

> The current RM doesn't even mention that Put calls "mod".  In fact,
> there are various ways of implementing Put, some of which call "mod" and
> some of which don't.  Surely, Put calling "mod" is an implementation
> detail?

Yes. Yet it is consistent, because what is not an implementation detail is 
that Put *may* call "mod" expecting a meaningfull behaviour from it. 

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



  reply	other threads:[~2002-08-02  1:15 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-07-24  5:33 Dispatching and generics - language lawyer question Grein, Christoph
2002-07-24 22:55 ` Robert A Duff
2002-07-25 15:46   ` Ben Brosgol
2002-07-29 20:38     ` Robert A Duff
2002-07-31 22:52       ` Dmitry A.Kazakov
2002-07-31 20:18         ` Robert A Duff
2002-08-02  1:15           ` Dmitry A.Kazakov [this message]
2002-08-01 16:30             ` Hyman Rosen
2002-08-02 23:42               ` Dmitry A.Kazakov
2002-08-02 15:49                 ` Hyman Rosen
2002-08-02 17:48                   ` Stephen Leake
2002-08-10  3:03                     ` Warren W. Gay VE3WWG
2002-08-05 11:15                   ` Dmitry A. Kazakov
2002-08-12 12:44                   ` Robert Dewar
2002-08-13  2:00                     ` Information Systems Annex was " Robert C. Leif
2002-08-13  8:17                       ` Robert Dewar
2002-08-13 23:53                         ` Information Systems Annex Robert C. Leif
2002-08-13 17:37                       ` Information Systems Annex was RE: Dispatching and generics - language lawyer question Keith Thompson
2002-08-13 23:53                         ` Robert C. Leif
2002-08-14  8:52                           ` Keith Thompson
2002-08-14 21:53                             ` Robert C. Leif
2002-08-15  9:31                               ` Robert Dewar
2002-08-15 21:54                                 ` Decimal Floating point was " Robert C. Leif
2002-08-16  6:26                                   ` Keith Thompson
2002-08-16 16:26                                     ` Robert C. Leif
2002-08-16 18:17                                       ` Keith Thompson
2002-08-16 15:26                                   ` Robert Dewar
2002-08-16 15:29                                   ` Robert Dewar
2002-08-15  9:26                           ` Robert Dewar
2002-08-15 16:17                             ` Darren New
2002-08-15 17:25                               ` David C. Hoos
2002-08-15 17:31                                 ` Darren New
2002-08-15 19:59                                 ` Frank J. Lhota
2002-08-15 17:39                               ` tmoran
2002-08-15 19:18                               ` Information Systems Annex was RE: Dispatching and generics - Larry Kilgallen
2002-08-15 18:41                                 ` Hyman Rosen
2002-08-16 15:49                                 ` Robert Dewar
2002-08-17  6:31                                   ` Simon Wright
2002-08-17 14:17                                     ` Robert Dewar
2002-08-15 21:54                             ` Decimal Floating types was RE: Information Systems Annex was RE: Dispatching and generics - language lawyer question Robert C. Leif
2002-08-16 15:21                               ` Robert Dewar
2002-08-16 16:15                                 ` Decimal Floating types Warren W. Gay VE3WWG
2002-08-17 10:52                                   ` Robert Dewar
2002-08-17 14:30                                     ` Warren W. Gay VE3WWG
2002-08-20  0:26                                       ` Robert Dewar
2002-08-20  2:35                                         ` SteveD
2002-08-22 18:15                                         ` Richard Riehle
2002-08-23  3:23                                           ` Robert Dewar
2002-08-16 15:47                             ` Information Systems Annex (usefulness of Decimal Floats) Warren W. Gay VE3WWG
2002-08-17 10:54                               ` Robert Dewar
2002-08-17 14:06                                 ` Warren W. Gay VE3WWG
2002-08-17 10:56                               ` Robert Dewar
2002-08-17 14:12                                 ` Warren W. Gay VE3WWG
2002-08-17 19:04                                 ` Robert C. Leif
2002-08-20  0:25                                   ` Robert Dewar
2002-08-16 15:38                           ` Information Systems Annex was RE: Dispatching and generics - language lawyer question Robert Dewar
2002-08-13 22:50           ` Randy Brukardt
2002-08-14  0:02             ` Robert A Duff
2002-07-25  0:40 ` Robert Dewar
  -- strict thread matches above, loose matches on Subject: below --
2002-07-22 23:13 Adam Beneschan
2002-07-23 15:42 ` Stephen Leake
2002-07-24 15:37   ` Stephen Leake
replies disabled

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