Ada: Convert an access to constant to access to variable - pointers

What is the proper way to convert an access to constant to access to
variable? (Yes, I know that then I need to be careful not to modify this
"variable".)
Maybe Unchecked_Conversion?
But:
Is Unchecked_Conversion guaranteed by the standard to work well in this
case?
Is there a simpler way than Unchecked_Conversion?

Unchecked_Conversion is not guaranteed to work in that case, as Ada doesn't give you any guarantees about the memory layout of access types. Supposedly Ada intentionally allows the compiler to have unique memory layouts and meanings for each access type.
If you add a Convention => C aspect to your access types, you may get the common memory layout you want, as C considers all pointers to operate on the same address space.

Ok, what's going on is [likely] that there's a mismatch in parameter modes (and maybe type-definitions) somewhere.
Let's say there's a few types:
Type Window(<>) is tagged private;
Type Constant_Reference is not null constant access Window'Class;
Type Reference is not null access Window'Class;
Type Handle is access Window'Class;
Given Function Get_Handle ( Object : in out aliased Window'Class ) what can we say about Object'Access? Well, it's an access to Window'Class which is not constant -- so it is compatible with both Handle and Reference but not Constant_Reference.
On the other hand, if we had Function Get_Handle ( Object : aliased Window'Class ) then Object'Access would yield an anonymous access which is compatible with Constant_Reference due to the constant nature of the in-parameter.
So, check your parameters and your design, and see if that's what's causing your issues.

Related

Extending a Variable's Lifetime

To be fair, I cannot be entirely sure the title correctly describes the problem I am having, as it merely mirrors my current understanding of Ada as it is.
The Problem
I have a function:
function Make_Option (Title : String) return Access_Option is
O : aliased Option := (
Title_Len => Title'Length,
Title => Title);
begin -- Make_Option
return O'Unrestricted_Access;
end Make_Option;
This function is supposed to create a new menu option for the user, that may in turn be inserted into a menu (one that you might see in a terminal-based environment). You are all probably sighing, as quite evidently, the O variable would be deallocated at the end of this function (from my current understanding). As such, using the Unrestricted_Access here is just plain stupidity, but it mirrors the result of what it is I am trying to accomplish (as this code indeed does compile successfully).
The Access_Option is defined as following:
type Access_Option is access all Option;
The idea is that with an access to the option, which in turn is a discriminated record, is that we can store it within an array-like structure (as the object itself varies in size).
Beyond doubt, it would be nice if we could instead use the Access attribute for this, as the compiler would then make sure the lifetime is long enough of the O variable we are referencing, but as the lifetime as a matter of fact only exists til the end of the Make_Option function, we are presented with the following:
non-local pointer cannot point to local object
What I am then asking, is: how would I go about having a function to create Access_Options for me? Is such a thing even possible, or am I doing it all wrong? To clarify, what I am trying to do is create a neat way for filling an array with references to discriminated records, that I can then dereference and use.
Thought Process
I personally have not tried too many things, more than think about solutions that may be plausible for the problem. And, frankly, rather than going crazy of working makeshift solutions, it would be nice to have a solution that works for large-scale applications too, without messing up the code base to bad.
Would you perhaps have some sort of object queue to handle it? Does Ada even deallocate resources automatically in the first place? Gah. I am confused.
Would it, in fact, be possible to somehow place the O variable outside of the scope for deallocation to then manually deallocate it later?
Given the example you show above a much simpler approach is to simply make an array of Unbounded_String:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_Io;
procedure Str_Arrays is
type Arr is array(1..10) of Unbounded_String;
A : Arr;
begin
for S of A loop
S := To_Unbounded_String("Hello World!");
end loop;
for S of A loop
Put_Line(To_String(S));
end loop;
end Str_arrays;
Don't try that.
There are two alternative options:
1) Use Ada.Containers.Indefinite_Vectors instead of a plain array.
2) Give your record discriminant a default value. Then you can store it in a plain array.
You seem to be reinventing the bounded string. Alternatives include
Using an instantiation of Ada.Strings.Bounded.Generic_Bounded_Length
Using Ada.Strings.Unbounded
Using an indefinite container (Ada.Containers.Indefinite_*) to hold type String

Pointers sent to function

