On Mar 31, 1:22 pm, Maciej Sobczak <see.my.homep...@[EMAIL PROTECTED]
> wrote:
> Consider a generic subprogram that makes sense for arguments of both
> class-wide type and a concrete type.
[snip]
> Now, the generic subprogram that operates on the given iterator,
> *without* using dynamic dispatch, can have the following form:
>
> generic
> type Element is private;
> type Iterator_Type (<>) is private;
> with function Get (I : Iterator_Type) return Element is <>;
> -- and so on for all other operations that are needed by this
> subprogram
> procedure Some_Procedure (I : in Iterator_Type);
>
> This works fine for direct instantiation with My_Concrete_Iterator:
>
> procedure SP is new Some_Procedure
> (T => Integer, Iterator_Type => My_Concrete_Iterator);
>
> The problem is that I failed to instantiate Some_Procedure for
> Iterator_Integer.Iterator'Class, which I could then reuse for
> My_Concrete_Iterator as well as for My_Other_Concrete_Iterator and so
> on:
>
> -- does not compile:
> procedure SP is new Some_Procedure
> (T => Integer, Iterator_Type => Iterator_Integer'Class); -- Bang!
>
> Bang, because relevant iterator operations cannot be found - the ones
> that are found have *wrong signatures*.
[snip]
At first, I thought it might be possible to do this, without
duplicating code, by writing a second generic package specifically for
class-wide types that would instantiate Some_Procedure. Something
like this:
generic
type Element is private;
type Iterator_Root is tagged private;
with function Get (I : in Iterator_Root) return Element is <>;
... other operations
package SP_For_Class is
procedure Some_Procedure_Class (I : in Iterator_Root'Class);
end SP_For_Class;
with Some_Procedure;
package body SP_For_Class is
function Dispatching_Get (I : in Iterator_Root'Class)
return Element is
begin
return Get (I);
end Dispatching_Get;
... similarly for other operations
procedure SP_Inst is new Some_Procedure
(Element, Iterator_Root'Class,
Dispatching_Get, ...other operations);
procedure Some_Procedure_Class (I : in Iterator_Root'Class)
renames SP_Inst;
end SP_For_Class;
Then for a concrete type, the programmer would instantiate
Some_Procedure; for a class-wide type, the programmer would
instantiate SP_For_Class, and then if Inst is the instance,
Inst.Some_Procedure_Class would be the equivalent procedure.
SP_For_Class would be sort of a wrapper, but it wouldn't need to
duplicate any of the logic from Some_Procedure.
The problem I ran into was the line "return Get(I)" fails because Get
is not a primitive operation of Iterator_Root and thus is not seen as
a dispatching operation.
What's missing here is a way to specify a generic formal subprogram
that must be a primitive operation of some tagged type (possibly a
generic formal tagged type), so that in the body of the generic the
formal subprogram will be treated as a dispatching operation; in an
instantiation, of course, the actual subprogram would have to meet the
criterion. It seems like this might be a useful feature in some
cases besides this one (although I can't think of one offhand), but
I can see how it would be difficult to work this into the syntax.
(Especially if the generic formal subprogram has two different
parameter or result tagged types; you'd need a way to tell it which
type the subprogram must be a primitive operation of.)
(P.S. It seems like we had a discussion on Ada-Comment some years ago
about the sort of issue Maciej mentions, at least with regard to the
"=" function. Some programmers were writing code, which GNAT accepted
due a bug, where generics declared
with function "=" (Left, Right : T) is <>;
and then the generic was instantiated with some class-wide type for
T. It
seemed like there was some sympathy for allowing this or providing for
a capability that would make this work, but not enough sympathy for
anyone to actually do anything about it. Bob Duff, does this ring a
bell at all?)
-- Adam


|