Discussion:
Error: "non-local pointer cannot point to a local object"
(too old to reply)
NiGHTS
2018-09-11 22:20:57 UTC
Permalink
As the subject line indicates, I am having a compile error which I am having difficulty solving.

I have two distinct records, in this example called "Master_Record" and "Working_Record". One contains an Integer, the other a "pointer" to that Integer. In this context, Working_Record depends on Master_Record. There can be many Working_Record instances for a single Master_Record. The Copy function is intended to enforce this rule by acting as an object factory, requiring an instance of Master_Record to create Working_Record. I know this isn't perfect, so any suggestions on a better strategy would be appreciated.

Ultimately the purpose of this is for Working_Record to be a copy-friendly record, where Master_Record is not intended to be used directly, except as a place to anchor the variable scope. The resulting code will be written as a library object containing two records just like I have here, as well as a Copy function. The user of this library object is expected to create an instance of Master_Record, then copy it to Working_Record.

----------------------------------------
type Master_Record is record

Root : aliased Integer;
-- Here is where other general variables are kept

end record;

type Working_Record is record

Root_Pointer : access Integer;
-- Here is where specific instance variables are kept

end record;

function Copy (

Source : in out Master_Record

) return Working_Record is
begin

return (Root_Pointer => Source.Root'Access); -- << Error here >>

end Copy;

MR : Master_Record;
WR : Working_Record := Copy (MR);
----------------------------------------

Any ideas on how to achieve this goal? I'm sure its something simple. Thanks in advance!
Brad Moore
2018-09-12 01:49:42 UTC
Permalink
Post by NiGHTS
As the subject line indicates, I am having a compile error which I am having difficulty solving.
I have two distinct records, in this example called "Master_Record" and "Working_Record". One contains an Integer, the other a "pointer" to that Integer. In this context, Working_Record depends on Master_Record. There can be many Working_Record instances for a single Master_Record. The Copy function is intended to enforce this rule by acting as an object factory, requiring an instance of Master_Record to create Working_Record. I know this isn't perfect, so any suggestions on a better strategy would be appreciated.
Ultimately the purpose of this is for Working_Record to be a copy-friendly record, where Master_Record is not intended to be used directly, except as a place to anchor the variable scope. The resulting code will be written as a library object containing two records just like I have here, as well as a Copy function. The user of this library object is expected to create an instance of Master_Record, then copy it to Working_Record.
----------------------------------------
type Master_Record is record
Root : aliased Integer;
-- Here is where other general variables are kept
end record;
type Working_Record is record
Root_Pointer : access Integer;
-- Here is where specific instance variables are kept
end record;
function Copy (
Source : in out Master_Record
) return Working_Record is
begin
return (Root_Pointer => Source.Root'Access); -- << Error here >>
end Copy;
MR : Master_Record;
WR : Working_Record := Copy (MR);
----------------------------------------
Any ideas on how to achieve this goal? I'm sure its something simple. Thanks in advance!
One solution would be to use access discriminants.


eg.
package P is

type Master_Record is record

Root : aliased Integer;
-- Here is where other general variables are kept

end record;

type Working_Record (Root : not null access Integer) is record
null;
-- Here is where specific instance variables are kept
end record;

end P;

with P; use P;

procedure Main is
MR : aliased Master_Record;
WR1 : Working_Record (Root => MR.Root'Access);
WR2 : Working_Record (Root => MR.Root'Access);
begin
WR1.Root.all := 35;
WR2.Root.all := 36;
end Main;

regards,

Brad
NiGHTS
2018-09-12 14:41:38 UTC
Permalink
Post by Brad Moore
Post by NiGHTS
As the subject line indicates, I am having a compile error which I am having difficulty solving.
I have two distinct records, in this example called "Master_Record" and "Working_Record". One contains an Integer, the other a "pointer" to that Integer. In this context, Working_Record depends on Master_Record. There can be many Working_Record instances for a single Master_Record. The Copy function is intended to enforce this rule by acting as an object factory, requiring an instance of Master_Record to create Working_Record. I know this isn't perfect, so any suggestions on a better strategy would be appreciated.
Ultimately the purpose of this is for Working_Record to be a copy-friendly record, where Master_Record is not intended to be used directly, except as a place to anchor the variable scope. The resulting code will be written as a library object containing two records just like I have here, as well as a Copy function. The user of this library object is expected to create an instance of Master_Record, then copy it to Working_Record.
----------------------------------------
type Master_Record is record
Root : aliased Integer;
-- Here is where other general variables are kept
end record;
type Working_Record is record
Root_Pointer : access Integer;
-- Here is where specific instance variables are kept
end record;
function Copy (
Source : in out Master_Record
) return Working_Record is
begin
return (Root_Pointer => Source.Root'Access); -- << Error here >>
end Copy;
MR : Master_Record;
WR : Working_Record := Copy (MR);
----------------------------------------
Any ideas on how to achieve this goal? I'm sure its something simple. Thanks in advance!
One solution would be to use access discriminants.
eg.
package P is
type Master_Record is record
Root : aliased Integer;
-- Here is where other general variables are kept
end record;
type Working_Record (Root : not null access Integer) is record
null;
-- Here is where specific instance variables are kept
end record;
end P;
with P; use P;
procedure Main is
MR : aliased Master_Record;
WR1 : Working_Record (Root => MR.Root'Access);
WR2 : Working_Record (Root => MR.Root'Access);
begin
WR1.Root.all := 35;
WR2.Root.all := 36;
end Main;
regards,
Brad
I like this strategy as it enforces my dependency requirement. Thank you.
r***@fastmail.jp
2018-09-12 06:05:06 UTC
Permalink
For Access attribute compiler checks if the object itself will live as long as an access to it for preventing "dangling reference". For situations when you take control over pointers in your hands, you must use the Unchecked_Access attribute. See ARM95 13.10 for details.

P.S.: Sorry for google translate.
NiGHTS
2018-09-12 14:42:13 UTC
Permalink
Post by r***@fastmail.jp
For Access attribute compiler checks if the object itself will live as long as an access to it for preventing "dangling reference". For situations when you take control over pointers in your hands, you must use the Unchecked_Access attribute. See ARM95 13.10 for details.
P.S.: Sorry for google translate.
Yes, I had forgotten about that attribute. That could also work for me. Thank you.
Dmitry A. Kazakov
2018-09-12 07:26:44 UTC
Permalink
Post by NiGHTS
As the subject line indicates, I am having a compile error which I am having difficulty solving.
I have two distinct records, in this example called "Master_Record" and "Working_Record". One contains an Integer, the other a "pointer" to that Integer. In this context, Working_Record depends on Master_Record. There can be many Working_Record instances for a single Master_Record. The Copy function is intended to enforce this rule by acting as an object factory, requiring an instance of Master_Record to create Working_Record. I know this isn't perfect, so any suggestions on a better strategy would be appreciated.
Ultimately the purpose of this is for Working_Record to be a copy-friendly record, where Master_Record is not intended to be used directly, except as a place to anchor the variable scope. The resulting code will be written as a library object containing two records just like I have here, as well as a Copy function. The user of this library object is expected to create an instance of Master_Record, then copy it to Working_Record.
----------------------------------------
type Master_Record is record
Root : aliased Integer;
-- Here is where other general variables are kept
end record;
type Working_Record is record
Root_Pointer : access Integer;
-- Here is where specific instance variables are kept
end record;
function Copy (
Source : in out Master_Record
) return Working_Record is
begin
return (Root_Pointer => Source.Root'Access); -- << Error here >>
What about killing accessibility info:

return (Root_Pointer => Source.Root.all'Unchecked_Access);
Post by NiGHTS
end Copy;
MR : Master_Record;
WR : Working_Record := Copy (MR);
----------------------------------------
Any ideas on how to achieve this goal? I'm sure its something simple. Thanks in advance!
What goal? It looks like a bad design. Copying pointers to integers is
asking for trouble.

BTW, if you used Ada.Finalization.Controlled, as you likely should, and
derived one record from another then default copying before Adjust would
copy pointer too. What would happen with access info, I have no idea,
probably copied as-is. (Yet another reason not to use anonymous access
types inside records unless for Rosen's trick or access-to-constant)
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
NiGHTS
2018-09-12 14:47:53 UTC
Permalink
Post by Dmitry A. Kazakov
What goal? It looks like a bad design. Copying pointers to integers is
asking for trouble.
The integer was chosen to simplify the example. In the actual application it is a tree container, where there is a single thread that is expected to manipulate various contexts of the same tree, thus multiple working records for the same tree.
Post by Dmitry A. Kazakov
BTW, if you used Ada.Finalization.Controlled, as you likely should, and
derived one record from another then default copying before Adjust would
copy pointer too. What would happen with access info, I have no idea,
probably copied as-is. (Yet another reason not to use anonymous access
types inside records unless for Rosen's trick or access-to-constant)
While my example does not show Ada.Finalization.Controlled in use, my application's record indeed is derived from this object. Still, I am not sure how overriding Adjust would be applied to my example. Would you show me a quick and dirty example of how this would be done?
Post by Dmitry A. Kazakov
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
Dmitry A. Kazakov
2018-09-12 15:22:55 UTC
Permalink
Post by NiGHTS
Post by Dmitry A. Kazakov
What goal? It looks like a bad design. Copying pointers to integers is
asking for trouble.
The integer was chosen to simplify the example. In the actual application it is a tree container, where there is a single thread that is expected to manipulate various contexts of the same tree, thus multiple working records for the same tree.
Why do you need copying? By-reference semantics does not match copying
(= by-value).
Post by NiGHTS
Post by Dmitry A. Kazakov
BTW, if you used Ada.Finalization.Controlled, as you likely should, and
derived one record from another then default copying before Adjust would
copy pointer too. What would happen with access info, I have no idea,
probably copied as-is. (Yet another reason not to use anonymous access
types inside records unless for Rosen's trick or access-to-constant)
While my example does not show Ada.Finalization.Controlled in use, my application's record indeed is derived from this object. Still, I am not sure how overriding Adjust would be applied to my example. Would you show me a quick and dirty example of how this would be done?
Before Adjust is called an exact copy of the controlled source object is
made. This naturally applies to its access components as well. Thus you
probably need not to override Adjust at all.

[ As I said I don't know what happens with the accessibility checks.
Where assignment of plain records fail, would assignment of controlled
ones fail as well, if Adjust is null? ]
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
Continue reading on narkive:
Loading...