comp.lang.ada
 help / color / mirror / Atom feed
* Access to generic formal parameters in an generic package instantiation
@ 2012-07-29 18:16 Florian Weimer
  2012-07-29 19:36 ` Dmitry A. Kazakov
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Florian Weimer @ 2012-07-29 18:16 UTC (permalink / raw)


If G is a generic package and P is one of its formal parameters, it is
legal to refer to G.P where G is visible?  Does this depend on the
kind of entity, or whether the formal part uses <>?

Has anybody tried to use generic formal packages to emulate Standard
ML signatures?  Is it possible to express SML "where" constraints,
that is, specify that two types in two formal packages are the same,
without break down the formal packages to their components?

It seems that generic formal packages are unusual because GNAT shows
some strange effects (and the occasional bug box).



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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-29 18:16 Access to generic formal parameters in an generic package instantiation Florian Weimer
@ 2012-07-29 19:36 ` Dmitry A. Kazakov
  2012-07-29 21:31   ` Florian Weimer
  2012-07-30 18:33 ` Adam Beneschan
  2012-07-31  7:48 ` Georg Bauhaus
  2 siblings, 1 reply; 8+ messages in thread
From: Dmitry A. Kazakov @ 2012-07-29 19:36 UTC (permalink / raw)


On Sun, 29 Jul 2012 20:16:00 +0200, Florian Weimer wrote:

> If G is a generic package and P is one of its formal parameters, it is
> legal to refer to G.P where G is visible?  Does this depend on the
> kind of entity, or whether the formal part uses <>?

Sometimes it works, sometimes it does not, I am not a language lawyer to
tell when GNAT is right or not. Facing this problem quite frequently, I
developed a custom to rename formal parameters within the declaration area,
e.g.

generic
   type Foo is ...;
   with package Bar is new Baz (<>);
package Boo is
   subtype My_Foo is Foo;
   package My_Bar is renames Bar;
   ...

Another method of making formal parameters visible is to have it a generic
child.

> that is, specify that two types in two formal packages are the same,
> without break down the formal packages to their components?

Yes. There several techniques to accomplish this.

1. You can to make that type a formal parameter and specify it among the
formal parameters of the instances:

   type T is ...
   with package P1 (T, <>);
   with package P2 (T, <>);

2. You can take the type from one package and constrain another with it:

   with package P1 (<>);
   with package P2 (P1.T, <>);

3. You can factor out a generic parameter package that defines T and other
common types and make it generic parent for the packages of interest.

> It seems that generic formal packages are unusual because GNAT shows
> some strange effects (and the occasional bug box).

There were always problems with generics in GNAT.

Though you likely won't believe me anyway, but using generics is a very bad
idea unless absolutely nothing else works. Here is an outlook what it
becomes in a relatively simple case:

   http://www.dmitry-kazakov.de/ada/fuzzy_packages.gif

Can you figure out a chain of instantiation of this for some given
floating-point type? How many instances it does? In a really complex case
there are multiple pages of such diagrams.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-29 19:36 ` Dmitry A. Kazakov
@ 2012-07-29 21:31   ` Florian Weimer
  2012-07-30 18:37     ` Adam Beneschan
  0 siblings, 1 reply; 8+ messages in thread
From: Florian Weimer @ 2012-07-29 21:31 UTC (permalink / raw)


* Dmitry A. Kazakov:

> On Sun, 29 Jul 2012 20:16:00 +0200, Florian Weimer wrote:
>
>> If G is a generic package and P is one of its formal parameters, it is
>> legal to refer to G.P where G is visible?  Does this depend on the
>> kind of entity, or whether the formal part uses <>?
>
> Sometimes it works, sometimes it does not, I am not a language lawyer to
> tell when GNAT is right or not.

It seems that the names of the generic formal declarations are lost
except if they refer to implicit declaration (those using <>).  I'm
not sure why implicit declarations are special-cased like this.  There
is sometimes no way to reference to an implicit declaration because
you are not supplying the arguments.  But if you want to get the
arguments back reliably, you have to add declarations anyway, and
those cover the implicit case as well, so I'm not sure this language
feature is really necessary.

