comp.lang.ada
 help / color / mirror / Atom feed
From: Adam Beneschan <adambeneschan@aol.com>
Subject: Re: orthogonal inheritance and extension aggregates
Date: Mon, 22 Jul 2013 09:02:27 -0700 (PDT)
Date: 2013-07-22T09:02:27-07:00	[thread overview]
Message-ID: <79e0bc53-5431-493d-95d1-aac74c7d19c9@googlegroups.com> (raw)
In-Reply-To: <6995bf02-6143-4d0f-aeb3-89a94bc1ac01@googlegroups.com>

On Friday, July 19, 2013 11:00:34 AM UTC-7, Adam Beneschan wrote:
> On Friday, July 19, 2013 10:46:38 AM UTC-7, Felix Krause wrote:
> 
> > I try to implement some feature via orthogonal inhertance like this:
> 
> 
> >     generic
> >        type Parent (<>) is abstract tagged private;
> >     package Extension is
> >        type Extended is abstract new Parent with private;
> > 
> >        -- operations of the extended type here
> >     private
> >        type Extended is abstract new Parent with record
> >           -- …
> >        end record;
> >     end Extension;
> 
> > 
> 
> > Now for testing, I tried to apply this on a Vector:
> 
> >     package Int_Vectors is new Ada.Container.Vectors (Natural, Integer);
> >     package Base is new Extension (Int_Vectors.Vector);
> 
> >     type Child is new Base.Extended with null record;
> 
> > At the declaration of Child, GNAT tells me "type must be declared 
> > abstract or "To_Vector" overridden". Can someone explain why this 
> > happens? As I understand it, To_Vector should be automatically defined 
> > for the derived type. Is this because the intermediate type Extended is 
> > declared abstract? Or because To_Vector dispatches in the return type?
> 
> This looks like a GNAT bug to me.

OK, I goofed.  I forgot that the rules were different when it comes to inherited functions that return tagged types.  GNAT's error message wasn't really helpful. 

The more I look at it, the more I think this is a missing language feature that is not going to be easy to fix.  Normally, if you have a tagged type T and an operation that is a function F that returns T, and in some other package P2 you defined a tagged type T2 that is derived from T and adds components to it, you *must* provide an overriding function F that operates on T2 and (presumably) sets up those additional fields.  If the language allowed you to simply inherit F, that version of F wouldn't set up the new fields.

If you declare T2 to be abstract, the language will let you get away with not overriding F; the inherited F will then be abstract.  I think this might have been a mistake (that is, I think 3.9.3(5) should have applied only to abstract subprograms, not to functions that return controlling types, at least when the parent type is non-abstract).  The package that declares the new fields in the type (i.e. P2) should be responsible for defining the operations that set up the new fields.  This is especially the case when the extension fields are declared in a private part, since other packages that define concrete derived types from T2 have no way to set up the extension fields defined for T2 (unless they happen to be in child packages of P2).  

Generics with formal derived types just make everything worse, as you've noticed, because now, at the time the generic is declared, the compiler can't tell what functions might be present that return the tagged type.  When the generic is instantiated, the question needs to be asked, "All right, we've just inherited some To_Vector functions that return this new Extended type; who's going to be responsible for making sure the new fields are set up"?  And you have two packages pointing fingers at each other.  Extension says it can't do it, because it doesn't know what functions will get inherited.  And the package that contains the instantiation can't do it, because it can't see the fields that need to be set up.  Even if Extension were a public extension, it still wouldn't work, because the language doesn't provide a way for code to instantiate a generic and then define new overriding primitives *inside* the generic.  But in the present case, where it's a private extension, any solution would have to involve some kind of new and interesting kind of cooperation between the two packages, since neither one has access to all the needed information.  The only solution I can think of is to add some sort of "default extension initializer" feature that Extension could provide, and then the inherited To_Vector functions that call the parent To_Vector and then the "default extension initializer" could be implicitly defined.  But I don't like this, since a single routine that initializes the extension components in the same way for all functions may not be appropriate.

So basically I think what you're trying to do just shouldn't be done in Ada, and frankly I think the generic instantiation should have been illegal, and it's a language hole that it lets you get through.  I'll try to think about it and see if there's some other solution that better reflects the class of problem you're trying to solve, rather than being a hack to work around the rules.  (Plus I'll try to think about how this might be handled in other languages, although no other language has the same kind of generic features as Ada so it might be difficult to find an exact parallel.)

                                 -- Adam  




  reply	other threads:[~2013-07-22 16:02 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-19 17:46 orthogonal inheritance and extension aggregates Felix Krause
2013-07-19 18:00 ` Adam Beneschan
2013-07-22 16:02   ` Adam Beneschan [this message]
2013-07-22 18:44     ` Dmitry A. Kazakov
2013-07-22 18:59     ` Adam Beneschan
2013-07-22 19:19       ` Adam Beneschan
2013-07-22 22:03       ` Felix Krause
2013-07-19 19:05 ` Dmitry A. Kazakov
2013-07-20  5:49   ` Randy Brukardt
2013-07-20  6:36     ` Dmitry A. Kazakov
2013-07-20  7:54       ` Niklas Holsti
replies disabled

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