From: "Randy Brukardt" <randy@rrsoftware.com>
Subject: Re: Access types as parameters
Date: Tue, 11 Aug 2009 18:41:21 -0500
Date: 2009-08-11T18:41:21-05:00 [thread overview]
Message-ID: <h5svl3$k4p$1@munin.nbi.dk> (raw)
In-Reply-To: u63dkb12m.fsf@stephe-leake.org
I know this is old, but it is so misguided that it needs a
reply...especially as it is from someone who usually knowledgable on this
forum. - RLB
"Stephen Leake" <stephen_leake@stephe-leake.org> wrote in message
news:u63dkb12m.fsf@stephe-leake.org...
...
> Most GTK subprograms do need access values; the same is true of any
> system that deals with derived types at multiple levels. The only
> library-level object that can hold any type in the hierarchy is a
> class-wide pointer. Lists of objects must hold pointers, etc.
All of the indefinite containers can hold class-wide objects. No (explicit)
pointers are needed.
One of the goals for the next revision of Ada is that the vast majority of
reasonable data structures can be reasonably written with the
Ada.Containers. In particular, the multiway tree container can be used to
model almost all forms for tree structure (and many graphs as well). That
should mean that the need for explicit access types will be greatly reduced
when class-wide programming.
Now, of course, GTK was designed for Ada 95, and those options weren't
available then, so misguided choices were more justifiable.
...
> A reason to use 'access Record_Type' instead of 'in Access_Type' is to
> avoid explicit type conversions.
This is a terrible reason: explicit conversions show when you are converting
accesses from one "domain of use" to another. (I'm thinking of each named
access type as a "domain-of-use". It only makes sense to have multiple named
access types for a particular designated type if there are different
"domains-of-use" [such as different storage pools or disjoint data
structures].) The type conversions make it clear when you are converting
from one "domain-of-use" to another, something that should be rare.
Anonymous access types hide that, and make it essentially impossible to
determine what the storage pool of an access is -- meaning that most values
that pass through anonymous access cannot be deallocated even if converted
to a named type (because there is no way to know if it is the *right* named
type). [Technically, they can be deallocated, but the program is erroneous
and may do anything.]
Finally, the implicit conversions are only allow to the anonymous type. To
get back to a named type, you have to go back to explicit conversions, so
you don't really save anything. In your example:
> Given:
>
> package Widget is
> type Gtk_Widget_Record is ...;
> type Gtk_Widget is access all Gtk_Widget_Record'class;
>
> procedure Show (Widget : in Gtk_Widget);
> end Widget;
>
> package Window is
> type Gtk_Window_Record is new Gtk_Widget_Record with ...;
> type Gtk_Window is access all Gtk_Window_Record'class;
> end Window;
>
> Window : Gtk_Window := ...;
>
> then this does not work:
>
> Widget.Show (Window);
>
> but this does:
>
> Widget.Show (Gtk_Widget (Window));
>
> This is just annoying!
>
> However, if Show is declared:
>
> procedure Show (Widget : access constant Gtk_Widget_Record'class);
>
> Then Show matches any access type in the class hierarchy;
>
> Widget.Show (Window);
>
> works.
Of course, Show in this case surely should be dispatching (even if the
interface itself doesn't use that property) so that extensions can extend
the operation, so the declaration should be:
procedure Show (Widget : in Gtk_Widget);
and the call should be
Show (Window.all);
Probably the real reason the designers of GTK made this an anonymous access
parameter is to get that dispatching property. It surely has little to do
with implicit conversions.
[The fact that you can dispatch on access types in Ada, but only with this
bizarre syntax is a highly misguided feature of the language IMHO. It was
added only because of the IN OUT parameter restrictions and the insistence
of some that that not being able to copy lousy C++ and Java designs directly
(rather than better Ada designs not using explicit access types) would harm
the language's use in some way.]
Anyway, the real issue that these implicit conversions don't work in many
cases that you would expect them to. For instance, inside of Show, if you
need to treat the parameter as a value of GTK_Widget:
Widget_List : GTK_Widget;
Widget_List := Widget; -- Illegal. Anon to Named conversions not
implicit!
Widget_List := GTK_Widget(Widget);
Indeed, the only reason (in Ada 95) why the anonymous access conversions are
implicit is the obvious problem that they don't have a name! Else I think
they would have in fact required a conversion.
It's possible that we'd going to fix this conversion problem in the next
version of Ada, but we will have to do more study to ensure that we don't
introduce a show-stopping incompatibility.
...
> I've been struggling with this issue in OpenToken, and settled on
> using 'access Record_Type' as the best compromise. Now I just need to add
> 'constant' in all the right places; that wasn't allowed in Ada 95,
> when OpenToken was first written.
That may have made sense in Ada 95, but now it is a terrible choice, as it
forces the user to do all memory management on the objects. If you force
passing access-to-objects, you cannot store the objects in a container and
allow the container to do the storage management. (It also requires adding a
huge amount of noise to stack-allocated objects -- the need to declare
everything "aliased" and 'access on every call -- and the use of
stack-allocated objects should always be a primary goal. Why OpenToken
cannot be designed to usually use stack-allocated objects escapes me...)
> In some cases, I have both class-wide and primitive operations:
>
> type Instance is abstract tagged private;
> subtype Class is Instance'Class;
> type Handle is access all Class;
>
> function Name (Token : in Instance) return String is abstract;
>
> -- Dispatching calls to Name
> function Name_Dispatch (Token : in Class) return String;
> function Name_Dispatch (Token : access constant Instance'Class) return
> String;
>
> That gives the best of all cases, at the expense of writting more
> code.
Let me get this straight. You declare an extra routine with a much longer
name and a complex (and expensive at runtime call-sequence) in order that
you can avoid writing ".all" periodically??
That is, if you have
type Any_Instance_Class is access all Instance'Class;
An_Instance : Any_Instance_Class;
(and appropriate visibility),
you would rather write:
Name_Dispatch (An_Instance);
rather than
Name (An_Instance.all);
???
Moreover, if you are using Ada 2005, you probably should write:
An_Instance.Name
And you don't even need the .all anymore! (Nor do you need "appropriate
visibility"!)
Talk about a lot of work for nothing. ;-)
>> And if you're going to store the access parameter in a global
>> structure, you'll get a runtime error if you try to store a dangling
>> reference, so it's best to use a global access type so that
>> accessibility level errors are caught at compile time.
>
> This is a problem; people keep stumbling across it. Still, you get
> used to it after a while, and stop trying to pass 'access of a local
> variable.
One would hope that designers of Ada interfaces would talk more care for the
users than to say "they get used to it after a while". That sort of ticking
time bomb (that easily can be missed in unit testing!) is very adverse to
the goals of safety espoused by many in this group (including me!). It has
the potential of making Ada into just another programming language.
Randy.
next prev parent reply other threads:[~2009-08-11 23:41 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-07-17 8:39 Access types as parameters Rick
2009-07-17 15:03 ` Adam Beneschan
2009-07-17 16:28 ` Hibou57 (Yannick Duchêne)
2009-07-17 23:25 ` rickduley
2009-07-18 1:03 ` Randy Brukardt
2009-07-19 22:57 ` rickduley
2009-07-20 0:10 ` John B. Matthews
2009-07-20 8:13 ` Dmitry A. Kazakov
2009-07-21 0:34 ` Randy Brukardt
2009-07-21 14:34 ` Adam Beneschan
2009-07-23 2:11 ` Stephen Leake
2009-08-11 23:41 ` Randy Brukardt [this message]
2009-08-12 2:22 ` Stephen Leake
2009-08-13 1:06 ` Randy Brukardt
2009-08-13 8:34 ` Niklas Holsti
2009-08-13 9:15 ` Dmitry A. Kazakov
2009-08-13 20:13 ` Niklas Holsti
2009-08-13 21:07 ` Dmitry A. Kazakov
2009-08-14 9:27 ` Niklas Holsti
2009-08-14 10:36 ` Dmitry A. Kazakov
2009-08-14 16:03 ` Niklas Holsti
2009-08-15 9:47 ` Dmitry A. Kazakov
2009-08-15 19:19 ` Niklas Holsti
2009-08-16 8:32 ` Dmitry A. Kazakov
2009-08-16 9:52 ` Niklas Holsti
2009-08-16 12:38 ` Dmitry A. Kazakov
2009-08-16 13:21 ` Niklas Holsti
2009-08-16 17:58 ` Dmitry A. Kazakov
2009-08-14 4:07 ` Randy Brukardt
2009-08-14 10:22 ` Niklas Holsti
2009-08-18 12:22 ` Stephen Leake
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox