Hi,
I noticed that my adacraft book is rather uncritical of Ada95’s flaws, and promotes the usage of access parameters and discriminants, which frankly make my skin crawl.
I know access parameters were introduced due to the absence of in out function parameters at the time, which is solved now. But this leaves access discriminants and their special accessibility features.
je-views-spreadsheet.adb:121:42: error: non-local pointer cannot point to local object
The line in question is a call to “Insert” declared in “JE.Spreadsheets”.
This appeared when I systematically replaced all “access Spreadsheet_type’class” by
type spreadsheet_access is access all spreadsheet_type’class
I didn’t study this program extensively yet, but on top of your hat, what kind of refactoring must I do ? Can it be done with snuggling the access type locally with a generic instantiation, and without Unchecked_Access too ?
Without seeing the code in question it is hard to say (I am not familiar with je-views and it’s children offhand).
However, some thoughts:
If you are trying to take the access of a function parameter, you can declare the parameter as aliased and see if that makes it no longer local. You may additionally need to make the object being passed in aliased (or make the type tagged which is implicitly aliased).
Anonymous access discriminants can sometimes relax those rules at the cost of potentially having a runtime check (not always but sometimes…depends on what the compiler can reason with your code). For an example see the type Reference_Type declared in Ada.Containers.Vectors and other containers.
type Cell_Type (Sheet : Spreadsheet_Access) is abstract tagged limited private;
type Formula_Cell_Type (Sheet : Spreadsheet_Access;
Size : Natural) is new Cell_Type with private;
type String_Cell_Type (Sheet : Spreadsheet_Access;
Size : Natural) is new Cell_Type with private;
in package JE.Spreadsheets. While the functions requiring Unchecked_Access are
function Formula_Cell (Sheet : in out Spreadsheet_type'Class; Value : String) return Cell_Access is (new Formula_Cell_Type'(Limited_Controlled with Sheet => Sheet'Unchecked_Access, State => <>, Size => Value'Length, Text => Value, others => <>));
function String_Cell (Sheet : in out Spreadsheet_type'Class; Value : String) return Cell_Access is (new String_Cell_Type'( Limited_Controlled with Sheet'Unchecked_Access, Value'Length, Text => Value, others => <>));
located package body JE.Spreadsheets. All calls to string_cell or formula_cell are in library-level subprograms of JE.Views.Spreadsheet, while the main program that calls JE.Views.Spreadsheet is
with JE.Views.Spreadsheet;
procedure Spreadsheet is
Sheet : JE.Views.Spreadsheet.Sheet_Type;
begin
JE.Views.Spreadsheet.Display (Sheet);
loop
case JE.Views.Spreadsheet.Next_Command is
when JE.Views.Spreadsheet.Modify =>
JE.Views.Spreadsheet.Modify (Sheet);
when JE.Views.Spreadsheet.Display =>
JE.Views.Spreadsheet.Display (Sheet);
when JE.Views.Spreadsheet.Quit =>
exit;
end case;
end loop;
end Spreadsheet;
With these information, can I do without Unchecked_ while keeping the named access type ?
Anonymous access types were a mistake, resulting in the accessibility rules, which the ARG freely admits that no one understands. Yet the ARG seems infatuated with them and continually expands their use. You don’t have to use them, though.
Named access types only allow assignment of access from objects declared at the same level as the access type or above. In most cases this usually means library level (but not always). Your objects would most likely all have to be declared at library level to avoid unchecked access, which won’t work for function parameters.
This is one of the reasons that anonymous access types were added, because of all the issues that arose from the restriction (if I remember it involved access to subprograms as one of the main drivers?)
Depends on how your program is structured. Instead of holding an access to spreadsheets in the other types, you might be able to pass a spreadsheet parameter to all of their operations as a standalone in/out parameter. But then the burden of how to maintain that object in a general session may be a challenge. You might be able to store it at the same location as all of your objects of the other types. Or you may not. It all depends.
It’s simple:
Item of type Spreadsheet_type is declared under mai procedure spreadsheet.adb. Spreadsheet_type is defined under package JE.Spreadsheet (JE is empty), and contains the header of a linked list, encoding the occupied cells of the Spreadsheet.
type Cell_Record is record
Where : String (1..Cell_Name_Length);
Size : Cell_Size;
Cell : Cell_Pointers.Pointer_Type;
end record;
package Cell_Lists is new JE.Lists (Cell_Record);
type Spreadsheet_Type is abstract tagged limited record
Cells : Cell_Lists.List_Type;
Dirty : Boolean := False;
Eval : Evaluation_Number := Evaluation_Number'First;
end record;
Pointer_type is just a smart pointer.
I believe, in the followingi
function Formula_Cell (Sheet : in out Spreadsheet_type'Class;
Value : String) return Cell_Access is
(new Formula_Cell_Type'(Limited_Controlled with Sheet => Sheet'Access, State => <>, Size => Value'Length, Text => Value, others => <>));
the exception is raised because Sheet is considered a local objecjt while the object returned is global under ./spreadsheet. But cells only refer to the object containing them !
That’s not what you’re trying to do; it’s how you’re trying to do it. If you want an alternative way to do it, we need the former.
If you’re implementing a spreadsheet, it depends on what features the program will have. Modern spreadsheet programs are examples of runaway feature bloat, so I’d think you’re only going to implement the basic functionality.