comp.lang.ada
 help / color / mirror / Atom feed
* Generic body
@ 2008-05-14 18:26 Sébastien
  2008-05-14 21:49 ` Randy Brukardt
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Sébastien @ 2008-05-14 18:26 UTC (permalink / raw)


Hi,

I'm trying to create a generic procedure with some instance in the same 
package.

package MyPack is

   generic
     type Toto is limited private;
   procedure MyProc;

   procedure MyProcInt is new MyProc(Toto => Integer);
   procedure MyProcStr is new MyProc(Toto => String);

end MyPack;

package body MyPack is

   procedure MyProc is
   begin
     -- Some stuff
   end MyProc;

end MyPack;

I don't how to do this because:
1) The compiler refuse the instance of MyProc because it doesn't have 
the MyProc body
2) If I put the body of MyProc in the package spec, the compiler refuses 
it because it's not the right place.

Thanks by advance for any help

Sebastien



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

* Re: Generic body
  2008-05-14 18:26 Generic body Sébastien
@ 2008-05-14 21:49 ` Randy Brukardt
  2008-05-14 21:51 ` Samuel Tardieu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Randy Brukardt @ 2008-05-14 21:49 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1661 bytes --]

"S�bastien" <seb.morand@gmail.com> wrote in message 
news:g0fash$73v$1@registered.motzarella.org...
> Hi,
>
> I'm trying to create a generic procedure with some instance in the same 
> package.
>
> package MyPack is
>
>   generic
>     type Toto is limited private;
>   procedure MyProc;
>
>   procedure MyProcInt is new MyProc(Toto => Integer);
>   procedure MyProcStr is new MyProc(Toto => String);
>
> end MyPack;
>
> package body MyPack is
>
>   procedure MyProc is
>   begin
>     -- Some stuff
>   end MyProc;
>
> end MyPack;
>
> I don't how to do this because:
> 1) The compiler refuse the instance of MyProc because it doesn't have the 
> MyProc body
> 2) If I put the body of MyProc in the package spec, the compiler refuses 
> it because it's not the right place.
>
> Thanks by advance for any help

You can't do this. The language doesn't allow it because the body of the 
instances would have to be elaborated before the body of the generic unit. 
That wouldn't be a major problem for a subprogram, but for a generic 
package, that could lead to all kinds of havoc (specifically, accessing 
objects that don't yet exist). To be consistent, it raises Program_Error in 
all cases. (GNAT rejects some of these cases at compile-time by default, 
which is not standard Ada behavior. But it still wouldn't work.) And, as 
you've found out, the only way to put a body into a specification is via an 
instance.

You'll have to put the instances in a separate unit from the generic unit. 
That's usually preferable anyway (especially in larger projects), but you 
don't have any choice in this case.

                                            Randy.





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

* Re: Generic body
  2008-05-14 18:26 Generic body Sébastien
  2008-05-14 21:49 ` Randy Brukardt
@ 2008-05-14 21:51 ` Samuel Tardieu
  2008-05-14 22:03 ` Adam Beneschan
  2008-05-15  8:43 ` gautier_niouzes
  3 siblings, 0 replies; 9+ messages in thread
From: Samuel Tardieu @ 2008-05-14 21:51 UTC (permalink / raw)


>>>>> "S�bastien" == S�bastien  <seb.morand@gmail.com> writes:

S�bastien> I don't how to do this because: 1) The compiler refuse the
S�bastien> instance of MyProc because it doesn't have the MyProc body
S�bastien> 2) If I put the body of MyProc in the package spec, the
S�bastien> compiler refuses it because it's not the right place.

What compiler are you using? (name and version)

With a recent GNAT, I get:

     7.   procedure MyProcInt is new MyProc(Toto => Integer);
          |
        >>> warning: cannot instantiate "MyProc" before body seen
        >>> warning: Program_Error will be raised at run time

     8.   procedure MyProcStr is new MyProc(Toto => String);
                                                    |
        >>> actual for "Toto" must be a definite subtype

which I think explains things well.

  Sam
--
Samuel Tardieu -- sam@rfc1149.net -- http://www.rfc1149.net/



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

* Re: Generic body
  2008-05-14 18:26 Generic body Sébastien
  2008-05-14 21:49 ` Randy Brukardt
  2008-05-14 21:51 ` Samuel Tardieu
@ 2008-05-14 22:03 ` Adam Beneschan
  2008-05-15  9:25   ` Sébastien
  2008-05-15  8:43 ` gautier_niouzes
  3 siblings, 1 reply; 9+ messages in thread
From: Adam Beneschan @ 2008-05-14 22:03 UTC (permalink / raw)


On May 14, 11:26 am, Sébastien <seb.mor...@gmail.com> wrote:
> Hi,
>
> I'm trying to create a generic procedure with some instance in the same
> package.
>
> package MyPack is
>
>    generic
>      type Toto is limited private;
>    procedure MyProc;
>
>    procedure MyProcInt is new MyProc(Toto => Integer);
>    procedure MyProcStr is new MyProc(Toto => String);

This one can't be right in any case, because String is an
unconstrained type.  You can't declare a *variable*

    X : String;

so therefore you can't use String as the actual type for Toto, because
MyProc could declare a variable

    X : Toto;

somewhere in it.  But if you really need the ability to use "String"
here, do this in your generic:

    type Toto(<>) is limited private;

I realize this has nothing to do with your question.

>
> end MyPack;
>
> package body MyPack is
>
>    procedure MyProc is
>    begin
>      -- Some stuff
>    end MyProc;
>
> end MyPack;

Regarding your question: you really can't do this in Ada, because of
3.11(13-14): "For the instantiation of a generic unit that has a body,
a check is made that this body is already elaborated....The exception
Program_Error is raised if any of these checks fails."  The compiler
*should* accept your program with no errors, but it should fail at
runtime because the program will have to "elaborate" the generic
instantiation before it elaborates the generic body, and the program
will fail on Program_Error before it even gets started.  If your
compiler is rejecting your program, then either it is doing so because
it "knows" that the program can't possibly work when it runs, or it
has a bug.

Although there may be ways to suppress the elaboration check,
depending on your compiler, I wouldn't take that approach, because the
check is there for a reason.  If you suppress the check, there's a
possibility that your program may not work as expected, depending on
what the body of your generic looks like, especially if it refers to
any global variables in the body of MyPack.

I'd recommend putting the generic in its own library unit, or in a
different package:

   package MyProcPack is  -- I hate this name
     generic
       type Toto(<>) is limited private;
     procedure MyProc;
   end MyProcPack;

   package body MyProcPack is
     procedure MyProc is ... end MyProc;
   end MyProcPack;

   with MyProcPack;
   pragma Elaborate_All (MyProcPack);
   package MyPack is
     procedure MyProcInt is new MyProcPack.MyProc(Toto => Integer);
     procedure MyProcStr is new MyProcPack.MyProc(Toto => String);
   end MyPack;

The Elaborate_All pragma is necessary to ensure that the body of
MyProcPack (including the body of the generic MyProc) is elaborated
before MyProc is instantiated.

If you don't understand what elaboration is all about, it's too
difficult to explain here---sorry.  But just trust me that you'll need
to do something like what I'm recommending.


> I don't how to do this because:
> 1) The compiler refuse the instance of MyProc because it doesn't have
> the MyProc body

As I've mentioned, the compiler really shouldn't refuse this, because
it's a legal Ada program although it cannot work right.  Some
compilers have modes that cause them to reject programs that are
certain to raise predefined exceptions, even when the programs are
legal, and your compiler could be running in a mode like this.

> 2) If I put the body of MyProc in the package spec, the compiler refuses
> it because it's not the right place.

Right---you can't put any sort of body in a package spec.

                                    -- Adam





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

* Re: Generic body
  2008-05-14 18:26 Generic body Sébastien
                   ` (2 preceding siblings ...)
  2008-05-14 22:03 ` Adam Beneschan
@ 2008-05-15  8:43 ` gautier_niouzes
  2008-05-15 13:11   ` Sébastien
  3 siblings, 1 reply; 9+ messages in thread
From: gautier_niouzes @ 2008-05-15  8:43 UTC (permalink / raw)


Here is how to do it...
--

package MyPack is

   generic
     type Toto is limited private;
   procedure MyProc;

   procedure MyProcInt;
   procedure MyProcChr;

end MyPack;

package body MyPack is

   procedure MyProc is
   begin
     null; -- Some stuff
   end MyProc;

   procedure MyProcInt_internal is new MyProc(Toto => Integer);
   procedure MyProcChr_internal is new MyProc(Toto => Character);

   procedure MyProcInt renames MyProcInt_internal;
   procedure MyProcChr renames MyProcChr_internal;

end MyPack;
__________________________________________________________________
Gautier's Ada programming -- http://sourceforge.net/users/gdemont/

NB: For a direct answer, e-mail address on the Web site!



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

* Re: Generic body
  2008-05-14 22:03 ` Adam Beneschan
@ 2008-05-15  9:25   ` Sébastien
  2008-05-15 14:59     ` Adam Beneschan
  0 siblings, 1 reply; 9+ messages in thread
From: Sébastien @ 2008-05-15  9:25 UTC (permalink / raw)


> somewhere in it.  But if you really need the ability to use "String"
> here, do this in your generic:
> 
>     type Toto(<>) is limited private;
> 
> I realize this has nothing to do with your question.

Not but it's an interesting issue. I remembered this syntax I saw some 
places and then read that:
http://en.wikibooks.org/wiki/Ada_Programming/Generics#Generic_formal_types
Now I understand well the matter. Thanks.

> Regarding your question: you really can't do this in Ada, because of
> 3.11(13-14): "For the instantiation of a generic unit that has a body,
> a check is made that this body is already elaborated....The exception
> Program_Error is raised if any of these checks fails."  The compiler
> *should* accept your program with no errors, but it should fail at
> runtime because the program will have to "elaborate" the generic
> instantiation before it elaborates the generic body, and the program
> will fail on Program_Error before it even gets started.  If your
> compiler is rejecting your program, then either it is doing so because
> it "knows" that the program can't possibly work when it runs, or it
> has a bug.
> Although there may be ways to suppress the elaboration check,
> depending on your compiler, I wouldn't take that approach, because the
> check is there for a reason.  If you suppress the check, there's a
> possibility that your program may not work as expected, depending on
> what the body of your generic looks like, especially if it refers to
> any global variables in the body of MyPack.

Yes I understand that warning are now a good things in Ada :-) Espcially 
when it says some exceptions will be raised at runtime. So I take time 
to undestand and correct any warning.

> I'd recommend putting the generic in its own library unit, or in a
> different package:
> 
>    package MyProcPack is  -- I hate this name
>      generic
>        type Toto(<>) is limited private;
>      procedure MyProc;
>    end MyProcPack;
> 
>    package body MyProcPack is
>      procedure MyProc is ... end MyProc;
>    end MyProcPack;
> 
>    with MyProcPack;
>    pragma Elaborate_All (MyProcPack);
>    package MyPack is
>      procedure MyProcInt is new MyProcPack.MyProc(Toto => Integer);
>      procedure MyProcStr is new MyProcPack.MyProc(Toto => String);
>    end MyPack;
> 
> The Elaborate_All pragma is necessary to ensure that the body of
> MyProcPack (including the body of the generic MyProc) is elaborated
> before MyProc is instantiated.
> 
> If you don't understand what elaboration is all about, it's too
> difficult to explain here---sorry.  But just trust me that you'll need
> to do something like what I'm recommending.

I read a lot of stuff about elaboration, I'm not a master of the subject 
yet, but I understand a bit about it. I thought that Elaborate_All was 
about dynamic check vs static check? (flat -gnatE for circular dependancy)

>> I don't how to do this because:
>> 1) The compiler refuse the instance of MyProc because it doesn't have
>> the MyProc body
> 
> As I've mentioned, the compiler really shouldn't refuse this, because
> it's a legal Ada program although it cannot work right.  Some
> compilers have modes that cause them to reject programs that are
> certain to raise predefined exceptions, even when the programs are
> legal, and your compiler could be running in a mode like this.
> 
>> 2) If I put the body of MyProc in the package spec, the compiler refuses
>> it because it's not the right place.
> 
> Right---you can't put any sort of body in a package spec.

Ok thanks to all of you for your help.

Sebastien



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

* Re: Generic body
  2008-05-15  8:43 ` gautier_niouzes
@ 2008-05-15 13:11   ` Sébastien
  0 siblings, 0 replies; 9+ messages in thread
From: Sébastien @ 2008-05-15 13:11 UTC (permalink / raw)


> package MyPack is
> 
>    generic
>      type Toto is limited private;
>    procedure MyProc;
> 
>    procedure MyProcInt;
>    procedure MyProcChr;
> 
> end MyPack;
> 
> package body MyPack is
> 
>    procedure MyProc is
>    begin
>      null; -- Some stuff
>    end MyProc;
> 
>    procedure MyProcInt_internal is new MyProc(Toto => Integer);
>    procedure MyProcChr_internal is new MyProc(Toto => Character);
> 
>    procedure MyProcInt renames MyProcInt_internal;
>    procedure MyProcChr renames MyProcChr_internal;
> 
> end MyPack;

Really nice solutions, thanks very much.



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

* Re: Generic body
  2008-05-15  9:25   ` Sébastien
@ 2008-05-15 14:59     ` Adam Beneschan
  2008-05-15 15:40       ` Sébastien
  0 siblings, 1 reply; 9+ messages in thread
From: Adam Beneschan @ 2008-05-15 14:59 UTC (permalink / raw)


On May 15, 2:25 am, Sébastien <seb.mor...@gmail.com> wrote:

> I read a lot of stuff about elaboration, I'm not a master of the subject
> yet, but I understand a bit about it. I thought that Elaborate_All was
> about dynamic check vs static check? (flat -gnatE for circular dependancy)

I don't think so.  It's about elaboration order, and making sure that
variables have a chance to get initialized before they're used.  If
you have a package body:

   package body Pak2 is
      Counter : Integer := 0;
      function Next_Counter return Integer is
      begin
         Counter := Counter + 1;
         return Counter;
      end Next_Counter;
   end Pak2;

In Ada semantics, the elaboration of Pak2's body is what initializes
Counter to 0.  But if the elaboration of some other package (say Pak3)
used Next_Counter before Pak2's body had a chance to be elaborated,
Counter would be uninitialized and Next_Counter would return garbage.
So it's necessary to ensure that Pak2's body is elaborated before Pak3
is elaborated, and that's what the Elaborate pragmas are for.
(Without the Elaborate pragmas, Pak2's body might be elaborated first
anyway, but you can't be sure.)

That's how it works in Ada.  I know that GNAT has a big long chapter
in the manual describing how it determines the elaboration order, but
I'm not really familiar with the details.  But I'd use the pragmas
anyway; even if GNAT would get things right without them, you may want
to port to a different compiler at a later time.

In any case, I like Gautier's solution and I wish I'd thought of it;
that avoids the Elaboration issues completely.

                               -- Adam



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

* Re: Generic body
  2008-05-15 14:59     ` Adam Beneschan
@ 2008-05-15 15:40       ` Sébastien
  0 siblings, 0 replies; 9+ messages in thread
From: Sébastien @ 2008-05-15 15:40 UTC (permalink / raw)


> I don't think so.  It's about elaboration order, and making sure that
> variables have a chance to get initialized before they're used.  If
> you have a package body:
> 
>    package body Pak2 is
>       Counter : Integer := 0;
>       function Next_Counter return Integer is
>       begin
>          Counter := Counter + 1;
>          return Counter;
>       end Next_Counter;
>    end Pak2;
> 
> In Ada semantics, the elaboration of Pak2's body is what initializes
> Counter to 0.  But if the elaboration of some other package (say Pak3)
> used Next_Counter before Pak2's body had a chance to be elaborated,
> Counter would be uninitialized and Next_Counter would return garbage.
> So it's necessary to ensure that Pak2's body is elaborated before Pak3
> is elaborated, and that's what the Elaborate pragmas are for.
> (Without the Elaborate pragmas, Pak2's body might be elaborated first
> anyway, but you can't be sure.)
> 
> That's how it works in Ada.  I know that GNAT has a big long chapter
> in the manual describing how it determines the elaboration order, but
> I'm not really familiar with the details.  But I'd use the pragmas
> anyway; even if GNAT would get things right without them, you may want
> to port to a different compiler at a later time.
> 
> In any case, I like Gautier's solution and I wish I'd thought of it;
> that avoids the Elaboration issues completely.
> 
>                                -- Adam

Ok thanks for precision, it's clearer for me about elaboration issue now.



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

end of thread, other threads:[~2008-05-15 15:40 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-05-14 18:26 Generic body Sébastien
2008-05-14 21:49 ` Randy Brukardt
2008-05-14 21:51 ` Samuel Tardieu
2008-05-14 22:03 ` Adam Beneschan
2008-05-15  9:25   ` Sébastien
2008-05-15 14:59     ` Adam Beneschan
2008-05-15 15:40       ` Sébastien
2008-05-15  8:43 ` gautier_niouzes
2008-05-15 13:11   ` Sébastien

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