|
Prev: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
Next: Converting Type Characters to type string
From: Georg Bauhaus on 1 Apr 2008 03:22 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 1 Apr 2008 05:42 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 1 Apr 2008 05:51 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 1 Apr 2008 06:53 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 1 Apr 2008 16:10
"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. ;-) |