Not null feature with anonymous and named access types

33 views
Skip to first unread message

Anh Vo

unread,
Jun 12, 2006, 4:33:16 PM6/12/06
to
I have been exploring the not null feature with anonymous access type
and named access type. One thing have learned that an access variable
declared based on these types will raise a Constraint_Error when
deallocating this access variable as shown in the code below.

Access_Type:
declare
type Access_Integer is not null access all Integer;
procedure Free is new Unchecked_Deallocation (Integer,
Access_Integer);
My_Ref_1 : Access_Integer := new Integer' (111);
My_Ref_2 : not null access Integer := new Integer' (222);
begin
-- perform action on My_Ref_1 and My_Ref_2
Free (My_Ref_1); -- raising Constraint_Error under GNAT/gcc-4.2.0
Free (Access_Integer (My_Ref_2)); -- did too
end Access_Type;

Does this behavior reflect ARM 2005 requirements?
Thanks in advance for your comments.

AV

Björn Persson

unread,
Jun 12, 2006, 5:26:26 PM6/12/06
to
Anh Vo wrote:
> I have been exploring the not null feature with anonymous access type
> and named access type. One thing have learned that an access variable
> declared based on these types will raise a Constraint_Error when
> deallocating this access variable as shown in the code below.

Of course. Deallocation sets the access variable to null, and that
violates the not-null constraint.

--
Björn Persson PGP key A88682FD
omb jor ers @sv ge.
r o.b n.p son eri nu

Anh Vo

unread,
Jun 12, 2006, 7:13:34 PM6/12/06
to
Björn Persson wrote:
> Anh Vo wrote:
> > I have been exploring the not null feature with anonymous access type
> > and named access type. One thing have learned that an access variable
> > declared based on these types will raise a Constraint_Error when
> > deallocating this access variable as shown in the code below.
>
> Of course. Deallocation sets the access variable to null, and that
> violates the not-null constraint.
>
Thanks for your quick reply.

Based on this requirement, one should not use not null access in this
case due to memory leak as the result of memory deallocation
incapability.

AV

Dmitry A. Kazakov

unread,
Jun 13, 2006, 3:53:41 AM6/13/06
to

Often memory management and handling objects should be well separated. In
public interfaces, where pointers are needed, null access types can be very
useful. This by no means should prevent the implementation interfaces from
using plain pointers, arena allocators, garbage collectors, etc to manage
memory.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Anh Vo

unread,
Jun 13, 2006, 11:27:56 AM6/13/06
to

Agreed. However, memory leak occurs when the scope is complete in this
case. Therefore, not null access should be used with extreme care.
Otherwise, memory leak is almost certain.

AV

Alex R. Mosteo

unread,
Jun 14, 2006, 11:13:17 AM6/14/06
to
Anh Vo wrote:

I don't see anything has radically changed in this respect since Ada95. You
expose in the spec a not null type and in body use some nullable type for
unchecked deallocations, if necessary.

Anh Vo

unread,
Jun 14, 2006, 11:37:13 AM6/14/06
to
Alex R. Mosteo wrote:
> > Agreed. However, memory leak occurs when the scope is complete in this
> > case. Therefore, not null access should be used with extreme care.
> > Otherwise, memory leak is almost certain.
>
> I don't see anything has radically changed in this respect since Ada95. You
> expose in the spec a not null type and in body use some nullable type for
> unchecked deallocations, if necessary.

It is nice to have null excluded feature. However, memory can not be
reclaimed, in this case, because of Constraint_Error raised when
attempting to deallocate it. In Ada 95, null excluded not available,
Constraint_Error will not be raised when deallocate the access object
again in this case.

AV

Dmitry A. Kazakov

unread,
Jun 14, 2006, 1:00:16 PM6/14/06
to
On 14 Jun 2006 08:37:13 -0700, Anh Vo wrote:

> Alex R. Mosteo wrote:

>>> Agreed. However, memory leak occurs when the scope is complete in this
>>> case. Therefore, not null access should be used with extreme care.
>>> Otherwise, memory leak is almost certain.
>>
>> I don't see anything has radically changed in this respect since Ada95. You
>> expose in the spec a not null type and in body use some nullable type for
>> unchecked deallocations, if necessary.
>
> It is nice to have null excluded feature. However, memory can not be
> reclaimed,

via *this* pointer, which does not mean that it cannot be reclaimed at all.
Consider trivial stack allocated aliased variable.

> in this case, because of Constraint_Error raised when
> attempting to deallocate it. In Ada 95, null excluded not available,
> Constraint_Error will not be raised when deallocate the access object
> again in this case.

No, you just don't use not-null pointers where deallocation is possible /
necessary. That's the very idea of not-null pointers.

For example, consider an implementation of a container. Its public
operation Get_Element could return a not-null pointer to the element,
ensuring two things: 1. the client will never get a null (so no need to
check it) 2. the client will never be able to deallocate the element
through the pointer returned. Internally the implementation may allocate
and deallocate elements using other pointers. So another operation
Remove_Element_By_Index would do it.

[It is still unsafe, as any aliasing is, yet definitely better than
nullable pointers.]

Anh Vo

unread,
Jun 14, 2006, 11:48:28 PM6/14/06
to

Dmitry A. Kazakov wrote:
> On 14 Jun 2006 08:37:13 -0700, Anh Vo wrote:
>
> via *this* pointer, which does not mean that it cannot be reclaimed at all.
> Consider trivial stack allocated aliased variable.

I am afraid I do not understand "this* pointer means. What I was
talking about not null access object using heap memory, not aliased
variable at all. See my code snipet from my original post.

> No, you just don't use not-null pointers where deallocation is possible /
> necessary. That's the very idea of not-null pointers.

I weight memory leak more important than convenient way of using null
excluded pointer. I am fine with not null pointer pointing to an
aliased object. In this case, attemptingp to deallocate the pointer is
clearly a language violation.

> For example, consider an implementation of a container. Its public
> operation Get_Element could return a not-null pointer to the element,
> ensuring two things: 1. the client will never get a null (so no need to
> check it) 2. the client will never be able to deallocate the element
> through the pointer returned. Internally the implementation may allocate
> and deallocate elements using other pointers. So another operation
> Remove_Element_By_Index would do it.
>
> [It is still unsafe, as any aliasing is, yet definitely better than
> nullable pointers.]

There is no disagreement here.

AV

Dmitry A. Kazakov

unread,
Jun 15, 2006, 4:21:34 AM6/15/06
to
On 14 Jun 2006 20:48:28 -0700, Anh Vo wrote:

> Dmitry A. Kazakov wrote:
>> On 14 Jun 2006 08:37:13 -0700, Anh Vo wrote:
>>
>> via *this* pointer, which does not mean that it cannot be reclaimed at all.
>> Consider trivial stack allocated aliased variable.
>
> I am afraid I do not understand "this* pointer means.

You can have many pointers and other references to the same memory.

> What I was
> talking about not null access object using heap memory, not aliased
> variable at all. See my code snipet from my original post.

That's no problem. You just shouldn't mix referencing objects and memory
management. Not-null access types aren't intended for memory management. So
your example is flawed [*].

>> No, you just don't use not-null pointers where deallocation is possible /
>> necessary. That's the very idea of not-null pointers.
>
> I weight memory leak more important than convenient way of using null
> excluded pointer. I am fine with not null pointer pointing to an
> aliased object. In this case, attemptingp to deallocate the pointer is
> clearly a language violation.

But an aliased object, in a wider sense, that you have a more than one
reference to it, is the only case where non-null pointer should be used!

--------------
* There is a language design problem that not-null is a subtype constraint
rather than a type, so Ada.Unchecked_Deallocation cannot reject
instantiation with a not-null pointer, as it probably should. But that is a
problem of generics, not of null-pointers. But this is another story.

Alex R. Mosteo

unread,
Jun 15, 2006, 6:50:43 AM6/15/06
to
Anh Vo wrote:

> Dmitry A. Kazakov wrote:
>> On 14 Jun 2006 08:37:13 -0700, Anh Vo wrote:
>>
>> via *this* pointer, which does not mean that it cannot be reclaimed at
>> all. Consider trivial stack allocated aliased variable.
>
> I am afraid I do not understand "this* pointer means. What I was
> talking about not null access object using heap memory, not aliased
> variable at all. See my code snipet from my original post.

I think he's refering to something like (I certainly was):

declare
type AI is access all Integer;
type NNAI is not null access all Integer;

NNI : NNAI := new Integer'(6);
I : AI := AI (NNI);

begin
-- You can't free NNI but you can free I. Of course, then NNI is
-- dangling and can't be nullified, but it could get a new proper
-- value. This would be fine if done in some body for whatever
-- reasons.
end;

Randy Brukardt

unread,
Jun 16, 2006, 9:16:33 PM6/16/06
to
"Anh Vo" <anhvo...@gmail.com> wrote in message
news:1150144396.1...@f6g2000cwb.googlegroups.com...

> I have been exploring the not null feature with anonymous access type
> and named access type. One thing have learned that an access variable
> declared based on these types will raise a Constraint_Error when
> deallocating this access variable as shown in the code below.
>
> Access_Type:
> declare
> type Access_Integer is not null access all Integer;

It's virtually always wrong to declare a *type* with "not null". It's use
should primarily be restricted to subtypes and parameters.

> procedure Free is new Unchecked_Deallocation (Integer,
> Access_Integer);

This instantiation is illegal; the "not null" property must match between
the formal and actual types. See 12.5.4(4/2).

> My_Ref_1 : Access_Integer := new Integer' (111);
> My_Ref_2 : not null access Integer := new Integer' (222);
> begin
> -- perform action on My_Ref_1 and My_Ref_2
> Free (My_Ref_1); -- raising Constraint_Error under GNAT/gcc-4.2.0

You shouldn't have been able to run this program.

> Free (Access_Integer (My_Ref_2)); -- did too
> end Access_Type;
>
> Does this behavior reflect ARM 2005 requirements?

No, see above.

> Thanks in advance for your comments.

As I said above, never declare a null-excluding type; it's impossible to use
in any meaningful way. Use "not null" in subtypes, object declarations,
parameters, and the like. (Parameters are expected to be the primary use.)

I'd write your example like:

Access_Type:
declare
type Access_Integer is access all Integer;

procedure Free is new Unchecked_Deallocation (Integer, Access_Integer);

My_Ref_1 : Access_Integer := new Integer' (111);
My_Ref_2 : not null access Integer := new Integer' (222);
begin
-- perform action on My_Ref_1 and My_Ref_2

Free (My_Ref_1); -- OK.
--Free (Access_Integer (My_Ref_2)); -- Raises Constraint_Error.
My_Ref_1 := My_Ref_2;
Free (My_Ref_1); -- OK.
end Access_Type;

(But the important use of "not null" is in passing parameters.)

Randy.


Randy Brukardt

unread,
Jun 16, 2006, 9:21:10 PM6/16/06
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1xjx7454hmql7.1...@40tude.net...
...

> * There is a language design problem that not-null is a subtype constraint
> rather than a type, so Ada.Unchecked_Deallocation cannot reject
> instantiation with a not-null pointer, as it probably should. But that is
a
> problem of generics, not of null-pointers. But this is another story.

This is doubly wrong: "not null" is *not* a constraint (it's something else
altogether). And it is required to match on generic instantiations (the
version of GNAT used is wrong here, not the language). Note that Ada
requires matching constraints in some cases for generics (remember
"statically matching subtypes"?) -- this has nothing to do with types.

Randy.


Dmitry A. Kazakov

unread,
Jun 17, 2006, 4:24:45 AM6/17/06
to
On Fri, 16 Jun 2006 20:21:10 -0500, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
> news:1xjx7454hmql7.1...@40tude.net...
> ...
>> * There is a language design problem that not-null is a subtype constraint
>> rather than a type, so Ada.Unchecked_Deallocation cannot reject
>> instantiation with a not-null pointer, as it probably should. But that is
>> a problem of generics, not of null-pointers. But this is another story.
>
> This is doubly wrong: "not null" is *not* a constraint (it's something else
> altogether).

I didn't check it, so I thought that GNAT was correct. Thank you for
clarification.

However, if anonymous not-null access is a distinct type then it cannot be
implicitly converted to/from a (normal) anonymous access type, or?

> And it is required to match on generic instantiations (the
> version of GNAT used is wrong here, not the language).

That is a good news (to Ada, I mean (:-)))

> Note that Ada
> requires matching constraints in some cases for generics (remember
> "statically matching subtypes"?) -- this has nothing to do with types.

Hmm, that was about the target type constraints.

What I mean is that any access type is itself a type and could
[potentially] have constrained subtypes with the constraints of its own.
Not-null could be treated as such constraint. The storage pool could be
another (if we wished to eliminate anonymous access types), discriminants,
(if were allowed for access types) could be third.

Robert A Duff

unread,
Jun 17, 2006, 10:24:28 AM6/17/06
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> This is doubly wrong: "not null" is *not* a constraint ...

True, but does anybody besides a language lawyer need to care?

- Bob

Robert A Duff

unread,
Jun 17, 2006, 10:25:36 AM6/17/06
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> (But the important use of "not null" is in passing parameters.)

Yes. And function results.

Too bad we couldn't make "not null" be the default...

- Bob

Randy Brukardt

unread,
Jun 19, 2006, 7:17:05 PM6/19/06
to
"Robert A Duff" <bob...@shell01.TheWorld.com> wrote in message
news:wccejxn...@shell01.TheWorld.com...

> "Randy Brukardt" <ra...@rrsoftware.com> writes:
>
> > This is doubly wrong: "not null" is *not* a constraint ...
>
> True, but does anybody besides a language lawyer need to care?

Only if they remember that you can't doubly constrain a type; "not null" is
independent of that.

In any case, my primary point as that "not null" has to match on generic
instantiation.

Randy.


Reply all
Reply to author
Forward
0 new messages