I have following code in main():
msgs, err := ch.Consume(
q.Name, // queue
//..
)
cache := ttlru.New(100, ttlru.WithTTL(5 * time.Minute)) //Cache type
//log.Println(reflect.TypeOf(msgs)) 'chan amqp.Delivery'
go func() {
//here I use `cache` and `msgs` as closures. And it works fine.
}
I decided to create separate function for instead of anonymous.
I declared it as func hitCache(cache *ttlru.Cache, msgs *chan amqp.Delivery) {
I get compile exception:
./go_server.go:61: cannot use cache (type ttlru.Cache) as type *ttlru.Cache in argument to hitCache:
*ttlru.Cache is pointer to interface, not interface
./go_server.go:61: cannot use msgs (type <-chan amqp.Delivery) as type *chan amqp.Delivery in argument to hitCache
Question: How should I pass msg and cache into the new function?
Well, if the receiving variable or a function parameter expects a value
of type *T — that is, "a pointer to T",
and you have a variable of type T, to get a pointer to it,
you have to get the address of that variable.
That's because "a pointer" is a value holding an address.
The address-taking operator in Go is &, so you need something like
hitCache(&cache, &msgs)
But note that some types have so-called "reference semantics".
That is, values of them keep references to some "hidden" data structure.
That means when you copy such values, you're copying references which all reference the same data structure.
In Go, the built-in types maps, slices and channels have reference semantics,
and hence you almost never need to pass around pointers to the values of such types (well, sometimes it can be useful but not now).
Interfaces can be thought of to have reference semantics, too (let's not for now digress into discussing this) because each value of any interface type contains two pointers.
So, in your case it's better to merely not declare the formal parameters of your function as pointers — declare them as "plain" types and be done with it.
All in all, you should definitely complete some basic resource on Go which explains these basic matters in more detail and more extensively.
You're using pointers in the function signature but not passing pointers - which is fine; as noted in the comments, there is no reason to use pointers for interface or channel values. Just change the function signature to:
hitCache(cache ttlru.Cache, msgs chan amqp.Delivery)
And it should work fine.
Pointers to interfaces are nearly never used. You may simplify things and use interfaces of pass by value.

Hacking pointers in fortran

Let's consider a complex structure in fortran
TYPE ComplexStrType
! Static as well as dynamic memory defined here.
END TYPE ComplexStrType
Defined a physical space (allocated on the stack memory I think) to use two variables of ComplexStrType:
TYPE(ComplexStrType) :: SomeComplexStr
TYPE(ComplexStrType) :: AnotherComplexStr
TYPE(ComplexStrType),POINTER :: PointerComplexStr
Then, I use SomeComplexStr to define a few stuff in the stack and to allocate a big space in the dynamic memory.
Now, suppose I want to point AnotherComplexStr to SomeComplexStr and forget space I have defined in the stack memory to AnotherComplexStr. To do that I use a simple but useful trick which converts some variable in a Target:
FUNCTION TargComplexStr(x)
IMPLICIT NONE
TYPE(ComplexStrType),INTENT(IN),TARGET :: x
TYPE(ComplexStrType),POINTER :: TargComplexStr
TargComplexStr => x
END FUNCTION TargComplexStr
And then I point PointerComplexStr to SomeComplexStr:
PointerComplexStr => TargComplexStr(SomeComplexStr)
Finally, I do AnotherComplexStr equal to PointerComplexStr:
AnotherComplexStr = PointerComplexStr
After that, it's supposed SomeComplexStr as well AnotherComplexStr are pointing to the same static and dynamic memory.
The thing is:
How can I free the space used by AnotherComplexStr used when I defined it at the beggining?
How do you recomend me nullify the pointers?
Is that practice safe, or do I have to expect some strange memory leaks on the execution?
If it's possible, how can I point the "pointed variable" to its original form? (Just in case I have to use it again as normal variable)
NOTE: It's useful because at the execution we can be decided if we want to use AnotherComplexStr as what it is, a complex and allocated structure, or we can switch it to be treated as a pointer and points it to another thing which already has the information we need. If there is another and easy way to do that, please tell me.
The "trick" that you are using in TargComplexStr does not work the way you think - that function offers nothing useful over simple pointer assignment.
You can associate a non-TARGET actual argument with a TARGET dummy argument, as you are doing, but when the procedure with the TARGET dummy argument completes, any pointers that were associated with the dummy argument become undefined (F2008 12.5.2.4 p11).
(Pointers can only be associated with targets, therefore something that isn't a target cannot have a pointer associated with it.)
This means that the result of the function is a pointer with undefined association status. It is not permitted to return a pointer with undefined association status from a function (F2008 12.6.2.2 p4).
The pointer assignment statement would then make PointerComplexStr become an undefined pointer. PointerComplexStr is then referenced in the assignment to AnotherComplexStr. It is not permitted to reference a pointer with undefined association status (F2008 16.5.2.8 p1).
Intrinsic assignment creates a copy of a value. This is the case even if the object on the right is a pointer - a copy of the value of the target of that pointer is created. Intrinsic assignment does not, at the level of the top data object being assigned[1], make one variable reference the storage of another. As far as I can tell, the intent of your entire example code could be replaced by:
AnotherComplexStr = ComplexStr
If you are trying to do something different to that, then you need to explain what it is that you are trying to do.
[1]: If the type of an object being assigned is a derived type that has a pointer components, then the definition of the value of the object includes the pointer association status of the pointer component, but not the value of the target of the component itself (F2008 4.5.8).

Ada Function Parameter as Access Type or Not

I am refactoring some code originally written using access types, but not yet tested. I found access types to be troublesome in Ada because they can only refer to dynamically allocated items, and referring to items defined at compile time is apparently not allowed. (This is Ada83.)
But now I come to a function like this one:
function Get_Next(stateInfo : State_Info_Access_Type) return integer;
I know that I can easily pass parameter "contents" of an access type rather than the access pointer itself, so I am considering writing this as
function Get_Next(stateInfoPtr : State_Info_Type) return integer;
where State_Info_Type is the type that State_Info_Access_Type refers to.
With this refactor, for all intents and purposes I think I'm still really passing what amounts to an implicit pointer back to the contents (using the .all) syntax).
I want to refactor and test starting with the lowest level functions, working my way up the call chains. My goal is to push the access types out of the code as I go.
Am I understanding this correctly or am I missing something?
I think original author(s), and possibly OP are missing a point, that is, how Ada parameter modes work.
To quote #T.E.D
Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine.
Ada does this automatically, and leaves the parameter modes as a way of describing the flow of information (Its NOT the C style reference / value conundrum). See the useful wikibook.
What worries me is that the code you have inherited looks like the author has used the explicit access parameter type as a way of getting functions to have side effects (usually considered a bad thing in Ada - World).
My recommendation is to change your functions to:
function Get_Next(State_Info : in State_Info_Type) return Integer;
and see if the compiler tells you if you are trying to modify State_Info. If so, you may need to change your functions to procedures like this:
procedure Get_Next(State_Info : in out State_Info_Type;
Result : out Integer);
This explicitly shows the flow of information without needing to know the register size or the size of State_Info_Type.
As an aside Ada 2012 Will allow you to have functions that have in out parameters.
To quote #T.E.D,
Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine.
Since this code hasn’t yet been tested, I think you are completely right to rework what looks like code written with a C mindset. But, you oughtn’t to mention pointers at all; you suggested
function Get_Next(stateInfoPtr : State_Info_Type) return integer;
but this would be better as
function Get_Next(stateInfo : State_Info_Type) return integer;
or even (IMO) as
function Get_Next(State_Info : State_Info_Type) return Integer;
to use more standard Ada styling! My editor (Emacs, but GPS can do this too) will change state_info into State_Info on the fly.
As an afterthought, you might be able to get rid of State_Info_Type_Pointer altogether. You mention .all, so I guess you’ve got
SITP : State_Info_Type_Pointer := new State_Info_Type;
... set up components
Next := Get_Next (SITP.all);
but what about
SIT : State_Info_Type;
... set up components
Next := Get_Next (SIT);
I wouldn't recommend this, but you can get pointers to variables in Ada 83 by using 'Address.
You can then use overlays (again this is all Ada83 stuff) to achieve access...
function something(int_address : Address) return integer
is
x : integer;
for x'address use int_address;
begin
-- play with x as you will.

Dealing with access type in Ada95

I have a specification of a function that acts like a constructor. The specification of the function is
function Create_Controller return Type_Controller;
Also, in the specification file, I have the Type_Controller type, which is an access. I copy the relevant fragment:
type Type_Controller_Implementation;
type Type_Controller is access Type_Controller_Implementation;
So, this is what I've attempted:
function Create_Controller return Type_Controller
is
My_Controller : aliased Type_Controller_Implementation;
begin
return My_Controller'Access;
end Create_Controller;
I tried to compile the program without the aliased keyword, but then, the compiler says:
prefix of "Access" attribute must be aliased
So, I put the aliased keyword and the compiler now suggests that I should change the specification:
result must be general access type
add "all" to type "Controlador_De_Impresion" defined at controller.ads
The problem is that I'm not allowed to change the specification. I've read the chapter about access types in the Ada Programming Wikibook, but I still don't understand why my code doesn't work. What am I doing wrong?
The implementation of the Create_Controller function body is incorrect. Were it to work as coded, you'd be returning a pointer to a variable local to that function body's scope...which would be immediately lost upon returning from the function, leaving you with an invalid pointer.
No, an instance of the type needs to be allocated and returned. If there's no explicit initialization that needs to occur you can simply do:
return new Type_Controller_Implementation;
If there is some initialization/construction that has to occur, then:
function Create_Controller return Type_Controller
is
My_Controller : Type_Controller := new Type_Controller_Implementation;
begin
-- Set fields of My_Controller
...
return My_Controller;
end Create_Controller;
When you declare an access type as access T, you're saying that "this is a pointer to a T and it must point to objects of type T allocated from a pool". (That is, allocated with a new keyword.) When you declare an access type as access all T, you're saying that it can point either to a T allocated from a pool, or to an aliased variable of type T.
If the type is declared as access T and you can't change it, then all access values of the type have to point to something allocated with new. You can't make it point to a variable (even to a "global" variable that isn't located on the stack).
The reasons for this are historical, I think. The first version of Ada (Ada 83) only had "pool-specific types." You couldn't make an access value point to some other variable at all, without trickery. This meant that a compiler could implement access values as indexes into some storage block, or as some other value, instead of making them the actual address of an object. This could save space (an access value could be smaller than an address) or allow more flexibility in how pool memory was managed. Allowing access values to point directly to objects takes away some of that flexibility. I think that's why they decided to keep the old meaning, for backward compatibility, and require an all keyword to indicate the new kind of access.

Resources