comp.lang.ada
 help / color / mirror / Atom feed
From: "Randy Brukardt" <randy@rrsoftware.com>
Subject: Re: Private primitive operations available to entire package hierarchy. Can it be done?
Date: Wed, 3 Aug 2005 15:03:35 -0500
Date: 2005-08-03T15:03:35-05:00	[thread overview]
Message-ID: <no2dnY55mo72v2zfRVn-pw@megapath.net> (raw)
In-Reply-To: 1122998146.914353.174110@g44g2000cwa.googlegroups.com

"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1122998146.914353.174110@g44g2000cwa.googlegroups.com...
> <quote>
> If you use access types in the parameters, then the users of your
interface
> will have to either:
>
> * use an allocator (new) to create objects. In that case, they'll have to
> use Unchecked_Deallocation to get rid of them. That puts a lot of effort
on
> the user that they may not need the power of (often stack allocation is
just
> fine for objects); or
> </quote>
>
> Well this can be hidden away inside a "Create" subprogram as per
> GtkAda, and as you have to create this kind of "constructor" for Ada
> types anyway, I don't see the problem?

The problem is storage leakage. You can't (in Ada) put a finalize routine on
an access type, so there is no way to reclaim the memory when the object
disappears. You'd have to use an explicit Destroy routine, and that puts the
burden on the users, and it doesn't work very well, either, because it isn't
safe against exceptions propagating, aborts, and the like. Our earliest
versions of Claw required such routines, and we found that they were very
difficult to use and debug, because any mistake tended to leave dead objects
around -- which then raised more exceptions and eventually caused the system
to deadlock.

> e.g. I currently have a New_Frame which will do any construction
> necessary for this type, basically it'll call the C constructor
> function which calls "new wxFrame(...)" and returns the pointer back to
> Ada which stores it inside wxObject in the wx.Base.Object.Object_Type
> as a System.Address.
>
> If I then derive a new frame type (My_Frame), I should also create a
> New_My_Frame primitive which calls New_Frame first on the object, then
> do any other construction necessary for My_Frame.

Right. I believe that is best done on objects, not on accesses. (Claw uses
procedure constructors because copying of objects inherent in Ada 95
functions is problematical.)

> <quote>
> * declare objects with the ugly "aliased" syntax, and worse, have to use
the
> 'Unchecked_Access attribute in most calls. Which means a lot of extra
typing
> (and more importantly, reading) that has nothing to do with their program.
> </quote>
>
> Well, I have Limited_Controlled as my root tagged type and I still have
> to use aliased, so that blatantly doesn't work, unless I'm missing
> something.

You must be missing something, because its not necessary *in the user code*.
I've tried to explain that several times already, and I don't think I can
explain it any better than I already have. And I don't want to try to design
your interface for you...

> <quote>
> Moreover, if you use access types in this way, you're preventing the users
> from using an Ada.Containers container to do their memory management.
They'd
> have to put access values into the container, and do their own memory
> management on those values -- pretty much defeating the purpose of a
container.
> </quote>
>
> Because the containers have their own access types inside the packages,
> right?

No, because you can't get an access to the element stored in a container.
(Well, that's not *quite* true, you could use 'Address and
Address_to_Access_Conversions, but that's certainly not guaranteed to work.)

> So, you're saying I should do the following in each of my packages:
>
> type Some_Type is new Some_Base_Type with private;
> type Some_Access is access all Some_Type;
> type Some_View is access constant Some_Type;

I would not declare access types in the user part of the specification. If
the user needs them, they can declare them easily enough, and if you declare
them, they can't use a custom storage pool.

If *you* need them for the implementation, declare them in the private part.

My rule is to never force the user to use access types - give them the
maximum flexibility by allowing them to chose the appropriate way to declare
the objects of your binding.

But if you really need them, they ought to be classwide (I usually use "any"
in the name to reflect this):

type Any_Some_Access is access all Some_Type'Class;
type Any_Some_View is access constant Some_Type'Class;

For Ada O-O programming, anything that is not primitive or an object
declaration that is specific is suspect. (Sometimes you have to make
exceptions for constructors.)

> <quote>
> If you need to use it longer, then you have to make sure that you have
> a way to destroy the access value if the object gets finalized while
> you are still holding onto the access value. Claw uses controlled types
> for this; when an object is finalized, the object
> is removed from all lists and other objects that it is in (obviously,
> that means making sure that the object keeps track of every place that
> it is linked).
> </quote>
>
> So, you get hold of the access of every type constructed and keep a
> reference counted list of them?

Not exactly. In Claw, we have a list of all top-level windows of the
application anyway. Child windows are linked to their parents, and
vice-versa. So we can traverse all the windows by following that top-level
list. When a window *object* is being destroyed, we traverse all of the
windows and remove any accesses to the object, whereever they are. We don't
reference count, because we're not tracking the accesses, we're tracking the
objects. (Remember, you can only manage a collection of objects in Ada, not
access values, as you can't have Adjust/Finalize on an access value.)

Other types of objects work similarly; typically, they contain a list of all
windows that they've been attached to. When one is finalized, it is removed
from any windows that it is attached to (which involves not only removing
the links, but also issuing any Windows operations needed to remove the
objects).

We do use something like reference counting to allow Window objects to be
assigned. But that capability was a mistake - we wouldn't do it if starting
over - so I won't try to describe it.

So the main capability (and cost) is that each object has to contain a list
of everywhere inside of the binding where it is linked, so it can be removed
if the object is finalized (or explicitly destroyed, for that matter).

> With the way you have to start the wxWidgets library up, it's more than
> fiddly. I've not been able to get reference counting working reliably.
> Also getting the app to finalize last is particularly difficult but I
> haven't played with it for a while.

Termination was a real pain in Claw; for the longest time we used a
subprogram that you had to call before exiting. Otherwise the program would
deadlock -- and it usually did in practice, because an exception got raised
while finalizing something else, or someone aborted a task, or other things.
We eventually got it worked out.

                             Randy.






  parent reply	other threads:[~2005-08-03 20:03 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-07-07 16:06 Private primitive operations available to entire package hierarchy. Can it be done? Lucretia
2005-07-07 16:17 ` OT: Joke Adrien Plisson
2005-07-07 16:24   ` Matthew Heaney
2005-07-07 19:10 ` Private primitive operations available to entire package hierarchy. Can it be done? Randy Brukardt
2005-07-13 15:40   ` Lucretia
2005-07-19 23:19     ` Randy Brukardt
2005-07-20 18:14       ` Lucretia
2005-07-21  3:10         ` Randy Brukardt
2005-07-25 18:14           ` Lucretia
2005-07-25 23:58             ` Randy Brukardt
2005-07-27 17:36               ` Lucretia
2005-07-27 21:28                 ` Randy Brukardt
2005-07-28 10:09                   ` Lucretia
2005-07-29  0:40                     ` Randy Brukardt
2005-08-02 15:55                       ` Lucretia
2005-08-03 18:26                         ` Lucretia
2005-08-03 20:04                           ` Randy Brukardt
2005-08-03 20:03                         ` Randy Brukardt [this message]
2005-08-08 18:04                           ` Lucretia
2005-08-08 20:47                             ` Randy Brukardt
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox