comp.lang.ada
 help / color / mirror / Atom feed
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.





  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