Prev: Child vs nested package : efficiency matter
Next: Two miscellaneous questions about GPS : Ada indentation and thenSPARK integration
From: Marc A. Criley on 29 May 2010 13:36 I'm creating a GNAT 4.4.3 on Ubuntu Ada binding for some C++ classes, using the binding generated by g++ -fdump-ada-spec as a starting point. While the binding will compile cleanly, the client code gets a compilation error, "dynamically tagged expression not allowed", when trying to set up the declarations to utilize it. Stripping out a test case, I see that it has nothing to with the C++ binding per se, but it's an Ada issue that's flummoxing me. Here's the test code: procedure Dyty_Test is type Class_Type is tagged limited record null; end record; function New_Class_Instance return Class_Type'Class; Conn : Class_Type := New_Class_Instance; function New_Class_Instance return Class_Type'Class is begin -- Just a stub return New_Class_Instance; end New_Class_Instance; begin null; end Dyty_Test; The Class_Type definition MUST be a tagged limited record to correspond to the C++ class, and the New_Class_Instance function (the constructor) MUST return a class-wide instance of that type. (There are corresponding C++ pragmas as well for these, but the error is the same whether they're present or not.) The error is on the declaration of "Conn", with the error occurring on the invocation of the initializing New_Class_Instance function. I'm just not understanding something here. I've tried a number of variations, but these have more or less become guesswork, and so it's time to ask for help :-) Thanks. Marc A. Criley McKae Technologies www.mckae.com
From: Dmitry A. Kazakov on 29 May 2010 14:23 On Sat, 29 May 2010 12:36:33 -0500, Marc A. Criley wrote: > Stripping out a test case, I see that it has nothing to with the C++ > binding per se, but it's an Ada issue that's flummoxing me. Here's the > test code: > > procedure Dyty_Test is > > type Class_Type is tagged limited record > null; > end record; > > function New_Class_Instance return Class_Type'Class; > > Conn : Class_Type := New_Class_Instance; Should Conn be mutable? Otherwise you could use a function instead. > function New_Class_Instance return Class_Type'Class is > begin > -- Just a stub > return New_Class_Instance; Infinite recursion. I suppose it is return X : Class_Type; > end New_Class_Instance; > > The error is on the declaration of "Conn", with the error occurring on > the invocation of the initializing New_Class_Instance function. I'm just > not understanding something here. You are "returning" a class-wide limited object, which is to "initialize" a specific object. A more difficult problem is that to initialize Conn, GNAT wants to know the body of the initializer. -------------------------------------------------------------- Variant 1. Two packages (to have the body): package P is type Class_Type is tagged limited record null; end record; function New_Class_Instance return Class_Type'Class; function New_Class_Object return Class_Type; end P; package P.Instances is Conn : Class_Type := New_Class_Object; end P.Instances; package body P is function New_Class_Object return Class_Type is begin return X : Class_Type; end New_Class_Object; function New_Class_Instance return Class_Type'Class is begin return New_Class_Object; end New_Class_Instance; end P; ---------------------------------------------------------------------------------------------------- Variant 2. Old good Ada initialization (in 80's we knew how to do it right) package P is type Class_Type is tagged limited record null; end record; function New_Class_Instance return Class_Type'Class; Conn : Class_Type; -- It will be OK upon the body elaboration! end P; package body P is procedure Construct (Object : in out Class_Type) is begin null; end Construct; function New_Class_Instance return Class_Type'Class is begin return X : Class_Type do Construct (X); end return; end New_Class_Instance; begin Construct (Conn); -- Fix it now end P; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Randy Brukardt on 1 Jun 2010 19:36 "Marc A. Criley" <mcNOSPAM(a)mckae.com> wrote in message news:c2ead$4c0150a0$4ca4a823$11809(a)API-DIGITAL.COM... .... > Stripping out a test case, I see that it has nothing to with the C++ > binding per se, but it's an Ada issue that's flummoxing me. Here's the > test code: > > procedure Dyty_Test is > > type Class_Type is tagged limited record > null; > end record; > > function New_Class_Instance return Class_Type'Class; > > Conn : Class_Type := New_Class_Instance; This is illegal because the function returns a class-wide object and you are assigning it into an object of a specific type. You have to explicitly use a type conversion here: Conn : Class_Type := Class_Type (New_Class_Instance); to specify that you want to truncate the returned object, or make the object classwide: Conn : Class_Type'Class := New_Class_Instance; But notice that while both of these are legal, they'll both raise Program_Error because an access-before-elaboration error (the body of New_Class_Instance hasn't been elaborated at the point of this call). Randy.
From: Yannick Duchêne (Hibou57) on 2 Jun 2010 22:36 Le Wed, 02 Jun 2010 01:36:17 +0200, Randy Brukardt <randy(a)rrsoftware.com> a écrit: > You have to explicitly use a > type conversion here: > > Conn : Class_Type := Class_Type (New_Class_Instance); > This one is not legal, as Class_Type is limited and conversion are not allowed on limited type due to their copy based semantic. [ARM 2005 4.6] says about type conversions âNeither the target type nor the operand type shall be limitedâ > to specify that you want to truncate the returned object, or make the > object > classwide: > > Conn : Class_Type'Class := New_Class_Instance; That is a beautiful one (to my eyes) > But notice that while both of these are legal, they'll both raise > Program_Error because an access-before-elaboration error (the body of > New_Class_Instance hasn't been elaborated at the point of this call). Not necessarily, as he can move the body of the function returning Class_Type before the declaration of the variable initialized from this function. Instead of function New_Class_Instance return Class_Type'Class; Conn : Class_Type := New_Class_Instance; function New_Class_Instance return Class_Type'Class is begin -- Just a stub return New_Class_Instance; end New_Class_Instance; Simply do function New_Class_Instance return Class_Type'Class; function New_Class_Instance return Class_Type'Class is begin -- Just a stub return New_Class_Instance; end New_Class_Instance; Conn : Class_Type := New_Class_Instance; and everything will go fine. -- There is even better than a pragma Assert: a SPARK --# check. --# check C and WhoKnowWhat and YouKnowWho; --# assert Ada; -- i.e. forget about previous premises which leads to conclusion -- and start with new conclusion as premise.
From: Yannick Duchêne (Hibou57) on 2 Jun 2010 22:37
Le Sat, 29 May 2010 20:23:36 +0200, Dmitry A. Kazakov <mailbox(a)dmitry-kazakov.de> a écrit: >> Conn : Class_Type := New_Class_Instance; > > Should Conn be mutable? Otherwise you could use a function instead. > Good note (formally talking). May be the reason was a matter of efficiency ? -- There is even better than a pragma Assert: a SPARK --# check. --# check C and WhoKnowWhat and YouKnowWho; --# assert Ada; -- i.e. forget about previous premises which leads to conclusion -- and start with new conclusion as premise. |