Re: Access types as parameters



Adam Beneschan <adam@xxxxxxxxxx> writes:

For a procedure, there's less reason to do so. I don't know anything
about GTK, so I don't know why this wouldn't have worked, if all
Initialize is doing is to set up some fields in Button:

procedure Initialize
(Button : in out Gtk_Button_Record'Class;
Label : UTF8_String);

If, on the other hand, Initialize needs Button as an access so that it
can store it in a data structure, then it probably would have been
best to make it a named access type, to ensure that dangling
references aren't stored in that data structure.

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.

So one reason to use 'access' instead of 'in out' is simply to avoid
the user having to type '.all' everywhere.

A reason to use 'access Record_Type' instead of 'in Access_Type' is to
avoid explicit type conversions. 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.

In addition, leaving out the 'class makes Show a primitive operation,
which has many advantages.

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.

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.

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.

--
-- Stephe
.


Loading