* How can one record component be local and another not? @ 2020-05-05 11:04 hreba 2020-05-05 11:33 ` AdaMagica ` (5 more replies) 0 siblings, 6 replies; 39+ messages in thread From: hreba @ 2020-05-05 11:04 UTC (permalink / raw) I have reduced my problem to the following example: package Aux is type Integer_P is access all Integer; type Rec is record a: aliased Integer; p: Integer_P; end record; procedure Init (r: in out Rec); end Aux; package body Aux is procedure Init (r: in out Rec) is begin r.p:= r.a'Access; -- <-- error! end Init; end Aux; Compiling results in "non-local pointer cannot point to local object" indicating the marked line above. How can one record component be local and another not? Intention is to have a library subprogram Init() for initialization. How would I implement that instead? (The reason for the above construction is the need to pass a pointer to a C library function.) -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:04 How can one record component be local and another not? hreba @ 2020-05-05 11:33 ` AdaMagica 2020-05-05 11:38 ` AdaMagica ` (2 more replies) 2020-05-05 11:43 ` AdaMagica ` (4 subsequent siblings) 5 siblings, 3 replies; 39+ messages in thread From: AdaMagica @ 2020-05-05 11:33 UTC (permalink / raw) Am Dienstag, 5. Mai 2020 13:04:56 UTC+2 schrieb hreba: > I have reduced my problem to the following example: > > package Aux is > type Integer_P is access all Integer; > type Rec is record > a: aliased Integer; > p: Integer_P; > end record; > > procedure Init (r: in out Rec); > end Aux; > > package body Aux is > procedure Init (r: in out Rec) is > begin > r.p:= r.a'Access; -- <-- error! > end Init; > end Aux; Imagine you define a local Rec: with Aux; procedure Proc is R: Aux.Rec; begin Aux.Init (R); end Proc; Now R has shorter lifetime than the access type Integer_P. Thus you might have somewhere an access object AO with longer lifetime than R and try to assign AO := R.P; Try Unrestricted_Access. ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:33 ` AdaMagica @ 2020-05-05 11:38 ` AdaMagica 2020-05-05 12:59 ` hreba 2020-05-05 14:32 ` hreba 2 siblings, 0 replies; 39+ messages in thread From: AdaMagica @ 2020-05-05 11:38 UTC (permalink / raw) Am Dienstag, 5. Mai 2020 13:33:08 UTC+2 schrieb AdaMagica: > Try Unrestricted_Access. But this will only work if Rec parameters are not transferred by copy. So perhaps this might be necessary (I'm not sure this helps): procedure Init (r: in out aliased Rec); ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:33 ` AdaMagica 2020-05-05 11:38 ` AdaMagica @ 2020-05-05 12:59 ` hreba 2020-05-05 13:19 ` J-P. Rosen 2020-05-05 13:37 ` Jere 2020-05-05 14:32 ` hreba 2 siblings, 2 replies; 39+ messages in thread From: hreba @ 2020-05-05 12:59 UTC (permalink / raw) On 5/5/20 1:33 PM, AdaMagica wrote: > Am Dienstag, 5. Mai 2020 13:04:56 UTC+2 schrieb hreba: >> I have reduced my problem to the following example: >> >> package Aux is >> type Integer_P is access all Integer; >> type Rec is record >> a: aliased Integer; >> p: Integer_P; >> end record; >> >> procedure Init (r: in out Rec); >> end Aux; >> >> package body Aux is >> procedure Init (r: in out Rec) is >> begin >> r.p:= r.a'Access; -- <-- error! >> end Init; >> end Aux; > > Imagine you define a local Rec: > > with Aux; > procedure Proc is > R: Aux.Rec; > begin > Aux.Init (R); > end Proc; > > Now R has shorter lifetime than the access type Integer_P. Thus you might have somewhere an access object AO with longer lifetime than R and try to assign > AO := R.P; > > Try Unrestricted_Access. > Don't understand that. R.a and R.p have exactly the same lifetime, which is the lifetime of R, haven't they? -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 12:59 ` hreba @ 2020-05-05 13:19 ` J-P. Rosen 2020-05-05 13:37 ` Jere 1 sibling, 0 replies; 39+ messages in thread From: J-P. Rosen @ 2020-05-05 13:19 UTC (permalink / raw) Le 05/05/2020 à 14:59, hreba a écrit : > Don't understand that. R.a and R.p have exactly the same lifetime, which > is the lifetime of R, haven't they? > But R.a can be assigned to any global object, with unlimited lifetime. Note that Unchecked_Access is not "dirty", it just reminds you that some responsabilities of compiler checks are passed on to you. It tells you: "beware with assignments". -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 12:59 ` hreba 2020-05-05 13:19 ` J-P. Rosen @ 2020-05-05 13:37 ` Jere 2020-05-05 14:28 ` hreba 1 sibling, 1 reply; 39+ messages in thread From: Jere @ 2020-05-05 13:37 UTC (permalink / raw) On Tuesday, May 5, 2020 at 8:59:21 AM UTC-4, hreba wrote: > On 5/5/20 1:33 PM, AdaMagica wrote: > > Am Dienstag, 5. Mai 2020 13:04:56 UTC+2 schrieb hreba: > >> I have reduced my problem to the following example: > >> > >> package Aux is > >> type Integer_P is access all Integer; > >> type Rec is record > >> a: aliased Integer; > >> p: Integer_P; > >> end record; > >> > >> procedure Init (r: in out Rec); > >> end Aux; > >> > >> package body Aux is > >> procedure Init (r: in out Rec) is > >> begin > >> r.p:= r.a'Access; -- <-- error! > >> end Init; > >> end Aux; > > > > Imagine you define a local Rec: > > > > with Aux; > > procedure Proc is > > R: Aux.Rec; > > begin > > Aux.Init (R); > > end Proc; > > > > Now R has shorter lifetime than the access type Integer_P. Thus you might have somewhere an access object AO with longer lifetime than R and try to assign > > AO := R.P; > > > > Try Unrestricted_Access. > > > > Don't understand that. R.a and R.p have exactly the same lifetime, which > is the lifetime of R, haven't they? > You are thinking about it in a way that looks at object lifetimes only. Ada often compares the lifetime of the access "type" to the lifetime of the object (called accessibility levels in the RM). I'm not sure why the decision to do it that way was made (I assume easier implementation at the time). I do know that some younger languages have worked out some pretty useful schemes for tracking object lifetimes along with the access variables. Rust comes to mind and SPARK is also coming along in that area as well. Additionally there are some rules concerning anonymous access types that allow a runtime checking of object lifetimes (as opposed to static checking of Rust and soon SPARK), but anonymous access types have a host of issues all their own and I don't know them well enough to comment on how to do that reliably. ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 13:37 ` Jere @ 2020-05-05 14:28 ` hreba 2020-05-05 15:18 ` AdaMagica 0 siblings, 1 reply; 39+ messages in thread From: hreba @ 2020-05-05 14:28 UTC (permalink / raw) > You are thinking about it in a way that looks at object lifetimes > only. Ada often compares the lifetime of the access "type" to the lifetime > of the object (called accessibility levels in the RM). I really never got aware that types too have a lifetime (visibility yes, but not lifetime). Ok, I'll have to observe this in future. Thanks for the explanation. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 14:28 ` hreba @ 2020-05-05 15:18 ` AdaMagica 0 siblings, 0 replies; 39+ messages in thread From: AdaMagica @ 2020-05-05 15:18 UTC (permalink / raw) Am Dienstag, 5. Mai 2020 16:28:26 UTC+2 schrieb hreba: > I really never got aware that types too have a lifetime (visibility yes, > but not lifetime). Ok, I'll have to observe this in future. Every declaration in Ada has a lifetime, except exceptions. These become anonymous if they leave the lifetime of their declaration. ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:33 ` AdaMagica 2020-05-05 11:38 ` AdaMagica 2020-05-05 12:59 ` hreba @ 2020-05-05 14:32 ` hreba 2 siblings, 0 replies; 39+ messages in thread From: hreba @ 2020-05-05 14:32 UTC (permalink / raw) > Now R has shorter lifetime than the access type Integer_P. At first read, I thought "access type Integer_P" was just a sloppy formulation for "variable of access type Integer_P". After learning from Jere (see below) that types too can have lifetimes, I understand. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:04 How can one record component be local and another not? hreba 2020-05-05 11:33 ` AdaMagica @ 2020-05-05 11:43 ` AdaMagica 2020-05-05 12:55 ` hreba 2020-05-05 11:46 ` Simon Wright ` (3 subsequent siblings) 5 siblings, 1 reply; 39+ messages in thread From: AdaMagica @ 2020-05-05 11:43 UTC (permalink / raw) Das ganze Konstrukt sieht sehr gefährlich aus! Copies will not point to the correct component: A, B: Rec; A := B; -- Peng! ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:43 ` AdaMagica @ 2020-05-05 12:55 ` hreba 0 siblings, 0 replies; 39+ messages in thread From: hreba @ 2020-05-05 12:55 UTC (permalink / raw) On 5/5/20 1:43 PM, AdaMagica wrote: > Das ganze Konstrukt sieht sehr gefährlich aus! Copies will not point to the correct component: > > A, B: Rec; > > A := B; -- Peng! > That is easy to solve: In my real application, Rec would be private anyway, so it could be made limited, and Init would be changed into a constructor function with result Rec. But first I wanted to solve (and understand) that local/non-local issue. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:04 How can one record component be local and another not? hreba 2020-05-05 11:33 ` AdaMagica 2020-05-05 11:43 ` AdaMagica @ 2020-05-05 11:46 ` Simon Wright 2020-05-05 13:07 ` hreba 2020-05-05 11:48 ` Niklas Holsti ` (2 subsequent siblings) 5 siblings, 1 reply; 39+ messages in thread From: Simon Wright @ 2020-05-05 11:46 UTC (permalink / raw) hreba <f_hreba@yahoo.com.br> writes: > package body Aux is > procedure Init (r: in out Rec) is > begin > r.p:= r.a'Access; -- <-- error! > end Init; > end Aux; 'Unchecked_Access does the job (but this is outside my language-lawyering abilities!) ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:46 ` Simon Wright @ 2020-05-05 13:07 ` hreba 2020-05-05 17:00 ` Dmitry A. Kazakov 0 siblings, 1 reply; 39+ messages in thread From: hreba @ 2020-05-05 13:07 UTC (permalink / raw) On 5/5/20 1:46 PM, Simon Wright wrote: > hreba <f_hreba@yahoo.com.br> writes: > >> package body Aux is >> procedure Init (r: in out Rec) is >> begin >> r.p:= r.a'Access; -- <-- error! >> end Init; >> end Aux; > > 'Unchecked_Access does the job (but this is outside my language-lawyering > abilities!) > Didn't expect that from you indeed. Besides "doing the job", what would be a clean solution (of a task that seems so basic to me)? -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 13:07 ` hreba @ 2020-05-05 17:00 ` Dmitry A. Kazakov 0 siblings, 0 replies; 39+ messages in thread From: Dmitry A. Kazakov @ 2020-05-05 17:00 UTC (permalink / raw) On 2020-05-05 15:07, hreba wrote: > On 5/5/20 1:46 PM, Simon Wright wrote: >> hreba <f_hreba@yahoo.com.br> writes: >> >>> package body Aux is >>> procedure Init (r: in out Rec) is >>> begin >>> r.p:= r.a'Access; -- <-- error! >>> end Init; >>> end Aux; >> >> 'Unchecked_Access does the job (but this is outside my language-lawyering >> abilities!) >> > > Didn't expect that from you indeed. Besides "doing the job", what would > be a clean solution (of a task that seems so basic to me)? There is no clean solution, because Rec is not limited or controlled. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:04 How can one record component be local and another not? hreba ` (2 preceding siblings ...) 2020-05-05 11:46 ` Simon Wright @ 2020-05-05 11:48 ` Niklas Holsti 2020-05-05 13:44 ` hreba 2020-05-05 15:45 ` Jeffrey R. Carter 2020-05-05 17:32 ` hreba 5 siblings, 1 reply; 39+ messages in thread From: Niklas Holsti @ 2020-05-05 11:48 UTC (permalink / raw) On 2020-05-05 14:04, hreba wrote: > I have reduced my problem to the following example: > > package Aux is > type Integer_P is access all Integer; > type Rec is record > a: aliased Integer; > p: Integer_P; > end record; > > procedure Init (r: in out Rec); > end Aux; > > package body Aux is > procedure Init (r: in out Rec) is > begin > r.p:= r.a'Access; -- <-- error! > end Init; > end Aux; > > Compiling results in "non-local pointer cannot point to local object" > indicating the marked line above. > > How can one record component be local and another not? > > Intention is to have a library subprogram Init() for initialization. How > would I implement that instead? > > (The reason for the above construction is the need to pass a pointer to > a C library function.) > The parameter "r" might be passed by copy, in which case the r.a'Access would point to the local copy, and become a dangling pointer on return (copy-out). It works if you replace "r: in out" with "r : access", which ensures pass by reference. It did not work for me (same error message) if I just added "aliased", making "r : aliased in out Rec", although I think that should also be enough to ensure pass by reference. This was on GNAT Community 2019 (20190517-83), Mac. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:48 ` Niklas Holsti @ 2020-05-05 13:44 ` hreba 0 siblings, 0 replies; 39+ messages in thread From: hreba @ 2020-05-05 13:44 UTC (permalink / raw) On 5/5/20 1:48 PM, Niklas Holsti wrote: > On 2020-05-05 14:04, hreba wrote: >> I have reduced my problem to the following example: >> >> package Aux is >> type Integer_P is access all Integer; >> type Rec is record >> a: aliased Integer; >> p: Integer_P; >> end record; >> >> procedure Init (r: in out Rec); >> end Aux; >> >> package body Aux is >> procedure Init (r: in out Rec) is >> begin >> r.p:= r.a'Access; -- <-- error! >> end Init; >> end Aux; >> >> Compiling results in "non-local pointer cannot point to local object" >> indicating the marked line above. >> >> How can one record component be local and another not? >> >> Intention is to have a library subprogram Init() for initialization. >> How would I implement that instead? >> >> (The reason for the above construction is the need to pass a pointer >> to a C library function.) >> > > The parameter "r" might be passed by copy, in which case the r.a'Access > would point to the local copy, and become a dangling pointer on return > (copy-out). Now I understand. > It works if you replace "r: in out" with "r : access", which ensures > pass by reference. Perfect, works indeed. Thanks a lot. I tried another thing too: Changed Init into a constructor function returning r in an extended return statement. Didn't work. So even an extended return statement seems to create a local copy first. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:04 How can one record component be local and another not? hreba ` (3 preceding siblings ...) 2020-05-05 11:48 ` Niklas Holsti @ 2020-05-05 15:45 ` Jeffrey R. Carter 2020-05-05 17:17 ` hreba 2020-05-05 17:32 ` hreba 5 siblings, 1 reply; 39+ messages in thread From: Jeffrey R. Carter @ 2020-05-05 15:45 UTC (permalink / raw) On 5/5/20 1:04 PM, hreba wrote: > > (The reason for the above construction is the need to pass a pointer to a C > library function.) Most likely you do not need to pass a pointer to your C function. For example, given the C function void f (int* i); You can do procedure F (I : in out Interfaces.C.int) with Import, Convention => C, ...; and the compiler will call the C function correctly. -- Jeff Carter "[T]he Musgroves had had the ill fortune of a very troublesome, hopeless son, and the good fortune to lose him before he reached his twentieth year ..." Persuasion 154 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 15:45 ` Jeffrey R. Carter @ 2020-05-05 17:17 ` hreba 2020-05-05 19:08 ` Niklas Holsti ` (2 more replies) 0 siblings, 3 replies; 39+ messages in thread From: hreba @ 2020-05-05 17:17 UTC (permalink / raw) On 5/5/20 5:45 PM, Jeffrey R. Carter wrote: > On 5/5/20 1:04 PM, hreba wrote: >> >> (The reason for the above construction is the need to pass a pointer >> to a C library function.) > > Most likely you do not need to pass a pointer to your C function. For > example, given the C function > > void f (int* i); > > You can do > > procedure F (I : in out Interfaces.C.int) with Import, Convention => C, > ...; > > and the compiler will call the C function correctly. > It is more complicated, unfortunately. I got type gsl_odeiv2_system is record c_function : access function (arg1 : double; arg2 : access double; arg3 : access double; arg4 : System.Address) return int; -- /usr/include/gsl/gsl_odeiv2.h:58 jacobian : access function (arg1 : double; arg2 : access double; arg3 : access double; arg4 : access double; arg5 : System.Address) return int; -- /usr/include/gsl/gsl_odeiv2.h:60 dimension : aliased size_t; -- /usr/include/gsl/gsl_odeiv2.h:61 params : System.Address; -- /usr/include/gsl/gsl_odeiv2.h:62 end record; pragma Convention (C_Pass_By_Copy, gsl_odeiv2_system); -- /usr/include/gsl/gsl_odeiv2.h:64 and I have to pass a variable sys: access gsl_odeiv2_system to the initialization function of that C library, and the params: System.Address; component in the record, which internally is then passed to c_function() and jacobian(), posed the problem. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 17:17 ` hreba @ 2020-05-05 19:08 ` Niklas Holsti 2020-05-06 19:31 ` hreba 2020-05-05 19:19 ` Jere 2020-05-06 6:42 ` Mark Lorenzen 2 siblings, 1 reply; 39+ messages in thread From: Niklas Holsti @ 2020-05-05 19:08 UTC (permalink / raw) On 2020-05-05 20:17, hreba wrote: > On 5/5/20 5:45 PM, Jeffrey R. Carter wrote: >> On 5/5/20 1:04 PM, hreba wrote: >>> >>> (The reason for the above construction is the need to pass a pointer >>> to a C library function.) >> >> Most likely you do not need to pass a pointer to your C function. For >> example, given the C function >> >> void f (int* i); >> >> You can do >> >> procedure F (I : in out Interfaces.C.int) with Import, Convention => >> C, ...; >> >> and the compiler will call the C function correctly. >> > > It is more complicated, unfortunately. I got > > type gsl_odeiv2_system is record > c_function : access function > (arg1 : double; > arg2 : access double; > arg3 : access double; > arg4 : System.Address) return int; -- > /usr/include/gsl/gsl_odeiv2.h:58 > jacobian : access function > (arg1 : double; > arg2 : access double; > arg3 : access double; > arg4 : access double; > arg5 : System.Address) return int; -- > /usr/include/gsl/gsl_odeiv2.h:60 > dimension : aliased size_t; -- /usr/include/gsl/gsl_odeiv2.h:61 > params : System.Address; -- /usr/include/gsl/gsl_odeiv2.h:62 > end record; > pragma Convention (C_Pass_By_Copy, gsl_odeiv2_system); -- > /usr/include/gsl/gsl_odeiv2.h:64 > > and I have to pass a variable > sys: access gsl_odeiv2_system > to the initialization function of that C library, and the > > params: System.Address; > > component in the record, which internally is then passed to c_function() > and jacobian(), posed the problem. I don't understand -- System.Address is not an access type; why do you need to use an access type to produce this parameter? Do you need a pointer to the "params" component? Perhaps you can show a bit more of the actual code that has the problem? -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 19:08 ` Niklas Holsti @ 2020-05-06 19:31 ` hreba 2020-05-09 19:43 ` Niklas Holsti 0 siblings, 1 reply; 39+ messages in thread From: hreba @ 2020-05-06 19:31 UTC (permalink / raw) On 5/5/20 9:08 PM, Niklas Holsti wrote: > > I don't understand -- System.Address is not an access type; why do you > need to use an access type to produce this parameter? Do you need a > pointer to the "params" component? > > Perhaps you can show a bit more of the actual code that has the problem? > Ok, I'll try to make it comprehensible without throwing a lot of code at you. I am writing a thick binding to the GSL library odeiv2 for numerically integrating ODEs (ordinary differential equations). I already have the thin binding gsl_odeiv2_h.ads. For initialization, I have to call the following subprogram of the thin binding: function gsl_odeiv2_driver_alloc_y_new (sys : access constant gsl_odeiv2_system; T : access constant gsl_odeiv2_step_type; hstart : double; epsabs : double; epsrel : double) return access gsl_odeiv2_driver; pragma Import (C, gsl_odeiv2_driver_alloc_y_new, "gsl_odeiv2_driver_alloc_y_new"); Parameter sys defines the ODE; its type is type gsl_odeiv2_system is record c_function : access function (arg1 : double; arg2 : access double; arg3 : access double; arg4 : System.Address) return int; jacobian : access function (arg1 : double; arg2 : access double; arg3 : access double; arg4 : access double; arg5 : System.Address) return int; dimension : aliased size_t; params : System.Address; end record; pragma Convention (C_Pass_By_Copy, gsl_odeiv2_system); Later, during integration, c_function() and jacobian() will be called with parameters of type System.Address (arg4 and arg5 resp.). These parameters must be passed as params inside sys to gsl_odeiv2_driver_alloc_y_new(). Now to my own code (most of the thin binding was created automatically with g++ -c -fdump-ada-spec-slim). Dglsys_P corresponds to c_function in the thin binding, The package is essentially generic dim: Positive; type Float is digits<>; package odeiv2 is err_noInit, -- Init_Solve() has not been called err_Precision, -- precision of C.double used in GSL not sufficient err_Method, -- integration method not implemented err_SolveAgain: -- Solve_Again() call without former Solve() Exception; type Float_Array is array (1..dim) of Float; type Float_Matrix is array (1..dim, 1..dim) of Float; type Par_Array is array (Positive range <>) of Float; type Method is (RK8PD); type Solver is limited private; type Dglsys_P is not null access procedure (t: Float; -- independent variable y: Float_Array; -- dependent variables at t dydt: out Float_Array; -- 1. ordinary derivatives at t params: Par_Array -- any parameters ); -- omitted: type Jacobi_P is access procedure... procedure Init_Solve -- Init. a dglsys, must be called once before calling -- (once or repeatedly) Solve() or Solve_Again(). -- The resulting sol must be an access type because of the internal -- interface to the GSL library. (Dglsys: Dglsys_P; -- the system of diff. equ. Jacobi: Jacobi_P; -- the jacobi calc., if avail. pars: access constant Par_Array; -- the parameters met: Method; -- the solve method h_start: Float; -- initial step size epsabs: Float; -- absolute error tolerance epsrel: Float; -- relative error tolerance sol: aliased in out Solver ); private package C renames Interfaces.C; package Ode renames gsl_odeiv2_h; type C_Array is array (Integer range <>) of aliased C.double; pragma Convention (C, C_Array); type Parameters is record dglpars: access constant Par_Array; -- pars of dglsys Dglsys: Dglsys_P; -- dglsys calc. Jacobi: Jacobi_P; -- Jacobi calc. end record; pragma Convention (C, Parameters); type Parameters_Ptr is access all Parameters; package Parameters_Conv is new System.Address_To_Access_Conversions (Parameters); type Solver is limited record initialized: Boolean:= false; -- Init_Solve() has been called firstcall_done: Boolean; -- first call done store_y: Boolean; -- copy y to ya ya: C_Array (1..dim); -- values of last Solve call sys: aliased Ode.gsl_odeiv2_system; driver: access Ode.gsl_odeiv2_driver; all_pars: aliased Parameters; all_pp: Parameters_Conv.Object_Pointer; end record; end odeiv2; In the package body I have to define the c_function above (thin binding spec.), which will call the corresponding function of type Dglsys_P (thick binding), and it finds this in the parameters. then I define the initialization subprogram. package body odeiv2 is package C_Arrays is new Interfaces.C.Pointers (Integer, C.double, C_Array, 0.0); function func (t: C.double; y,f: access C.double; params: System.Address) return C.int; pragma Convention (C, func); function func (t: C.double; y,f: access C.double; params: System.Address) return C.int -- GSL version of Dglsys is use type System.Address; all_pars: Parameters_Conv.Object_Pointer; yf, dydt: Float_Array; y0: C_Arrays.Pointer:= C_Arrays.Pointer(y); f0: C_Arrays.Pointer:= C_Arrays.Pointer(f); begin all_pars:= Parameters_Conv.To_Pointer (params); for i in 1..dim loop yf(i):= Float(y0.all); C_Arrays.Increment (y0); end loop; all_pars.Dglsys (Float(t), yf, dydt, all_pars.dglpars.all); for i in 1..dim loop f0.all:= C.double(dydt(i)); C_Arrays.Increment (f0); end loop; return gsl_errno_h.GSL_SUCCESS; end func; procedure Init_Solve (Dglsys: Dglsys_P; -- the system of diff.equ. Jacobi: Jacobi_P; -- jacobi calc., if available pars: access constant Par_Array; -- the parameters met: Method; -- the solve method h_start: Float; -- initial step size epsabs: Float; -- absolute error tolerance epsrel: Float; -- relative error tolerance sol: aliased in out Solver ) is gsl_met: access constant Ode.gsl_odeiv2_step_type; begin -- set all_pars -- sol: flags for calling logic sol.Initialized:= true; sol.firstcall_done:= false; sol.store_y:= true; sol.all_pars.dglpars:= pars; sol.all_pars.Dglsys:= Dglsys; sol.all_pars.Jacobi:= Jacobi; -- transform integration method to GSL format case met is when RK8PD => gsl_met:= Ode.gsl_odeiv2_step_rk8pd; when others => raise err_Method with "forgot to implement integration method"; end case; -- build sys and driver sol.all_pp:= sol.all_pars'Unchecked_Access; sol.sys:= (func'Access, jac'Access, C.size_t(dim), Parameters_Conv.To_Address (sol.all_pp)); sol.driver:= Ode.gsl_odeiv2_driver_alloc_y_new (sol.sys'Access, gsl_met, C.double(h_start), C.double(epsabs), C.double(epsrel)); end Init_Solve; -- %< ------------- end odeiv2; The above version compiles. At first I didn't have the Solver component all_pp, but passed app_pars'Address to the call of gsl_odeiv2_driver_alloc_y_new at the end of Init_Solve. It too compiled. But whatever I try, I don't get rid of the runtime error raised CONSTRAINT_ERROR : odeiv2.ads:92:4 access check failed It accuses the line type Parameters is record -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-06 19:31 ` hreba @ 2020-05-09 19:43 ` Niklas Holsti 2020-05-10 15:10 ` hreba 0 siblings, 1 reply; 39+ messages in thread From: Niklas Holsti @ 2020-05-09 19:43 UTC (permalink / raw) On 2020-05-06 22:31, hreba wrote: > On 5/5/20 9:08 PM, Niklas Holsti wrote: >> >> I don't understand -- System.Address is not an access type; why do you >> need to use an access type to produce this parameter? Do you need a >> pointer to the "params" component? >> >> Perhaps you can show a bit more of the actual code that has the problem? >> > > Ok, I'll try to make it comprehensible without throwing a lot of code at > you. Thanks, and apologies for a late response (and this isn't a full response yet). [snip] > sol.all_pp:= sol.all_pars'Unchecked_Access; [snip] > The above version compiles. At first I didn't have the Solver component > all_pp, but passed app_pars'Address to the call of > gsl_odeiv2_driver_alloc_y_new at the end of Init_Solve. It too compiled. > > But whatever I try, I don't get rid of the runtime error > > raised CONSTRAINT_ERROR : odeiv2.ads:92:4 access check failed Do you mean that the exception occurs even with Unchecked_Access (as in the code you displayed) instead of plain Access? > It accuses the line > > type Parameters is record If the exception still happens with Unchecked_Access, can you get a full trace-back to show where the accessibility check is invoked? -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-09 19:43 ` Niklas Holsti @ 2020-05-10 15:10 ` hreba 0 siblings, 0 replies; 39+ messages in thread From: hreba @ 2020-05-10 15:10 UTC (permalink / raw) Hi Niklas, Problem resolved: One of the components of Parameters is a not null access type, and I didn't initialize the instance right at the declaration, so for a short time the component was null. I localized the error with -gnatD, which I found only now and only by chance. Thanks again for your helpfulness. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 17:17 ` hreba 2020-05-05 19:08 ` Niklas Holsti @ 2020-05-05 19:19 ` Jere 2020-05-06 6:42 ` Mark Lorenzen 2 siblings, 0 replies; 39+ messages in thread From: Jere @ 2020-05-05 19:19 UTC (permalink / raw) On Tuesday, May 5, 2020 at 1:17:42 PM UTC-4, hreba wrote: > On 5/5/20 5:45 PM, Jeffrey R. Carter wrote: > > On 5/5/20 1:04 PM, hreba wrote: > >> > >> (The reason for the above construction is the need to pass a pointer > >> to a C library function.) > > > > Most likely you do not need to pass a pointer to your C function. For > > example, given the C function > > > > void f (int* i); > > > > You can do > > > > procedure F (I : in out Interfaces.C.int) with Import, Convention => C, > > ...; > > > > and the compiler will call the C function correctly. > > > > It is more complicated, unfortunately. I got > > type gsl_odeiv2_system is record > c_function : access function > (arg1 : double; > arg2 : access double; > arg3 : access double; > arg4 : System.Address) return int; -- > /usr/include/gsl/gsl_odeiv2.h:58 > jacobian : access function > (arg1 : double; > arg2 : access double; > arg3 : access double; > arg4 : access double; > arg5 : System.Address) return int; -- > /usr/include/gsl/gsl_odeiv2.h:60 > dimension : aliased size_t; -- /usr/include/gsl/gsl_odeiv2.h:61 > params : System.Address; -- /usr/include/gsl/gsl_odeiv2.h:62 > end record; > pragma Convention (C_Pass_By_Copy, gsl_odeiv2_system); -- > /usr/include/gsl/gsl_odeiv2.h:64 > > and I have to pass a variable > sys: access gsl_odeiv2_system > to the initialization function of that C library, and the > > params: System.Address; > > component in the record, which internally is then passed to c_function() > and jacobian(), posed the problem. > > -- > Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 This isn't so much a question for you directly...maybe more for those more experienced with the RM, but I was curious about the implications of having an "aliased" parameter inside a record with a C convention specified. For some reason, I thought that the aliased keyword implied a certain alignment in Ada (not necessarily in C) and didn't know if specifying the convention undid that alignment or if there is a risk of the record not always being the same layout/alignment as the expected C struct for the aliased parameter. ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 17:17 ` hreba 2020-05-05 19:08 ` Niklas Holsti 2020-05-05 19:19 ` Jere @ 2020-05-06 6:42 ` Mark Lorenzen 2020-05-06 8:26 ` Simon Wright 2 siblings, 1 reply; 39+ messages in thread From: Mark Lorenzen @ 2020-05-06 6:42 UTC (permalink / raw) On Tuesday, May 5, 2020 at 7:17:42 PM UTC+2, hreba wrote: > On 5/5/20 5:45 PM, Jeffrey R. Carter wrote: > > On 5/5/20 1:04 PM, hreba wrote: > >> > >> (The reason for the above construction is the need to pass a pointer > >> to a C library function.) > > > > Most likely you do not need to pass a pointer to your C function. For > > example, given the C function > > > > void f (int* i); > > > > You can do > > > > procedure F (I : in out Interfaces.C.int) with Import, Convention => C, > > ...; > > > > and the compiler will call the C function correctly. > > > > It is more complicated, unfortunately. I got > > type gsl_odeiv2_system is record > c_function : access function > (arg1 : double; > arg2 : access double; > arg3 : access double; > arg4 : System.Address) return int; -- > /usr/include/gsl/gsl_odeiv2.h:58 > jacobian : access function > (arg1 : double; > arg2 : access double; > arg3 : access double; > arg4 : access double; > arg5 : System.Address) return int; -- > /usr/include/gsl/gsl_odeiv2.h:60 > dimension : aliased size_t; -- /usr/include/gsl/gsl_odeiv2.h:61 > params : System.Address; -- /usr/include/gsl/gsl_odeiv2.h:62 > end record; > pragma Convention (C_Pass_By_Copy, gsl_odeiv2_system); -- > /usr/include/gsl/gsl_odeiv2.h:64 > > and I have to pass a variable > sys: access gsl_odeiv2_system > to the initialization function of that C library, and the > > params: System.Address; > > component in the record, which internally is then passed to c_function() > and jacobian(), posed the problem. > > -- > Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 You need to step back and try to get an overview of what you are trying to achieve - not blindly copy some low-level C construct. Figure out why those C functions take parameters of an access type. Are they in/out or out parameters? Then define the Ada equivalent of those function access types e.g: type C_Function_Access is access function (Arg1 : double; Arg2 : in out double; Arg3 : in out double; Arg4 : in System.Address) return int with Convention => C; Note that in Ada 2012 functions are unfortunately allowed to have in/out-mode and out-mode parameters. In previous revisions, functions were only allowed to have in-mode parameters. As explained by Jeffrey R. Carter above, Convention => C guarantees that in/out-mode and out-mode parameters are passed by value. Your record type then becomes something like: type GSL_Odeiv2_System is record C_Function : C_Function_Access; ... end record with Convention C_Pass_By_Copy; You are trying to create an Ada interface to C, but you are dragging the low-level nature of C into your Ada. When you encounter access types and addresses in Ada, then step back and try to get an overview of what needs to be achieved - not how it is done in C and thus mechanically copied in the auto-generated Ada code. Regards, Mark L ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-06 6:42 ` Mark Lorenzen @ 2020-05-06 8:26 ` Simon Wright 2020-05-06 8:33 ` Mark Lorenzen 0 siblings, 1 reply; 39+ messages in thread From: Simon Wright @ 2020-05-06 8:26 UTC (permalink / raw) Mark Lorenzen <mark.lorenzen@gmail.com> writes: > As explained by Jeffrey R. Carter above, Convention => C guarantees > that in/out-mode and out-mode parameters are passed by value. By address, surely? ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-06 8:26 ` Simon Wright @ 2020-05-06 8:33 ` Mark Lorenzen 0 siblings, 0 replies; 39+ messages in thread From: Mark Lorenzen @ 2020-05-06 8:33 UTC (permalink / raw) On Wednesday, May 6, 2020 at 10:26:14 AM UTC+2, Simon Wright wrote: > Mark Lorenzen writes: > > > As explained by Jeffrey R. Carter above, Convention => C guarantees > > that in/out-mode and out-mode parameters are passed by value. > > By address, surely? Bummer! Yes - by address! Regards, Mark L ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 11:04 How can one record component be local and another not? hreba ` (4 preceding siblings ...) 2020-05-05 15:45 ` Jeffrey R. Carter @ 2020-05-05 17:32 ` hreba 2020-05-05 19:04 ` Niklas Holsti 2020-05-06 17:30 ` Niklas Holsti 5 siblings, 2 replies; 39+ messages in thread From: hreba @ 2020-05-05 17:32 UTC (permalink / raw) Ok, with all your hints I came to the following solution: -- package Aux is type Integer_P is access all Integer; type Rec is limited record a: aliased Integer; p: Integer_P; end record; procedure Init (r: access Rec); end Aux; -- package body Aux is procedure Init (r: access Rec) is begin r.p:= r.a'Access; end Init; end Aux; -- with Aux; procedure Test is r: aliased Aux.Rec; begin Aux.Init (r'Access); end Test; -- It compiles nicely, and then: frank@pc-frank:~/Temp/Test0$ ./test raised PROGRAM_ERROR : aux.adb:4 accessibility check failed #@!!0ßx*~@!!! -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 17:32 ` hreba @ 2020-05-05 19:04 ` Niklas Holsti 2020-05-05 20:11 ` Niklas Holsti 2020-05-06 17:30 ` Niklas Holsti 1 sibling, 1 reply; 39+ messages in thread From: Niklas Holsti @ 2020-05-05 19:04 UTC (permalink / raw) On 2020-05-05 20:32, hreba wrote: > Ok, with all your hints I came to the following solution: > > -- > package Aux is > type Integer_P is access all Integer; > type Rec is limited record > a: aliased Integer; > p: Integer_P; > end record; > > procedure Init (r: access Rec); > end Aux; > -- > package body Aux is > procedure Init (r: access Rec) is > begin > r.p:= r.a'Access; > end Init; > end Aux; > -- > with Aux; > procedure Test is > r: aliased Aux.Rec; > begin > Aux.Init (r'Access); > end Test; > -- > > It compiles nicely, and then: > > frank@pc-frank:~/Temp/Test0$ ./test > raised PROGRAM_ERROR : aux.adb:4 accessibility check failed > > #@!!0ßx*~@!!! Ok, apologies if I led you down the wrong path. I admit I did not build a running program to check my suggestion of the "access" parameter, and I have not myself often used this kind of code. You should be able to get rid of this error by using r.a'Unchecked_Access instead of r.a'Access, and then (I think) you can return to using an "in out" parameter mode instead of "access" mode. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 19:04 ` Niklas Holsti @ 2020-05-05 20:11 ` Niklas Holsti 2020-05-06 13:13 ` hreba 0 siblings, 1 reply; 39+ messages in thread From: Niklas Holsti @ 2020-05-05 20:11 UTC (permalink / raw) On 2020-05-05 22:04, Niklas Holsti wrote: > On 2020-05-05 20:32, hreba wrote: >> Ok, with all your hints I came to the following solution: >> >> -- >> package Aux is >> type Integer_P is access all Integer; >> type Rec is limited record >> a: aliased Integer; >> p: Integer_P; >> end record; >> >> procedure Init (r: access Rec); >> end Aux; >> -- >> package body Aux is >> procedure Init (r: access Rec) is >> begin >> r.p:= r.a'Access; >> end Init; >> end Aux; >> -- >> with Aux; >> procedure Test is >> r: aliased Aux.Rec; >> begin >> Aux.Init (r'Access); >> end Test; >> -- >> >> It compiles nicely, and then: >> >> frank@pc-frank:~/Temp/Test0$ ./test >> raised PROGRAM_ERROR : aux.adb:4 accessibility check failed >> >> #@!!0ßx*~@!!! > > Ok, apologies if I led you down the wrong path. I admit I did not build > a running program to check my suggestion of the "access" parameter, and > I have not myself often used this kind of code. > > You should be able to get rid of this error by using > r.a'Unchecked_Access instead of r.a'Access, and then (I think) you can > return to using an "in out" parameter mode instead of "access" mode. ... but better make it "aliased in out" to ensure pass-by-reference. I do agree with Dmitry that records with internal pointers-to-component should be "limited" or "controlled". -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 20:11 ` Niklas Holsti @ 2020-05-06 13:13 ` hreba 0 siblings, 0 replies; 39+ messages in thread From: hreba @ 2020-05-06 13:13 UTC (permalink / raw) On 5/5/20 10:11 PM, Niklas Holsti wrote: > On 2020-05-05 22:04, Niklas Holsti wrote: >> On 2020-05-05 20:32, hreba wrote: >>> Ok, with all your hints I came to the following solution: >>> >>> -- >>> package Aux is >>> type Integer_P is access all Integer; >>> type Rec is limited record >>> a: aliased Integer; >>> p: Integer_P; >>> end record; >>> >>> procedure Init (r: access Rec); >>> end Aux; >>> -- >>> package body Aux is >>> procedure Init (r: access Rec) is >>> begin >>> r.p:= r.a'Access; >>> end Init; >>> end Aux; >>> -- >>> with Aux; >>> procedure Test is >>> r: aliased Aux.Rec; >>> begin >>> Aux.Init (r'Access); >>> end Test; >>> -- >>> >>> It compiles nicely, and then: >>> >>> frank@pc-frank:~/Temp/Test0$ ./test >>> raised PROGRAM_ERROR : aux.adb:4 accessibility check failed >>> >>> #@!!0ßx*~@!!! >> >> Ok, apologies if I led you down the wrong path. I admit I did not >> build a running program to check my suggestion of the "access" >> parameter, and I have not myself often used this kind of code. >> >> You should be able to get rid of this error by using >> r.a'Unchecked_Access instead of r.a'Access, and then (I think) you can >> return to using an "in out" parameter mode instead of "access" mode. > > ... but better make it "aliased in out" to ensure pass-by-reference. Perfect Niklas, all your proposed variants work! > I do agree with Dmitry that records with internal pointers-to-component > should be "limited" or "controlled". Did that already, as you can see above. It was a recurring issue for me but only now I understood it and know how to solve it. Thanks a lot for your help. -- Frank Hrebabetzky, Kronach +49 / 9261 / 950 0565 ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-05 17:32 ` hreba 2020-05-05 19:04 ` Niklas Holsti @ 2020-05-06 17:30 ` Niklas Holsti 2020-05-06 18:28 ` Jere 2020-05-07 9:07 ` J-P. Rosen 1 sibling, 2 replies; 39+ messages in thread From: Niklas Holsti @ 2020-05-06 17:30 UTC (permalink / raw) On 2020-05-05 20:32, hreba wrote: > Ok, with all your hints I came to the following solution: > > -- > package Aux is > type Integer_P is access all Integer; > type Rec is limited record > a: aliased Integer; > p: Integer_P; > end record; > > procedure Init (r: access Rec); > end Aux; > -- > package body Aux is > procedure Init (r: access Rec) is > begin > r.p:= r.a'Access; > end Init; > end Aux; > -- > with Aux; > procedure Test is > r: aliased Aux.Rec; > begin > Aux.Init (r'Access); > end Test; > -- > > It compiles nicely, and then: > > frank@pc-frank:~/Temp/Test0$ ./test > raised PROGRAM_ERROR : aux.adb:4 accessibility check failed > > #@!!0ßx*~@!!! Just to close out this issue, I wrote some test programs and explored various changes. I believe the reason for this exception is that the accessibility level of the object "Test.r" is local, nested in the procedure "Test" (so "r" exists only for the relevant call of "Test") while the access type "Integer_P" is library-level and so out-lasts the call of "Test". Note that, although "Test" here is no doubt the program's main subprogram and so its call (assuming it is not recursive) lasts almost as long as the execution of the program, the compiler does not make use of this fact to determine the life-times of types and objects in "Test". If "r" is moved to a package, to be a statically allocated, library-level object, "Aux.Init (r'Access)" works without raising this exception. Somewhat surprisingly to me, any call of the form "Aux.Init (r'Unchecked_Access)" also works, whether "r" is a library-level object or a local (limited-life) object, even if "Aux.Init" itself uses "'Access" and not "'Unchecked_Access". Apparently the accessibility level provided in the value of Unchecked_Access is such as to make the check succeed, as for a library-level object. I also found that a call like "Aux.Init (new Aux.Rec)", which applies "Aux.Init" to a heap-allocated "Rec" object, fails the accessibility check, so this check is really strict. Of course, the heap object can be deallocated at any time, so it may have a short life-time, but that can be done (mainly) by Unchecked_Deallocation, so it involves "unchecked" programming. Hm. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-06 17:30 ` Niklas Holsti @ 2020-05-06 18:28 ` Jere 2020-05-06 19:09 ` Niklas Holsti 2020-05-07 9:07 ` J-P. Rosen 1 sibling, 1 reply; 39+ messages in thread From: Jere @ 2020-05-06 18:28 UTC (permalink / raw) On Wednesday, May 6, 2020 at 1:30:58 PM UTC-4, Niklas Holsti wrote: > On 2020-05-05 20:32, hreba wrote: > > Ok, with all your hints I came to the following solution: > > > > -- > > package Aux is > > type Integer_P is access all Integer; > > type Rec is limited record > > a: aliased Integer; > > p: Integer_P; > > end record; > > > > procedure Init (r: access Rec); > > end Aux; > > -- > > package body Aux is > > procedure Init (r: access Rec) is > > begin > > r.p:= r.a'Access; > > end Init; > > end Aux; > > -- > > with Aux; > > procedure Test is > > r: aliased Aux.Rec; > > begin > > Aux.Init (r'Access); > > end Test; > > -- > > > <SNIPPED> > Somewhat surprisingly to me, any call of the form > "Aux.Init (r'Unchecked_Access)" also works, whether "r" is a > library-level object or a local (limited-life) object, even if > "Aux.Init" itself uses "'Access" and not "'Unchecked_Access". Apparently > the accessibility level provided in the value of Unchecked_Access is > such as to make the check succeed, as for a library-level object. > Yeah, RM section 13.10 says it treats it as if the object were declared at library level for Unchecked_Access > I also found that a call like "Aux.Init (new Aux.Rec)", which applies > "Aux.Init" to a heap-allocated "Rec" object, fails the accessibility > check, so this check is really strict. Of course, the heap object can be > deallocated at any time, so it may have a short life-time, but that can > be done (mainly) by Unchecked_Deallocation, so it involves "unchecked" > programming. Hm. > Is that because the heap allocated object is allocated using an anonymous access type instead of a named access type per chance? I know anonymous access types have different accessibility level rules. It might be setting the accessibility level to the point of call maybe? ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-06 18:28 ` Jere @ 2020-05-06 19:09 ` Niklas Holsti 0 siblings, 0 replies; 39+ messages in thread From: Niklas Holsti @ 2020-05-06 19:09 UTC (permalink / raw) On 2020-05-06 21:28, Jere wrote: > On Wednesday, May 6, 2020 at 1:30:58 PM UTC-4, Niklas Holsti wrote: >> On 2020-05-05 20:32, hreba wrote: >>> Ok, with all your hints I came to the following solution: >>> >>> -- >>> package Aux is >>> type Integer_P is access all Integer; >>> type Rec is limited record >>> a: aliased Integer; >>> p: Integer_P; >>> end record; >>> >>> procedure Init (r: access Rec); >>> end Aux; >>> -- >>> package body Aux is >>> procedure Init (r: access Rec) is >>> begin >>> r.p:= r.a'Access; >>> end Init; >>> end Aux; >>> -- >>> with Aux; >>> procedure Test is >>> r: aliased Aux.Rec; >>> begin >>> Aux.Init (r'Access); >>> end Test; >>> -- >>> >> <SNIPPED> >> Somewhat surprisingly to me, any call of the form >> "Aux.Init (r'Unchecked_Access)" also works, whether "r" is a >> library-level object or a local (limited-life) object, even if >> "Aux.Init" itself uses "'Access" and not "'Unchecked_Access". Apparently >> the accessibility level provided in the value of Unchecked_Access is >> such as to make the check succeed, as for a library-level object. >> > Yeah, RM section 13.10 says it treats it as if the object were declared > at library level for Unchecked_Access That explains it clearly, thanks for the reference. >> I also found that a call like "Aux.Init (new Aux.Rec)", which applies >> "Aux.Init" to a heap-allocated "Rec" object, fails the accessibility >> check, so this check is really strict. Of course, the heap object can be >> deallocated at any time, so it may have a short life-time, but that can >> be done (mainly) by Unchecked_Deallocation, so it involves "unchecked" >> programming. Hm. >> > Is that because the heap allocated object is allocated using an > anonymous access type instead of a named access type per chance? > I know anonymous access types have different accessibility level > rules. It might be setting the accessibility level to the point > of call maybe? I made some more experiments: a) anonymous access (Aux.Init (new Aux.Rec)): check fails b) local named type "access Aux.Rec": check fails c) library-level access type (access Aux.Rec declared in package Aux): works. Interesting... I haven't developed a good intuition for this yet. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-06 17:30 ` Niklas Holsti 2020-05-06 18:28 ` Jere @ 2020-05-07 9:07 ` J-P. Rosen 2020-05-07 10:15 ` Niklas Holsti 2020-05-07 10:31 ` Stefan.Lucks 1 sibling, 2 replies; 39+ messages in thread From: J-P. Rosen @ 2020-05-07 9:07 UTC (permalink / raw) Le 06/05/2020 à 19:30, Niklas Holsti a écrit : > Note that, although "Test" here is no doubt the program's main > subprogram and so its call (assuming it is not recursive) lasts almost > as long as the execution of the program, the compiler does not make use > of this fact to determine the life-times of types and objects in "Test". No, tasks declared in library packages could survive the main program. You may even have a "begin null; end" main program, and do all the work with library tasks. Moreover, there is no rule in Ada that makes the main subprogram "special". -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-07 9:07 ` J-P. Rosen @ 2020-05-07 10:15 ` Niklas Holsti 2020-05-07 13:00 ` Egil H H 2020-05-07 13:25 ` Simon Wright 2020-05-07 10:31 ` Stefan.Lucks 1 sibling, 2 replies; 39+ messages in thread From: Niklas Holsti @ 2020-05-07 10:15 UTC (permalink / raw) On 2020-05-07 12:07, J-P. Rosen wrote: > Le 06/05/2020 à 19:30, Niklas Holsti a écrit : >> Note that, although "Test" here is no doubt the program's main >> subprogram and so its call (assuming it is not recursive) lasts almost >> as long as the execution of the program, the compiler does not make use >> of this fact to determine the life-times of types and objects in "Test". > > No, tasks declared in library packages could survive the main program. And the environment task, yes. I know, which is why I said "almost as long as". The example program we were discussing had no library tasks. > You may even have a "begin null; end" main program, and do all the work > with library tasks. Yes, but not for this example program. But I should have been clearer, I admit. > Moreover, there is no rule in Ada that makes the main subprogram "special". Indeed, I was trying to make that point, but evidently not clearly enough. Sometimes this is a little annoying, where one wants to write a small program with some library-level stuff, but must then separate those declarations into a package. An option to have a "main package" instead of a "main subprogram" would sometimes be neat (and now somebody will tell me that Gnat already has that...) -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-07 10:15 ` Niklas Holsti @ 2020-05-07 13:00 ` Egil H H 2020-05-07 13:25 ` Simon Wright 1 sibling, 0 replies; 39+ messages in thread From: Egil H H @ 2020-05-07 13:00 UTC (permalink / raw) On Thursday, May 7, 2020 at 12:15:07 PM UTC+2, Niklas Holsti wrote: > On 2020-05-07 12:07, J-P. Rosen wrote: > > Le 06/05/2020 à 19:30, Niklas Holsti a écrit : > >> Note that, although "Test" here is no doubt the program's main > >> subprogram and so its call (assuming it is not recursive) lasts almost > >> as long as the execution of the program, the compiler does not make use > >> of this fact to determine the life-times of types and objects in "Test". > > > > No, tasks declared in library packages could survive the main program. > > And the environment task, yes. I know, which is why I said "almost as > long as". The example program we were discussing had no library tasks. > > > You may even have a "begin null; end" main program, and do all the work > > with library tasks. > > Yes, but not for this example program. But I should have been clearer, I > admit. > > > Moreover, there is no rule in Ada that makes the main subprogram "special". > > Indeed, I was trying to make that point, but evidently not clearly enough. > > Sometimes this is a little annoying, where one wants to write a small > program with some library-level stuff, but must then separate those > declarations into a package. An option to have a "main package" instead > of a "main subprogram" would sometimes be neat (and now somebody will > tell me that Gnat already has that...) > > -- > Niklas Holsti > Tidorum Ltd > niklas holsti tidorum fi > . @ . Since you asked so nicely... Sort of, -z No main subprogram. Bind and link the program even if the unit name given on the command line is a package name. The resulting executable will execute the elaboration routines of the package and its closure, then the finalization routines. I believe that's needed for the DSA? -- ~egilhh ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-07 10:15 ` Niklas Holsti 2020-05-07 13:00 ` Egil H H @ 2020-05-07 13:25 ` Simon Wright 1 sibling, 0 replies; 39+ messages in thread From: Simon Wright @ 2020-05-07 13:25 UTC (permalink / raw) Niklas Holsti <niklas.holsti@tidorum.invalid> writes: >> No, tasks declared in library packages could survive the main program. > > And the environment task, yes. I've seen people suggest aborting the environment task as a way of ending a program with library tasks .. I suppose the main program could exit without terminating the environment task .. looking at ARM 10.2, (25) says "When the environment task completes (normally or abnormally), it waits for the termination of all such tasks, and then finalizes any remaining objects of the partition." but (30) says "If the environment task completes abnormally, the implementation may abort any dependent tasks.". Cortex GNAT RTS treats exiting the main program as the same as exiting any other taks body, i.e. illegal under Ravenscar, but I suppose I could include 'delay until Ada.Real_Time.Time_Last;' - might result in fewer surprises and would be more ARM-compliant. ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-07 9:07 ` J-P. Rosen 2020-05-07 10:15 ` Niklas Holsti @ 2020-05-07 10:31 ` Stefan.Lucks 2020-05-07 11:58 ` J-P. Rosen 1 sibling, 1 reply; 39+ messages in thread From: Stefan.Lucks @ 2020-05-07 10:31 UTC (permalink / raw) [-- Attachment #1: Type: text/plain, Size: 1078 bytes --] On Thu, 7 May 2020, J-P. Rosen wrote: > No, tasks declared in library packages could survive the main program. Correct me, if I am wrong, but my understanding has always been that the main program (or "environment task") can only terminate after all the tasks started within the main program have terminated (or, perhaps, have been aborted, or did run into an unhandled exception). > You may even have a "begin null; end" main program, and do all the work > with library tasks. Once again, my understanding is that a main program with the "begin null; end Program_Name" does not terminate, as long as one of its tasks is still running. In fact, I am frequently using the "begin null; end Program_Name;" pattern myself, and "Program_Name" does not terminate, as long as any of its tasks is still alife and kicking. -------- I love the taste of Cryptanalysis in the morning! -------- www.uni-weimar.de/de/medien/professuren/mediensicherheit/people/stefan-lucks ----Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany---- ^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: How can one record component be local and another not? 2020-05-07 10:31 ` Stefan.Lucks @ 2020-05-07 11:58 ` J-P. Rosen 0 siblings, 0 replies; 39+ messages in thread From: J-P. Rosen @ 2020-05-07 11:58 UTC (permalink / raw) Le 07/05/2020 à 12:31, Stefan.Lucks@uni-weimar.de a écrit : > On Thu, 7 May 2020, J-P. Rosen wrote: > >> No, tasks declared in library packages could survive the main program. > > Correct me, if I am wrong, but my understanding has always been that the > main program (or "environment task") can only terminate after all the > tasks started within the main program have terminated (or, perhaps, have > been aborted, or did run into an unhandled exception). True AND False. The master of a library task is the environment task, not the procedure declared as the main program. So you can return from the main procedure, and then wait for the termination of library tasks. The confusion is that the procedure declared as "main" is not the real main program. The real main program is generated by the compiler, it elaborates the library packages, and then calls the main procedure. In gnat, you can even see the source (file b__*.adb) >> You may even have a "begin null; end" main program, and do all the work >> with library tasks. > > Once again, my understanding is that a main program with the "begin > null; end Program_Name" does not terminate, as long as one of its tasks > is still running. As explained above, Program_Name terminates, but not the "real" main program that called it. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 39+ messages in thread
end of thread, other threads:[~2020-05-10 15:10 UTC | newest] Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-05-05 11:04 How can one record component be local and another not? hreba 2020-05-05 11:33 ` AdaMagica 2020-05-05 11:38 ` AdaMagica 2020-05-05 12:59 ` hreba 2020-05-05 13:19 ` J-P. Rosen 2020-05-05 13:37 ` Jere 2020-05-05 14:28 ` hreba 2020-05-05 15:18 ` AdaMagica 2020-05-05 14:32 ` hreba 2020-05-05 11:43 ` AdaMagica 2020-05-05 12:55 ` hreba 2020-05-05 11:46 ` Simon Wright 2020-05-05 13:07 ` hreba 2020-05-05 17:00 ` Dmitry A. Kazakov 2020-05-05 11:48 ` Niklas Holsti 2020-05-05 13:44 ` hreba 2020-05-05 15:45 ` Jeffrey R. Carter 2020-05-05 17:17 ` hreba 2020-05-05 19:08 ` Niklas Holsti 2020-05-06 19:31 ` hreba 2020-05-09 19:43 ` Niklas Holsti 2020-05-10 15:10 ` hreba 2020-05-05 19:19 ` Jere 2020-05-06 6:42 ` Mark Lorenzen 2020-05-06 8:26 ` Simon Wright 2020-05-06 8:33 ` Mark Lorenzen 2020-05-05 17:32 ` hreba 2020-05-05 19:04 ` Niklas Holsti 2020-05-05 20:11 ` Niklas Holsti 2020-05-06 13:13 ` hreba 2020-05-06 17:30 ` Niklas Holsti 2020-05-06 18:28 ` Jere 2020-05-06 19:09 ` Niklas Holsti 2020-05-07 9:07 ` J-P. Rosen 2020-05-07 10:15 ` Niklas Holsti 2020-05-07 13:00 ` Egil H H 2020-05-07 13:25 ` Simon Wright 2020-05-07 10:31 ` Stefan.Lucks 2020-05-07 11:58 ` J-P. Rosen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox