From: Georg Bauhaus on
Maciej Sobczak wrote:
> Consider a generic subprogram that makes sense for arguments of both
> class-wide type and a concrete type.

> -- does not compile:
> procedure SP is new Some_Procedure
> (T => Integer, Iterator_Type => Iterator_Integer'Class); -- Bang!

FWIW, the following triggers everything from a running
program to an Ada 95 compiler internal assertion failure
(in case the iterator object is initialized in the main
procedure).


with Iterators, Some_Procedure;
procedure Test_Iterators is

package II is new Iterators(Integer);

procedure Context_Conc(it: II.Conc_Iter) is
procedure SP is new Some_Procedure
(Integer, II, Iterator_Type => II.Conc_Iter);
begin
SP(it);
end Context_Conc;

procedure Context_Disp(it: II.Iterator'Class) is
procedure SP is new Some_Procedure
(Integer, II, Iterator_Type => II.Iterator'Class);
begin
SP(it);
end Context_Disp;

c: II.Conc_Iter := II.Conc_Iter'(El => new Integer'(42));
begin
Context_Conc(c);
Context_Disp(c);
end Test_Iterators;

with Iterators;
generic
type T is private;
with package Integer_Iterators is new Iterators(T);
type Iterator_Type(<>) is new Integer_Iterators.Iterator with private;
procedure Some_Procedure (it: Iterator_Type);


generic
type T is private;
package Iterators is

type Iterator is abstract tagged null record;
function Get(It: Iterator) return T is abstract;

type T_Ptr is access constant T;
type Conc_Iter is new Iterator with
record
El: T_Ptr;
end record;

function Get(It: Conc_Iter) return T;

end Iterators;


procedure Some_Procedure (It: Iterator_Type) is
use type Integer_Iterators.Iterator;
Tmp: T;
begin
Tmp := Get(It);
end Some_Procedure;


package body Iterators is

function Get (It: Conc_Iter) return T is
begin
return It.El.all;
end Get;

end Iterators;
From: Dmitry A. Kazakov on
On Mon, 31 Mar 2008 13:22:10 -0700 (PDT), Maciej Sobczak wrote:

> Consider a generic subprogram that makes sense for arguments of both
> class-wide type and a concrete type.
>
> As a motivating example, there might be a hierarchy of iterator types
> rooted in some imaginary Iterator type that is itself defined in the
> generic package with the element type as its own formal parameter.
> There are concrete iterator types that are derived from this root
> Iterator type (exactly: from some instantiation thereof).
>
> There might be also a generic subprogram that operates on the iterator
> given as its parameter. This subprogram takes two formal generic
> parameters: the element type and the iterator type.
>
> Now - on one hand it makes sense to have a hierarchy of iterators and
> benefit from loose coupling and other features of OO, but on the other
> hand the iterators themselves can be lightweight objects that are used
> in tight loops and we can expect them to be fast, therefore we could
> benefit from *avoiding* the dynamic dispatch if there is enough
> context to do so.
>
> Both make sense, depending on the context at the call site.
>
> To achieve both benefits the user might instantiate the subprogram for
> the Iterator'Class type (to be exact: for the 'Class of some
> instantiation of Iterator) in the context where only a class-wide type
> is available, like within some other polymorphic subprogram; and for
> the concrete type, like My_Concrete_Iterator, in the context where the
> concrete type is available, with the hope that such an instantiation
> can be more easily inlined.

Just a small side note. If you care about performance you should do exactly
the opposite you tried to, i.e. you should instantiate it with a specific
type rather than with a class of. Doing so, you will force the compiler to
resolve primitive operations statically without dispatching overhead. When
you use class-wide, then its will dispatch somewhere, maybe later in the
bodies, maybe more than once.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Maciej Sobczak on
On 1 Kwi, 11:42, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
wrote:

> Just a small side note. If you care about performance you should do exactly
> the opposite you tried to, i.e. you should instantiate it with a specific
> type rather than with a class of.

This is exactly what I want to do.
If I have the knowledge of the specific iterator type, I want to
instantiate the subprogram with this specific type to facilitate
direct dispatch and code inlining.
When the only this I have is 'Class, then I want to instantiate the
subprogram with what I have and agree for indirect dispatch to
iterator operations within the subprogram body.

The question is whether it is possible in Ada without walking on the
edge of compiler conformance - and in particular without accidentally
benefiting from any compiler bug that will bite me later on when it's
fixed.
Yes, some bugs can be harmful after they are fixed. :-)

I will try the scheme proposed by Georg.

--
Maciej Sobczak * www.msobczak.com * www.inspirel.com
From: Dmitry A. Kazakov on
On Tue, 1 Apr 2008 02:51:19 -0700 (PDT), Maciej Sobczak wrote:

> On 1 Kwi, 11:42, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
> wrote:
>
>> Just a small side note. If you care about performance you should do exactly
>> the opposite you tried to, i.e. you should instantiate it with a specific
>> type rather than with a class of.
>
> This is exactly what I want to do.
> If I have the knowledge of the specific iterator type, I want to
> instantiate the subprogram with this specific type to facilitate
> direct dispatch and code inlining.
> When the only this I have is 'Class, then I want to instantiate the
> subprogram with what I have and agree for indirect dispatch to
> iterator operations within the subprogram body.
>
> The question is whether it is possible in Ada without walking on the
> edge of compiler conformance - and in particular without accidentally
> benefiting from any compiler bug that will bite me later on when it's
> fixed.
> Yes, some bugs can be harmful after they are fixed. :-)
>
> I will try the scheme proposed by Georg.

You could also do:

generic
type Element_Type is private; -- element type
package Iterators is
type Iterator_Type is interface;
function Get (I : Iterator_Type) return Element_Type is abstract;
-- and so on for other operations...
end Iterators;

with Iterators;
generic
with package Root_Iterators is new Iterators (<>);
type Base_Iterator_Type is
new Root_Iterators.Iterator_Type with private;
package Some_Procedure is
type Iterator_Type is new Base_Iterator_Type with null record;
procedure Foo (I : Iterator_Type); -- Primitive operation when tagged
end Some_Procedure;

You have to derive from Iterator_Type in order to declare another primitive
operation Foo. The element type comes with the instance of Iterators which
is the first formal parameter. The second formal parameter is a
non-abstract iterator type implementing the iterator interface. This schema
allows to cascade packages like Some_Procedure taking
Some_Procedure_1_Instance.Iterator_Type as the parameter for
Some_Procedure_2_Instance. Base_Iterator_Type could also be abstract, but
that would more difficult to trace instantiation problems.

Example:

with Ada.Finalization;
with Iterators, Some_Procedure;

procedure Test_Iterators is

------ Iterators to tagged elements -----------
type My_Element is new Ada.Finalization.Controlled with null record;
package My_Element_Iterators is new Iterators (My_Element);

package Firewall_1 is
type My_Iterator is
new My_Element_Iterators.Iterator_Type with null record;
function Get (I : My_Iterator) return My_Element;
end Firewall_1;

package My_Element_SP is
new Some_Procedure (My_Element_Iterators, Firewall_1.My_Iterator);

------- Iterators to integer elements -------
package Integer_Iterators is new Iterators (Integer);
package Firewall_2 is
type Integer_Iterator is
new Integer_Iterators.Iterator_Type with null record;
function Get (I : Integer_Iterator) return Integer;
end Firewall_2;

package Integer_SP is
new Some_Procedure (Integer_Iterators, Firewall_2.Integer_Iterator);

---------------------------------------------------------
package body Firewall_1 is
function Get (I : My_Iterator) return My_Element is
begin
return (Ada.Finalization.Controlled with null record);
end Get;
end Firewall_1;

package body Firewall_2 is
function Get (I : Integer_Iterator) return Integer is
begin
return 5;
end Get;
end Firewall_2;

begin
null;
end Test_Iterators;

The packages like Firewall are needed to freeze the element type.
Otherwise, the compiler would yell that

function Get (I : My_Iterator) return My_Element;

is doubly dispatching.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Randy Brukardt on
"Adam Beneschan" <adam(a)irvine.com> wrote in message
news:f0879dc0-7498-48f7-8d44-9856316d35ce(a)s19g2000prg.googlegroups.com...
....
> 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),

No, it's not missing. That's what abstract formal subprograms are for. See
specifically 12.6(8.4-8.5/2).

I'm not sure that helps in this case, but feel free to try. ;-).

Randy.

P.S. These were totally my idea, originally in the context of
Generic_Dispatching_Constructor (which I also dreamt up after a conversation
with Steve Baird and Tucker Taft on the factory problem). I off-handedly
suggested that the "magic" embodied in the original version of that generic
could be given language status, and I was stunned to find that everyone
thought that was a good idea. (Especially after the death of defaults for
generic formal parameters.) And voila! Abstract formal subprograms. I'm glad
that you like them. ;-)