> Facing this problem quite frequently, I developed a custom to rename
> formal parameters within the declaration area, e.g.
>
> generic
>    type Foo is ...;
>    with package Bar is new Baz (<>);
> package Boo is
>    subtype My_Foo is Foo;
>    package My_Bar is renames Bar;
>    ...

The same approach is used in C++ where template arguments are not
accessible from outside of the template.  Instead, you have to provide
typedefs for alias names.

> Another method of making formal parameters visible is to have it a
> generic child.

This smells a bit like a compiler bug.  The standard doesn't seem to
mention it.

>> that is, specify that two types in two formal packages are the same,
>> without break down the formal packages to their components?
>
> Yes. There several techniques to accomplish this.
>
> 1. You can to make that type a formal parameter and specify it among the
> formal parameters of the instances:
>
>    type T is ...
>    with package P1 (T, <>);
>    with package P2 (T, <>);

I got a bug box when I tried this.

> Though you likely won't believe me anyway, but using generics is a very bad
> idea unless absolutely nothing else works. Here is an outlook what it
> becomes in a relatively simple case:
>
>    http://www.dmitry-kazakov.de/ada/fuzzy_packages.gif

It's just the usual curse of the higher order.  Functions call graphs
aren't always pretty, either.

Anyway, I'm trying to find a good way for resource management which
does not rely on finalization, and I want to cut down boilerplate
code.



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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-29 18:16 Access to generic formal parameters in an generic package instantiation Florian Weimer
  2012-07-29 19:36 ` Dmitry A. Kazakov
@ 2012-07-30 18:33 ` Adam Beneschan
  2012-07-31  7:48 ` Georg Bauhaus
  2 siblings, 0 replies; 8+ messages in thread
From: Adam Beneschan @ 2012-07-30 18:33 UTC (permalink / raw)


On Sunday, July 29, 2012 11:16:00 AM UTC-7, Florian Weimer wrote:
> If G is a generic package and P is one of its formal parameters, it is
> legal to refer to G.P where G is visible? 

No, unless you're inside G.  Outside of G, you can't refer to any entities inside G.

I wonder if you're referring to a generic *instance*, though.  It's helpful to keep the terminology straight:

   generic
       type T is private;
   package Gen_Package is ...

   package Instance is new Gen_Package (Integer);  -- for example

Gen_Package is a "generic package".  Outside of Gen_Package, you can't refer to Gen_Package.T and it wouldn't make any sense.  Instance is not a "generic package"; it's a "generic instance", or an "instance of a generic package".

However, you still can't refer to Instance.T.  I think the theory was probably that the code knows what Instance.T is because it's right there in the parameter list when Gen_Package is instantiated, so it isn't necessary to allow Instance.T.  

In this case
    generic
       with INST is new Gen_Package (<>);
    package Gen_Package_2 is ...

INST is a "generic formal package", not a "generic package".  It represents an instance of Gen_Package, but of course we don't know what the instance is until we instantiate Gen_Package_2.  Within Gen_Package_2, you can refer to INST.T, because (unlike the previous example) the code in Gen_Package_2 doesn't know what INST.T is, because there's only a <> in the parameter list of the generic formal package declaration.

Hope this helps a little,


> Does this depend on the
> kind of entity, or whether the formal part uses <>?
> 
> 
> 
> Has anybody tried to use generic formal packages to emulate Standard
> 
> ML signatures?  Is it possible to express SML "where" constraints, 
> that is, specify that two types in two formal packages are the same,
> without break down the formal packages to their components?

You can do something like this:

  generic
     with package INST is new Gen_Package (<>);
     with package ANOTHER_INST is new Another_Gen_Package (T => Inst.T);
  package Gen_Package_3 is ...

Now when you instantiation 

  package Some_Inst is new Gen_Package_3 (P1, P2);

the instantiation is legal only if P1 and P2 were instantiated with the same type for T.  This seems like what you're looking for.  (P.S. This sort of thing is also legal starting with Ada 2005:


  generic
     with package INST is new Gen_Package (<>);
     with package ANOTHER_INST is new Another_Gen_Package (T => Inst.T,
                                                           others => <>);
  package Gen_Package_3 is ...
 
That puts a constraint on the type T used to instantiate Another_Gen_Package, while not putting any constraints on any other actual parameters.)

Hope this helps a little,

                          -- Adam




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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-29 21:31   ` Florian Weimer
@ 2012-07-30 18:37     ` Adam Beneschan
  0 siblings, 0 replies; 8+ messages in thread
From: Adam Beneschan @ 2012-07-30 18:37 UTC (permalink / raw)


On Sunday, July 29, 2012 2:31:29 PM UTC-7, Florian Weimer wrote:

> > 1. You can to make that type a formal parameter and specify it among the 
> > formal parameters of the instances: 
>  
> >    type T is ...
> >    with package P1 (T, <>);
> >    with package P2 (T, <>);
> 
> I got a bug box when I tried this.

The syntax isn't legal.  You shouldn't have gotten a bug box, but you should definitely get an error message.  Unless <> is all by itself inside parentheses, you need either a parameter name or "others":

    generic
       type T is private;
       with package P1 (T, others => <>);
       with package P2 (T, others => <>);

or, if (say) P1 has only two formal parameters:

       with package P1 (T, parameter_name => <>);

                            -- Adam



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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-29 18:16 Access to generic formal parameters in an generic package instantiation Florian Weimer
  2012-07-29 19:36 ` Dmitry A. Kazakov
  2012-07-30 18:33 ` Adam Beneschan
@ 2012-07-31  7:48 ` Georg Bauhaus
  2012-07-31 15:29   ` Adam Beneschan
  2 siblings, 1 reply; 8+ messages in thread
From: Georg Bauhaus @ 2012-07-31  7:48 UTC (permalink / raw)


On 29.07.12 20:16, Florian Weimer wrote:
> It seems that generic formal packages are unusual because GNAT shows
> some strange effects (and the occasional bug box).

Compilers seem to differ on this one, which should be Ada 95.
I am not sure the generics are properly addressing the issue
of type comparison (well, of convertibility).

With GNAT's bug boxes currently in the way I can't try the
Ada 2012 features. (Something about failures when testing entity
node kinds.)

generic
    type T is private;
    Fst, Snd : in T;
package Same_Type is end;

with Same_Type;
generic
    type Ancestor is private          ;
    type T1 is new Ancestor;
    type T2 is new Ancestor;
    X : T1;
    Y : T2;
--   with package Comparison is new Same_Type (T1, T1'(X), T1 (Y));
package Ops is

private
    package Comparison_1 is new Same_Type (T1, T1'(X), T1 (Y));
    package Comparison_2 is new Same_Type (T2, T2 (X), T2'(Y));
end;

with Same_Type, Ops;
procedure Test_G is

    type Int is new Integer;
    type Chr is new Character;

    Two : constant Int := 2;
    C : constant Chr := 'c';

    package Test_1 is new Ops (Int, Int, Int, Two, Two);

--!GNAT!   package Test_2 is new Ops (Int, Int, Chr, Two, C);

    package PK is
       type root is tagged null record;
       type left is new root with null record;
       type right is new root with null record;
    end PK;
    use pK;

    L : Left;
    R : Right;
    package test_3 is new ops (Root, Left, Right, L, R);
begin
    null;
end Test_G;




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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-31  7:48 ` Georg Bauhaus
@ 2012-07-31 15:29   ` Adam Beneschan
  2012-07-31 16:50     ` Georg Bauhaus
  0 siblings, 1 reply; 8+ messages in thread
From: Adam Beneschan @ 2012-07-31 15:29 UTC (permalink / raw)


On Tuesday, July 31, 2012 12:48:04 AM UTC-7, Georg Bauhaus wrote:

> Compilers seem to differ on this one, which should be Ada 95.
> I am not sure the generics are properly addressing the issue
> of type comparison (well, of convertibility).
> 
>
> With GNAT's bug boxes currently in the way I can't try the
> Ada 2012 features. (Something about failures when testing entity
> node kinds.)
> 
> 
> 
> generic
>     type T is private;
>     Fst, Snd : in T;
> package Same_Type is end;
> 
> with Same_Type;
> generic
>     type Ancestor is private;
>     type T1 is new Ancestor;
>     type T2 is new Ancestor;
>     X : T1;
>     Y : T2;
> --   with package Comparison is new Same_Type (T1, T1'(X), T1 (Y));
> 
> package Ops is
> private
>     package Comparison_1 is new Same_Type (T1, T1'(X), T1 (Y));
>     package Comparison_2 is new Same_Type (T2, T2 (X), T2'(Y));
> end;
> 
> with Same_Type, Ops;
> procedure Test_G is
>     type Int is new Integer;
>     type Chr is new Character;
>     Two : constant Int := 2;
>     C : constant Chr := 'c';
>     package Test_1 is new Ops (Int, Int, Int, Two, Two);
> --!GNAT!   package Test_2 is new Ops (Int, Int, Chr, Two, C);

GNAT gets a bug box here, but you do realize that the instantiation is illegal, right?  T2 is supposed to be derived from T1, but Chr is not derived from Int.  I'm sure you probably realize this, but it's not clear from your post what you're trying to show.

>     package PK is
>        type root is tagged null record;
>        type left is new root with null record;
>        type right is new root with null record;
>     end PK;
>     use pK;
>
>     L : Left;
>     R : Right;
>     package test_3 is new ops (Root, Left, Right, L, R);

I get an "instantiation error" when I try this with GNAT, which is usually a bad sign.  In this case, I think it's a hole in the language.  The formal types are declared without "tagged", so that while compiling the generic, they're treated as untagged.  And for untagged types, any time you have two types with the same ultimate ancestor, you can convert between them.  For tagged types, the rules are different, though, since downward conversions (from a type to its descendant) are not generally allowed, since the descendant can have new components that a conversion wouldn't be able to supply.  (I'm not sure offhand whether a downward conversion to a null extension is allowed--I'd have to look it up.)  The problem is that a generic formal untagged type can have a tagged type as an actual.  So in a case like this, where a generic contains a construct that would be legal for untagged types but illegal for tagged types, the language doesn't seem to prevent error cases from coming up.  There may be other  constructs besides type conversions that cause problems when an untagged formal has a tagged actual.

Anyway, I'll look into this further but will probably send something to Ada-Comment unless this has been brought up already.  I think it could be fixed fairly simply.  (I'm thinking that adding a rule that a generic formal untagged derived type cannot have a tagged type as an actual would work, and would be unlikely to make any existing code illegal.)

                               -- Adam



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

* Re: Access to generic formal parameters in an generic package instantiation
  2012-07-31 15:29   ` Adam Beneschan
@ 2012-07-31 16:50     ` Georg Bauhaus
  0 siblings, 0 replies; 8+ messages in thread
From: Georg Bauhaus @ 2012-07-31 16:50 UTC (permalink / raw)


On 31.07.12 17:29, Adam Beneschan wrote:
>>     package Test_1 is new Ops (Int, Int, Int, Two, Two);
>> > --!GNAT!   package Test_2 is new Ops (Int, Int, Chr, Two, C);
> GNAT gets a bug box here, but you do realize that the instantiation is illegal, right?  T2 is supposed to be derived from T1, but Chr is not derived from Int.  I'm sure you probably realize this, but it's not clear from your post what you're trying to show.

Yes, I had hoped that GNAT, like ObjectAda, would say that
at compile time, i.e. whether I can instantiate the generic
with the two types, or that they are too different, in a sense.
I thought that involving a number of things tested at compile
time could remotely resemble testing (type related?) things
like is done when using C++ templates.




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

end of thread, other threads:[~2012-08-07  7:16 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-29 18:16 Access to generic formal parameters in an generic package instantiation Florian Weimer
2012-07-29 19:36 ` Dmitry A. Kazakov
2012-07-29 21:31   ` Florian Weimer
2012-07-30 18:37     ` Adam Beneschan
2012-07-30 18:33 ` Adam Beneschan
2012-07-31  7:48 ` Georg Bauhaus
2012-07-31 15:29   ` Adam Beneschan
2012-07-31 16:50     ` Georg Bauhaus

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