* "out" or "access" @ 1998-10-21 0:00 =:-) Vincent 1998-10-21 0:00 ` Jeff Carter ` (2 more replies) 0 siblings, 3 replies; 24+ messages in thread From: =:-) Vincent @ 1998-10-21 0:00 UTC (permalink / raw) What's the best way ? package B is ... The_Procedure ( The_Parameter: out Integer ); -- or The_Procedure ( The_Parameter: access Integer ); ... end B; ... package body A is ... g_Toto: Integer; -- or aliased Integer ... procedure The_Other_Procedure is begin ... B.The_Procedure ( g_Toto ); -- or B.The_Procedure( g_Toto'Access ); ... end; ... end A; Thanks. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 "out" or "access" =:-) Vincent @ 1998-10-21 0:00 ` Jeff Carter 1998-10-21 0:00 ` Pat Rogers 1998-10-21 0:00 ` dennison 1998-10-21 0:00 ` Tucker Taft 2 siblings, 1 reply; 24+ messages in thread From: Jeff Carter @ 1998-10-21 0:00 UTC (permalink / raw) To: =:-) Vincent =:-) Vincent wrote: > > What's the best way ? > > package B is > ... > The_Procedure ( The_Parameter: out Integer ); > -- or The_Procedure ( The_Parameter: access Integer ); > ... > end B; > ... > package body A is > ... > g_Toto: Integer; -- or aliased Integer > ... > procedure The_Other_Procedure is > begin > ... > B.The_Procedure ( g_Toto ); > -- or B.The_Procedure( g_Toto'Access ); > ... > end; > ... > end A; There's no comparison. An access parameter is closer to an "in out" parameter than an "out" parameter. If an "out" parameter will do, do not use an access parameter if you can avoid it. If an "in out" parameter will do, still don't use an access parameter if you can avoid it. Access parameters exist primarily to interfaces with subprograms from other languages. -- Jeff Carter PGP:1024/440FBE21 E-mail: carter commercial-at innocon period com "Monsieur Arthur King, who has the brain of a duck, you know." Monty Python & the Holy Grail ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 ` Jeff Carter @ 1998-10-21 0:00 ` Pat Rogers 1998-10-21 0:00 ` Martin C. Carlisle 1998-10-22 0:00 ` Robert A Duff 0 siblings, 2 replies; 24+ messages in thread From: Pat Rogers @ 1998-10-21 0:00 UTC (permalink / raw) Jeff Carter wrote in message <362DF0D3.BC101364@spam.innocon.com>... >=:-) Vincent wrote: >> >> <snipped question of access parameters versus mode out parameters> > > <snipped good answer by Jeff> > Access parameters exist primarily to interfaces with subprograms from other >languages. A bit too strong there, IMHO. Access parameters are a very handy alternative when you want to derive from a type that has primitive subprograms with a formal parameter of a named access type. Why? Because access parameters are not named access types, so the derivation provides primitives with the desired signatures. For example: type T1 is tagged ... type T1_Pointer is access T1; procedure Foo( This : in T1; That : in T1_Pointer ); Then, in a derivation: type T2 is new T1 with ... This gives us: procedure Foo( This : in T2; That : in T1_Pointer ); Note that the type of the formal 'That' is still T1_Pointer, probably not what we wanted. On the other hand, had we defined things as: type T1 is tagged ... -- don't need this now... type T1_Pointer is access T1; procedure Foo( This : in T1; That : access T1 ); The derivation would provide procedure Foo( This : in T2; That : access T2 ); which is probably the desired result in this case. --- Pat Rogers Training, Development and Consulting in: http://www.classwide.com Deadline Schedulability Analysis progers@acm.org Software Fault Tolerance (281)648-3165 Real-Time/OO Languages ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 ` Pat Rogers @ 1998-10-21 0:00 ` Martin C. Carlisle 1998-10-22 0:00 ` Pat Rogers 1998-10-22 0:00 ` Robert A Duff 1 sibling, 1 reply; 24+ messages in thread From: Martin C. Carlisle @ 1998-10-21 0:00 UTC (permalink / raw) Be careful using access as below, as this creates two different dispatched objects in the call (which is illegal). See LRM 6.1(24) and 3.9.2 --Martin In article <70kvnv$gvo$1@supernews.com>, Pat Rogers <progers@NOclasswideSPAM.com> wrote: >Jeff Carter wrote in message <362DF0D3.BC101364@spam.innocon.com>... >A bit too strong there, IMHO. Access parameters are a very handy >alternative when you want to derive from a type that has primitive >subprograms with a formal parameter of a named access type. Why? >Because access parameters are not named access types, so the >derivation provides primitives with the desired signatures. For >example: > > type T1 is tagged ... > > type T1_Pointer is access T1; > > procedure Foo( This : in T1; That : in T1_Pointer ); > >Then, in a derivation: > > type T2 is new T1 with ... > >This gives us: > > > procedure Foo( This : in T2; That : in T1_Pointer ); > >Note that the type of the formal 'That' is still T1_Pointer, >probably not what we wanted. > >On the other hand, had we defined things as: > > type T1 is tagged ... > > -- don't need this now... type T1_Pointer is access T1; > > procedure Foo( This : in T1; That : access T1 ); > >The derivation would provide > > procedure Foo( This : in T2; That : access T2 ); > >which is probably the desired result in this case. -- Martin C. Carlisle, Computer Science, US Air Force Academy mcc@cs.usafa.af.mil, http://www.usafa.af.mil/dfcs/bios/carlisle.html DISCLAIMER: This content in no way reflects the opinions, standard or policy of the US Air Force Academy or the United States Government. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 ` Martin C. Carlisle @ 1998-10-22 0:00 ` Pat Rogers 0 siblings, 0 replies; 24+ messages in thread From: Pat Rogers @ 1998-10-22 0:00 UTC (permalink / raw) Martin C. Carlisle wrote in message <70l1nq$mrb$1@cnn.Princeton.EDU>... >Be careful using access as below, as this creates two different >dispatched objects in the call (which is illegal). See LRM 6.1(24) >and 3.9.2 You seem to be saying that there is no legal call with this approach, but neither RM reference supports that conclusion. The actual parameters to a call make a given call illegal or not, and that depends upon what is passed, per call. For example, if the actuals are statically-tagged -- the typical case -- there is no problem. If both actuals are dynamically-tagged they have to have the same tag, which is checked at run-time per RM 3.9.2(16). A call cannot have both statically-tagged and dynamically-tagged controlling operands, per RM 3.9.(8), but that is just one case. >> type T1 is tagged ... >> >> type T1_Pointer is access T1; >> >> procedure Foo( This : in T1; That : in T1_Pointer ); >> >>Then, in a derivation: >> >> type T2 is new T1 with ... >> >>This gives us: >> >> >> procedure Foo( This : in T2; That : in T1_Pointer ); >> >>Note that the type of the formal 'That' is still T1_Pointer, >>probably not what we wanted. >> >>On the other hand, had we defined things as: >> >> type T1 is tagged ... >> >> -- don't need this now... type T1_Pointer is access T1; >> >> procedure Foo( This : in T1; That : access T1 ); >> >>The derivation would provide >> >> procedure Foo( This : in T2; That : access T2 ); >> >>which is probably the desired result in this case. --- Pat Rogers Training & Development in: http://www.classwide.com Deadline Schedulability Analysis progers@acm.org Software Fault Tolerance (281)648-3165 Real-Time/OO Languages ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 ` Pat Rogers 1998-10-21 0:00 ` Martin C. Carlisle @ 1998-10-22 0:00 ` Robert A Duff 1 sibling, 0 replies; 24+ messages in thread From: Robert A Duff @ 1998-10-22 0:00 UTC (permalink / raw) "Pat Rogers" <progers@NOclasswideSPAM.com> writes: > A bit too strong there, IMHO. Access parameters are a very handy > alternative when you want to derive from a type that has primitive > subprograms with a formal parameter of a named access type. Why? > Because access parameters are not named access types, so the > derivation provides primitives with the desired signatures. For > example: > > type T1 is tagged ... > > type T1_Pointer is access T1; > > procedure Foo( This : in T1; That : in T1_Pointer ); But in *most* cases, "That" should be either "in out T1" or "in out T1'Class". You only need it to be a pointer in certain special cases (eg you want Foo to save the pointer into some global data structure). I agree that if you need a pointer, "access T1" is often what you want. I agree with the other posters, who said to use "out" or "in out" usually, and only use "access" if there's some particular reason for it. I must admit, thought that it's annoying that T2_Pointer is not implicitly convertible to T1_Pointer. That conversion is perfectly safe (whereas the other direction involves a run-time check, and should be explicit). > Then, in a derivation: > > type T2 is new T1 with ... > > This gives us: > > > procedure Foo( This : in T2; That : in T1_Pointer ); > > Note that the type of the formal 'That' is still T1_Pointer, > probably not what we wanted. > > On the other hand, had we defined things as: > > type T1 is tagged ... > > -- don't need this now... type T1_Pointer is access T1; > > procedure Foo( This : in T1; That : access T1 ); > > The derivation would provide > > procedure Foo( This : in T2; That : access T2 ); > > which is probably the desired result in this case. - Bob -- Change robert to bob to get my real email address. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 "out" or "access" =:-) Vincent 1998-10-21 0:00 ` Jeff Carter @ 1998-10-21 0:00 ` dennison 1998-10-21 0:00 ` Tucker Taft 2 siblings, 0 replies; 24+ messages in thread From: dennison @ 1998-10-21 0:00 UTC (permalink / raw) In article <908956499.754394@dedale.pandemonium.fr>, "=:-) Vincent" <vb@bruker.fr> wrote: > What's the best way ? > Generally you will want to use "out" unless you *need* to use access. You didn't provide any information about what the routine needs to do with the parameter for me to say if you need access, but in most cases you won't. -- T.E.D. -----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 "out" or "access" =:-) Vincent 1998-10-21 0:00 ` Jeff Carter 1998-10-21 0:00 ` dennison @ 1998-10-21 0:00 ` Tucker Taft 1998-10-22 0:00 ` Pascal Obry 2 siblings, 1 reply; 24+ messages in thread From: Tucker Taft @ 1998-10-21 0:00 UTC (permalink / raw) =:-) Vincent (vb@bruker.fr) wrote: : What's the best way ? An "out" parameter is always preferable to an "access" parameter, in my view. Use an "access" parameter only if you need an access value when inside the called subprogram for some reason. This usually only happens when interfacing to some other language, or some preexisting subsystem of some sort. : package B is : ... : The_Procedure ( The_Parameter: out Integer ); : -- or The_Procedure ( The_Parameter: access Integer ); : ... : end B; : ... : package body A is : ... : g_Toto: Integer; -- or aliased Integer : ... : procedure The_Other_Procedure is : begin : ... : B.The_Procedure ( g_Toto ); : -- or B.The_Procedure( g_Toto'Access ); : ... : end; : ... : end A; : Thanks. -- -Tucker Taft stt@inmet.com http://www.inmet.com/~stt/ Intermetrics, Inc. Burlington, MA USA An AverStar Company ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-21 0:00 ` Tucker Taft @ 1998-10-22 0:00 ` Pascal Obry 1998-10-29 0:00 ` Robert A Duff 0 siblings, 1 reply; 24+ messages in thread From: Pascal Obry @ 1998-10-22 0:00 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 934 bytes --] Tucker Taft a �crit dans le message ... >=:-) Vincent (vb@bruker.fr) wrote: >: What's the best way ? > >An "out" parameter is always preferable to an "access" parameter, in my view. > >Use an "access" parameter only if you need an access value when >inside the called subprogram for some reason. This usually only >happens when interfacing to some other language, or some preexisting >subsystem of some sort. > Ok but be carefull. With an access type you can't pass a null pointer. This is a big problem. In fact if you look at the Win32 C API or UNIX C library you'll find that it is often possible to pass a null pointer to some parameters to say : "ignore this one, I don't care for the result" ! So, in many many cases it is better to use an access type (not an access formal parameter) when interfacing with some other language. Pascal. PS : The Win32Ada binding is full of access parameters that are just wrong ! ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-22 0:00 ` Pascal Obry @ 1998-10-29 0:00 ` Robert A Duff 1998-10-29 0:00 ` Matthew Heaney 0 siblings, 1 reply; 24+ messages in thread From: Robert A Duff @ 1998-10-29 0:00 UTC (permalink / raw) "Pascal Obry" <p.obry@der.edf.fr> writes: > PS : The Win32Ada binding is full of access parameters that are just wrong ! That's because (1) the author didn't know about this rule (that access parameters don't allow null), and (2) the compiler he was using didn't check this rule (back then). The access-parameter feature was invented specifically to solve the following problem: You want to pass a tagged thing as a parameter to a dispatching operation, and of course have it dispatch as usual, but you want to store a pointer to that thing in a global data structure. Therefore, access parameters have these features: (1) if the procedure is in the right place, it's a dispatching op, (2) no null's are allowed, because of course you can't dispatch unless you have a tag, and so the pointer has to point to some tagged object, rather than be null, and (3) you can pass pointers to more-nested things into less-nested procedures (with some run-time accessibility checks). You also get implicit conversion of pointer-to-class-wide types (in the safe direction). In retrospect, I think it would have been better to separate the individual features more orthogonally. Eg, I sometimes want to declare a record component that can never be null -- Ada has a way to declare never-null things, but only if they're formal parameters. Another eg, if "type T2 is new T1...", then T2 implicitly converts to T1'Class, but access-to-T2 does not implicitly convert to access-to-T1'Class, except in the case of access parameters -- I would like a more general feature, to avoid making "safe" conversions explicit. Given the specific problem access params were intended to solve, "access constant" made little sense. But in restrospect, I think we should have allowed it. It was only later that we noticed access params might be useful in interface-to-C. Of course that's only true for C functions that don't expect a NULL. It also requires the compiler to omit the extra dope needed to do the run-time accessibility checks -- of course the C compiler can't deal with that extra dope. - Bob -- Change robert to bob to get my real email address. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-29 0:00 ` Robert A Duff @ 1998-10-29 0:00 ` Matthew Heaney 1998-10-29 0:00 ` Robert A Duff 0 siblings, 1 reply; 24+ messages in thread From: Matthew Heaney @ 1998-10-29 0:00 UTC (permalink / raw) Robert A Duff <bobduff@world.std.com> writes: > Another eg, if "type T2 is new T1...", then T2 implicitly converts to > T1'Class, but access-to-T2 does not implicitly convert to > access-to-T1'Class, except in the case of access parameters -- I would > like a more general feature, to avoid making "safe" conversions > explicit. Agreed. It only adds syntactic overhead, with no added value. Worse, it makes you not pay attention to those type casts that really do matter. > Given the specific problem access params were intended to solve, > "access constant" made little sense. But in restrospect, I think we > should have allowed it. We absolutely need access constant params. It's the only (safe) way to implement a factory method that returns an iterator, so that you can traverse a read-only data structure. For example: generic type Item_Type is private; ... package Queues is type Root_Queue is abstract tagged limited private; ... type Root_Iterator is abstract tagged private; function New_Iterator (Queue : access constant Root_Queue) return Root_Iterator'Class is abstract; function Done (Iterator : Root_Iterator) return Boolean is abstract; procedure Get_Item (Iterator : Root_Iterator) return Item_Type is abstract; procedure Advance (Iterator : in out Root_Iterator); ... end; Every type that derives from Root_Queue is required to implement a factory method (New_Iterator), that allows you to iterate over that structure. This way, you can iterate over class-wide objects: generic with Image (Item : Item_Type) return String is <>; procedure Queues.Put (Queue : in Root_Queue'Class); procedure Queues.Put (Queue : in Root_Queue'Class) is Iter : Root_Iterator'Class := New_Iterator (Queue); begin while not Done (Iter) loop Ada.Text_IO.Put (Image (Get_Item (Iter))); Advance (Iter); end loop; end; Without access constant, you have to use access, which requires a read-write (and aliased) view of the object. It's not so bad in the example above, because we could always declare procedure Put to take the queue object as in out. But this will not work for functions, ie function "=" (L, R : Root_Queue'Class) return Boolean; because functions can't take in out params, and a comparison of class-wide objects should only be a read-only activity anyway. So you have to work around this by declaring functions to take access params: function "=" (L, R : access Root_Queue'Class) return Boolean; which is really ugly. Not having access constant parameters tends to cause a ripple effect, were you have to go back declare objects as aliased, or to change subprograms that have args of mode in to mode in out or access. In my work on the Ada Components Library, I've worked around this by resorting to ugly hacks like using System.Address_To_Access_Conversions and parameters of a named access-to-constant type. The latter approach means I lose the ability to dispatch, which is a REAL bummer. Please, let's fix this omission, sooner rather than later. We need access constant parameters. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-29 0:00 ` Matthew Heaney @ 1998-10-29 0:00 ` Robert A Duff 1998-10-30 0:00 ` dennison 0 siblings, 1 reply; 24+ messages in thread From: Robert A Duff @ 1998-10-29 0:00 UTC (permalink / raw) Matthew Heaney <matthew_heaney@acm.org> writes: > Agreed. It only adds syntactic overhead, with no added value. Worse, > it makes you not pay attention to those type casts that really do > matter. Yes. The boy who cried "wolf". > Not having access constant parameters tends to cause a ripple effect, > ... I agree with your points. But how about this workaround: declare New_Iterator to take an 'in' parameter of type Root_Queue. (Presuming you really do want an iterator that can't modify the thing it's iterating over.) So it's dispatching, which you want. Inside the various overridings of it, you will normally have to do 'Unchecked_Access to produce a pointer to the thing, which you would presumably store inside the iterator object. This works because all tagged parameters are aliased. It's slightly ugly, and slightly unsafe, but at least it's fairly localized. You do have to warn your clients that they had better not let an iterator live longer that what it's iterating over. Don't you agree that this workaround is better than the ones that cause those nasty ripple effects? > We need access constant parameters. Well, we at least *want* them. - Bob -- Change robert to bob to get my real email address. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-29 0:00 ` Robert A Duff @ 1998-10-30 0:00 ` dennison 1998-10-30 0:00 ` Matthew Heaney 0 siblings, 1 reply; 24+ messages in thread From: dennison @ 1998-10-30 0:00 UTC (permalink / raw) In article <wcc3e87hrl8.fsf@world.std.com>, Robert A Duff <bobduff@world.std.com> wrote: > But how about this workaround: declare New_Iterator to take an 'in' > parameter of type Root_Queue. (Presuming you really do want an iterator > that can't modify the thing it's iterating over.) So it's dispatching, > which you want. Inside the various overridings of it, you will normally > have to do 'Unchecked_Access to produce a pointer to the thing, which I must be missing something here. Isn't it possible that taking an 'Unchecked_Access of an in parameter will just give you a pointer to a copy of the object on the stack, which will disappear when the procedure ends? Or are you saying to do a ".all'Unchecked_Access" on the in parameter? -- T.E.D. -----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-30 0:00 ` dennison @ 1998-10-30 0:00 ` Matthew Heaney 1998-10-30 0:00 ` Robert A Duff 0 siblings, 1 reply; 24+ messages in thread From: Matthew Heaney @ 1998-10-30 0:00 UTC (permalink / raw) dennison@telepath.com writes: > In article <wcc3e87hrl8.fsf@world.std.com>, > Robert A Duff <bobduff@world.std.com> wrote: > >> But how about this workaround: declare New_Iterator to take an 'in' >> parameter of type Root_Queue. (Presuming you really do want an >> iterator that can't modify the thing it's iterating over.) So it's >> dispatching, which you want. Inside the various overridings of it, >> you will normally have to do 'Unchecked_Access to produce a pointer >> to the thing, which > > I must be missing something here. Isn't it possible that taking an > 'Unchecked_Access of an in parameter will just give you a pointer to a > copy of the object on the stack, which will disappear when the > procedure ends? Or are you saying to do a ".all'Unchecked_Access" on > the in parameter? We're talking about tagged types here, and there are special rules that apply to objects of a tagged type. The RM mandates that tagged types be passed by reference, and so tagged types passed as subprogram arguments are "implicitly aliased." That's why you can say: procedure Op (O : in T) is -- T is a tagged type type TA is access constant T; OA : constant TA := O'Access; begin without O being declared as "access T" --because T is tagged. Ditto for procedure Op (O : in out T) is type TA is access all T; OA : constant TA := O'Access; begin The RM also recommends that implementations "deliver a useful result" when you take the O'Address of a by-reference type (tagged types, limited types) passed as a subprogram parameter. That's why Sys.Addr_To_Acc_Conv can be used to work around this problem. You don't ever have to pass tagged types as access parameters --unless you need the operation to dispatch. My problem is I need to do this: procedure Visit (S : Stack'Class) is I : Iterator'Class := Initialize (S'Access); begin where Initialize is a function that takes a _constant_ access parameter and returns an iterator (whose type is class-wide). The problem is ... I can't do that, because access constant parameters don't exist in the language. The workaround is to pass the argument as an in param --not access constant param-- so it will dispatch, then use Addr_To_Acc_Conv to turn that into a useful pointer: function Initialize (S : Stack) return Iterator'Class; This func is primitive for type Stack, and therefore it dispatches: package Stacks.My_Stacks is type My_Stack is new Stack with private; type My_Iterator is new Iterator with private; function Initialize (S : My_Stack) return Iterator'Class; ... private ... package Conv is new Sys.Addr_To_Acc_Conv (My_Stack); type My_Iterator is new Iterator with record Stack : Conv.Object_Pointer; Index : <some index type>; end record; function Initialize (S : My_Stack) return Iterator'Class is begin return My_Iterator'(To_Pointer (S'Address), S.Top); end; So now the iterator object contains a pointer to the stack object passed in. The works --and I'm not unhappy with it-- it's just that there's no way to prevent dangling references, as you can with access parameters. The declaration procedure Print (S : Stack'Class) is Iter : Iterator'Class := Start_At_Top (S); begin doesn't make it obvious that the _address_ of S is being looked at, and that object Iter contains a pointer to S. That's why it's important to make sure that the stack object lives at least as long as the iterator, or else a dangling reference will occur. I'd much rather say procedure Print (S : Stack'Class) is Iter : Iterator'Class := Start_At_Top (S'Access); begin because it states explicitly that I'm manipulating a reference, but I can't do that, because the language doesn't allow it. So although technically speaking you don't _need_ access constant parameters --because an in param dispatches, and you can sensibly take the address of a tagged type passed as a param-- having access constant parameters is still _strongly_ desireable. It frustrates me that you can't implement a factory method for an iterator, without having to use back-door methods. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-30 0:00 ` Matthew Heaney @ 1998-10-30 0:00 ` Robert A Duff 1998-10-31 0:00 ` dewar 1998-10-31 0:00 ` Matthew Heaney 0 siblings, 2 replies; 24+ messages in thread From: Robert A Duff @ 1998-10-30 0:00 UTC (permalink / raw) Matthew Heaney <matthew_heaney@acm.org> writes: > The RM also recommends that implementations "deliver a useful result" > when you take the O'Address of a by-reference type (tagged types, > limited types) passed as a subprogram parameter. That's why > Sys.Addr_To_Acc_Conv can be used to work around this problem. I don't understand why you want to use 'Address at all. My earlier suggestion was to use 'Unchecked_Access. It has the same problem with possible dangling references, but at least it doesn't throw type checking completely out the window, as 'Address does. > type My_Iterator is > new Iterator with record > Stack : Conv.Object_Pointer; ^^^^^^^^^^^^^^^^^^^ Say My_Stack_Ptr, which is declared "access constant My_Stack", and then... > Index : <some index type>; > end record; > > function Initialize (S : My_Stack) return Iterator'Class is > begin > return My_Iterator'(To_Pointer (S'Address), S.Top); return My_Iterator'(S'Unchecked_Access, S.Top); > end; By the way, have you considered making the iterators limited, and initializing them with a discriminant that points to the Stack (or whatever is being iterated)? - Bob -- Change robert to bob to get my real email address. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-30 0:00 ` Robert A Duff @ 1998-10-31 0:00 ` dewar 1998-10-31 0:00 ` Matthew Heaney 1998-10-31 0:00 ` Matthew Heaney 1 sibling, 1 reply; 24+ messages in thread From: dewar @ 1998-10-31 0:00 UTC (permalink / raw) In article <wccpvb9vh0k.fsf@world.std.com>, Robert A Duff <bobduff@world.std.com> wrote: > Matthew Heaney <matthew_heaney@acm.org> writes: > > > The RM also recommends that implementations "deliver a useful result" > > when you take the O'Address of a by-reference type (tagged types, > > limited types) passed as a subprogram parameter. That's why > > Sys.Addr_To_Acc_Conv can be used to work around this problem. > > I don't understand why you want to use 'Address at all. > My earlier suggestion was to use 'Unchecked_Access. > It has the same problem with possible dangling references, > but at least it doesn't throw type checking completely out > the window, as 'Address does. Note that Unchecked_Access still has restrictions which can be annoying, it cannot be applied to parameters for example, because it still requires the object to be aliased. In GNAT, the Unrestricted_Access attribute can be used anywhere 'Address is usable, and is comparable in effect, except that strong typing of the resulting pointer is retained. Robert Dewar Ada Core Technologies -----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-31 0:00 ` dewar @ 1998-10-31 0:00 ` Matthew Heaney 0 siblings, 0 replies; 24+ messages in thread From: Matthew Heaney @ 1998-10-31 0:00 UTC (permalink / raw) dewar@gnat.com writes: > Note that Unchecked_Access still has restrictions which can be annoying, it > cannot be applied to parameters for example, because it still requires the > object to be aliased. I wish we could liberalize the rules here. Right now, you can only apply the Access attribute to an aliased object, which means the object has to be publically tagged. I've had to declare types as publically tagged --even though I don't think the abstraction requires it-- because elsewhere I require an aliased view. It would be hipper if you were allowed to use the Access attribute for objects whose _full_ view is limited or tagged, even if the partial (public) isn't. There's a precedent for this: the full view of a type in a generic package may privately derive from Finalization.Controlled. This means instantations can only be done at library level. This feature of the abstraction isn't stated publically stated -- the compiler has to tell you at time of instantation. Why not use a similar rule for Unchecked_Access: you can only do it if the _full_ view of the type is limited or tagged, irrespective of what the partial view says. > In GNAT, the Unrestricted_Access attribute can be used anywhere > 'Address is usable, and is comparable in effect, except that strong > typing of the resulting pointer is retained. This is a very nice attribute, but I've been loathe to use it, because of potential portability problems. It would be helpful if all vendors provided at least a weak form of the Unrestricted_Access attribute. For example, I don't really care about downward closures. But using it to effect type-safe conversion from an access-to-constant into an access-to-variable seems pretty painless. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-30 0:00 ` Robert A Duff 1998-10-31 0:00 ` dewar @ 1998-10-31 0:00 ` Matthew Heaney 1998-11-01 0:00 ` Robert A Duff 1 sibling, 1 reply; 24+ messages in thread From: Matthew Heaney @ 1998-10-31 0:00 UTC (permalink / raw) Robert A Duff <bobduff@world.std.com> writes: > I don't understand why you want to use 'Address at all. > My earlier suggestion was to use 'Unchecked_Access. > It has the same problem with possible dangling references, > but at least it doesn't throw type checking completely out > the window, as 'Address does. > > > type My_Iterator is > > new Iterator with record > > Stack : Conv.Object_Pointer; > ^^^^^^^^^^^^^^^^^^^ > Say My_Stack_Ptr, which is declared "access constant My_Stack", and > then... You are correct. However, the library I'm building has one iterator type, that can be used to both query and modify objects in the collection. The representation of the iterator must therefore include an access-to-variable access type. (Actually, I could do it the other way around: implement the iterator type using an access-to-constant access type, and use addr-to-acc-conv inside the one operation that modifies state. Hmmm...) So perhaps I'm going beyond what even access constant params buy you. Maybe my real problem is how to "cast away const." It would be hip if the language provided a way to do that explicitly, analogous to something like Unchecked_Conversion. BTW: does the language define --or give implementation advice-- on what the effect of unchecked conversion from access-to-constant to access-to-variable is? Or is it the intention of the designers that you never try to do that? Real programmers --like me-- are occasionally going to need to cast away const. The language designers should state explictly 1) that you shouldn't do that, or 2) that it's OK to do it, and here's how. If you don't say, then I'm going to do it _some_ way, perhaps using a technique you didn't intend. Just tell me what your specific intent is. > By the way, have you considered making the iterators limited, > and initializing them with a discriminant that points to the > Stack (or whatever is being iterated)? Oh yes, but this doesn't meet my needs, because you need to call a dispatching operation ("factory method") that returns an iterator of a class-wide type. Class-wide types are indefinate, and therefore require initialization during object declaration, which isn't possible if the type is limited. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-10-31 0:00 ` Matthew Heaney @ 1998-11-01 0:00 ` Robert A Duff 1998-11-01 0:00 ` Matthew Heaney 0 siblings, 1 reply; 24+ messages in thread From: Robert A Duff @ 1998-11-01 0:00 UTC (permalink / raw) Matthew Heaney <matthew_heaney@acm.org> writes: > You are correct. However, the library I'm building has one iterator > type, that can be used to both query and modify objects in the > collection. The representation of the iterator must therefore include > an access-to-variable access type. Perhaps you should have two different sorts of iterators, one that can modify, and one that can't. > So perhaps I'm going beyond what even access constant params buy you. > Maybe my real problem is how to "cast away const." Sounds dangerous. >... It would be hip if > the language provided a way to do that explicitly, analogous to > something like Unchecked_Conversion. > > BTW: does the language define --or give implementation advice-- on what > the effect of unchecked conversion from access-to-constant to > access-to-variable is? Or is it the intention of the designers that you > never try to do that? I think you should not do that. What should it mean? I mean, if you modify a constant? An Ada compiler is within it's rights to put constant stuff in read-only memory -- and if you modify it, you get a core dump or some such nasty thing. Or share memory for the same constant data -- you better not change it. Perhaps you should give an example. It seems like cast-away-const is even worse than any type-cheating one might want to do. > Oh yes, but this doesn't meet my needs, because you need to call a > dispatching operation ("factory method") that returns an iterator of a > class-wide type. Class-wide types are indefinate, and therefore require > initialization during object declaration, which isn't possible if the > type is limited. I wish we could initialize limited things, but still not copy them around. Sigh. - Bob -- Change robert to bob to get my real email address. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-11-01 0:00 ` Robert A Duff @ 1998-11-01 0:00 ` Matthew Heaney 1998-11-01 0:00 ` Robert A Duff 0 siblings, 1 reply; 24+ messages in thread From: Matthew Heaney @ 1998-11-01 0:00 UTC (permalink / raw) Robert A Duff <bobduff@world.std.com> writes: > Perhaps you should have two different sorts of iterators, one that can > modify, and one that can't. Yes, I thought of that too, but I was trying to keep things simple. > > So perhaps I'm going beyond what even access constant params buy you. > > Maybe my real problem is how to "cast away const." > > Sounds dangerous. "const" in the sense of in param: function Set_Top (Stack : Stack_Type) return Item_Access is SA : constant Object_Pointer := To_Pointer (Stack'Address); begin pragma Assert (Stack.Length > 0); return SA.Items (Stack.Top)'Access; end Set_Top; So the client can: Set_Top (Stack).all := 10; Of course, here it's not strictly necessary, since I can declare Set_Top to take an access parameter. The "const" thing is the entity passed as the in-param of the function call. In my case, the entities are always tagged, and so are aliased, and so taking the address is well-defined. The behavior I'm thinking of is analogous to what happens when you call function Random of the random number generator. Essentially, I'm trying to get around Ada's lack of in out params for functions. How does the Ada programmer implement his own abstractions whose functions have state-changing behavior -- like Random does? Yes, yes, I know you can implement the abstraction as a controlled record containing a pointer to the "real" data, but I was investigating cheaper alternatives. Why is the RM so silent on intended uses of package System.Address_To_Access_Conversions? If the designers don't intend for you to use it as in my example above, then why doesn't the RM just come right out and say that? > > BTW: does the language define --or give implementation advice-- on what > > the effect of unchecked conversion from access-to-constant to > > access-to-variable is? Or is it the intention of the designers that you > > never try to do that? > > I think you should not do that. What should it mean? I mean, if you > modify a constant? An Ada compiler is within it's rights to put > constant stuff in read-only memory -- and if you modify it, you get a > core dump or some such nasty thing. Or share memory for the same > constant data -- you better not change it. I should have asked, How do the language designers intend Ada programmers to implement a side-effect producing function, whose param (of mode in) is a tagged type? When I do this: function Set_Top (Stack : Stack_Type) return Item_Access is begin ... Stack'Access ... this gives me an access-to-constant view. I want an access-to-variable view. I wasn't trying to change a "constant," in the sense of a constant object declaration (which isn't possible for limited types anyway), but rather I was trying to turn a constant view --of an otherwise modifiable object-- into a variable view. > Perhaps you should give an example. It seems like cast-away-const is > even worse than any type-cheating one might want to do. > > Oh yes, but this doesn't meet my needs, because you need to call a > > dispatching operation ("factory method") that returns an iterator of a > > class-wide type. Class-wide types are indefinate, and therefore require > > initialization during object declaration, which isn't possible if the > > type is limited. > > I wish we could initialize limited things, but still not copy them > around. Sigh. I would be really swell if we had constructors too, not just functions trying to do the job. The latter technique doesn't work for limited types. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-11-01 0:00 ` Matthew Heaney @ 1998-11-01 0:00 ` Robert A Duff 1998-11-02 0:00 ` Matthew Heaney 0 siblings, 1 reply; 24+ messages in thread From: Robert A Duff @ 1998-11-01 0:00 UTC (permalink / raw) Matthew Heaney <matthew_heaney@acm.org> writes: > Robert A Duff <bobduff@world.std.com> writes: > > > Perhaps you should have two different sorts of iterators, one that can > > modify, and one that can't. > > Yes, I thought of that too, but I was trying to keep things simple. Too simple? > > > So perhaps I'm going beyond what even access constant params buy you. > > > Maybe my real problem is how to "cast away const." > > > > Sounds dangerous. > > "const" in the sense of in param: > > function Set_Top > (Stack : Stack_Type) > return Item_Access is > > SA : constant Object_Pointer := > To_Pointer (Stack'Address); > begin > pragma Assert (Stack.Length > 0); > return SA.Items (Stack.Top)'Access; > end Set_Top; > > So the client can: > > Set_Top (Stack).all := 10; But this allows clients to write upon constants, which sounds like a Bad Thing. > Of course, here it's not strictly necessary, since I can declare Set_Top > to take an access parameter. > > The "const" thing is the entity passed as the in-param of the function > call. In my case, the entities are always tagged, and so are aliased, > and so taking the address is well-defined. But writing upon constants is not. > The behavior I'm thinking of is analogous to what happens when you call > function Random of the random number generator. ...which is pretty ugly, IMHO. > Essentially, I'm trying to get around Ada's lack of in out params for > functions. How does the Ada programmer implement his own abstractions > whose functions have state-changing behavior -- like Random does? I wish functions allowed 'in out' params. In the absence of that, you can do the Random trick, but that's kind of messy. I'd suggest an explicit access type instead. > Yes, yes, I know you can implement the abstraction as a controlled > record containing a pointer to the "real" data, but I was investigating > cheaper alternatives. > > Why is the RM so silent on intended uses of package > System.Address_To_Access_Conversions? Because the RM isn't a text book, I guess. > I should have asked, How do the language designers intend Ada programmers > to implement a side-effect producing function, whose param (of mode in) > is a tagged type? I think the language designers intend that you shouldn't do that. As far as the language design issue goes, I'm on your side -- 'in out' should be allowed in functions. But since it isn't, I wouldn't resort to the extreme trickery you suggest. > When I do this: > > function Set_Top (Stack : Stack_Type) return Item_Access is > begin > ... Stack'Access ... > > this gives me an access-to-constant view. I want an access-to-variable > view. > > I wasn't trying to change a "constant," in the sense of a constant > object declaration (which isn't possible for limited types anyway), but > rather I was trying to turn a constant view --of an otherwise modifiable > object-- into a variable view. I would suggest you either pass explicit access values, or else give up on functions and use procedures. > I would be really swell if we had constructors too, not just functions > trying to do the job. The latter technique doesn't work for limited > types. That was my point -- *initializing* a limited object with a function call should not be illegal. It's assigning them around after that that causes trouble. Likewise, an aggregate of a limited type could make perfect sense, if it's only used to *initialize* an object. - Bob -- Change robert to bob to get my real email address. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-11-01 0:00 ` Robert A Duff @ 1998-11-02 0:00 ` Matthew Heaney 1998-11-03 0:00 ` Simon Wright 0 siblings, 1 reply; 24+ messages in thread From: Matthew Heaney @ 1998-11-02 0:00 UTC (permalink / raw) Robert A Duff <bobduff@world.std.com> writes: > > > Perhaps you should have two different sorts of iterators, one that can > > > modify, and one that can't. > > > > Yes, I thought of that too, but I was trying to keep things simple. > > Too simple? Ah, the process of design -- something about which I'm sure you are familiar. I'm designing a data structure library --which I've been calling the Ada Components Library-- which comprises pluggable units. You assemble the data structure having the space & time characteristics you desire, from a simpler set of primitives. (Sound like our favorite language?) This avoids the combinatorial explosion the plagued the original Booch components. He had to build tens and tens of data structures, anticipating every combination. The ACL isn't like that. It's very simple -- only a few hundred lines. (Actually, what made it all possible is composition via access discriminants.) Every data structure allows you to traverse that data structure one element at a time. Typically, there are two ways to do this - passive iteration and active iteration. From time-to-time, it's desirable to change the values of the items in the data structure, without resorting to inefficient "solutions" like copying the original data structure, and changing the source values prior to insertion into the target structure. You just want to change the values in place. You could use a passive iterator to do this. The data structure is passed inout, and the Process procedure passed as a generic formal takes each item as mode inout. You therefore have to provide two kinds of passive iterators: a read-only version, and a read-write version. The former is necessary because you could be in a subprogram (say, a Print routine) that takes the data structure as mode in. So now things are starting to get overwhelming, if you consider that I have to provide possibly two kinds of active iterators too. My desire is to keep the library as simple as possible. By providing primitive components, the client can assemble those primitives together to effect the desired behavior. You don't have to everything for him. We can keep the library simpler by providing only an active iterator, and letting the client assemble a passive iterator himself (by using the active iterator). But if there are two kinds of passive iterators, that means that either 1) I have to provide two active iterators, one for read-only, and one for read-write, or 2) provide one active iterator that can be used in both read-only or read-write contexts. Obviously, my choice is for one active iterator, that allows you to modify data structure elements, but that can be used anywhere, including those places where the data structure is Officially read-only. It may seem like using Addr_To_Acc_Conv for this is a "dirty trick," but the client is going to build an infrastructure on top of the primitives, and it's that ultimate data structure that is going to allow only "legal" things. For example, here's our two passive iterators: generic with procedure Process (Item : in Item_Type); procedure Select_Items (Stack : in Stack_Type); generic with procedure Process (Item : in out Item_Type); procedure Modify_Items (Stack : in out Stack_here's); There's nothing "illegal" here: items can be selected from a read-only stack, and can be modified from a read-write stack. The client allows only meaningful behavior for his stack. We can use one active iterator to build both kinds of passive iterators: procedure Select_Items (Stack : in Stack_Type) is Iter : Stack_Iterator := Start_At_Top (Stack'Access); begin for I in 1 .. Get_Length (Stack) loop Process (Get_Item (Iter)); Advance (Iter); end loop; end; procedure Modify_Items (Stack : in out Stack_Type) is Iter : Stack_Iterator := Start_At_Top (Stack'Access); begin for I in 1 .. Get_Length (Stack) loop Process (Get_Item (Iter)); Advance (Iter); end loop; end; As you can see, these have the same body. Only one active iterator type is required, in order to effect both kinds of ultimate behavior. Is that _too_ simple? My philosophy is, less is more. > But this allows clients to write upon constants, which sounds like a Bad > Thing. All of these data structures are tagged limited private. They can't ever be constant, can they? > > The "const" thing is the entity passed as the in-param of the function > > call. In my case, the entities are always tagged, and so are aliased, > > and so taking the address is well-defined. > > But writing upon constants is not. What's your defination of "constant"? Is a (limited) by-reference object passed as an in parameter a constant? That's the only kind of constant I was talking about. Actually, I think Ada goes too far wrt to parameter modes. For an abstract data type, the arguments to subprograms should describe only a logical view of the abstraction; what the client sees. But internally, the implementor of an abstraction should be able to change the state of the object as a side-effect of the call -- even if the parameter mode is in. It's his business how to implement his abstraction. In Ada, the outside view of the abstraction tends to constrain the inside view too. In a sense, by specifying the mode (in vs inout) for the object of the abstract data type, you've overspecified. By passing the arg as inout --just so you can produce a side-effect legally-- you've exposed an aspect of the implementation, that isn't necessarily important to clients. That's why the "pure" object-oriented notation: Object.Do_Something is nice, because it allows the implementor to make whatever state changes are required in order to effect logical behavior, without having to announce whether state changes are in fact required. It's not the client's business to know. > > Essentially, I'm trying to get around Ada's lack of in out params for > > functions. How does the Ada programmer implement his own abstractions > > whose functions have state-changing behavior -- like Random does? > > I wish functions allowed 'in out' params. > > In the absence of that, you can do the Random trick, but that's kind of > messy. I'd suggest an explicit access type instead. For my Set_Top function, that's what I did: function Set_Top (Stack : access Stack_Type) return Item_Access; ... Set_Top (Stack'Access).all := 42; What's motivating this is that I can write a stack that works for limited private items. Ever needed a stack of File_Types? Something like: Stack : access Stack_Type; -- of File_Type ... declare File : File_Type renames Push (Stack'Access).all; begin Create (File, Name => "matt.dat"); ... declare File : File_Type renames Set_Top (Stack'Access).all; begin Close (File); Pop (Stack); end; > > I should have asked, How do the language designers intend Ada programmers > > to implement a side-effect producing function, whose param (of mode in) > > is a tagged type? > > I think the language designers intend that you shouldn't do that. Then the intentions of the language designers are unclear, because of function Random. Programmers are going expect that they can do that kind of thing too, efficiently, and within the language. > > I would be really swell if we had constructors too, not just functions > > trying to do the job. The latter technique doesn't work for limited > > types. > > That was my point -- *initializing* a limited object with a function > call should not be illegal. It's assigning them around after that that > causes trouble. Likewise, an aggregate of a limited type could make > perfect sense, if it's only used to *initialize* an object. Yes! ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-11-02 0:00 ` Matthew Heaney @ 1998-11-03 0:00 ` Simon Wright 1998-11-16 0:00 ` Matthew Heaney 0 siblings, 1 reply; 24+ messages in thread From: Simon Wright @ 1998-11-03 0:00 UTC (permalink / raw) Matthew Heaney <matthew_heaney@acm.org> writes: > I'm designing a data structure library --which I've been calling the Ada > Components Library-- which comprises pluggable units. You assemble the > data structure having the space & time characteristics you desire, from > a simpler set of primitives. (Sound like our favorite language?) [..] > From time-to-time, it's desirable to change the values of the items in > the data structure, without resorting to inefficient "solutions" like > copying the original data structure, and changing the source values > prior to insertion into the target structure. You just want to change > the values in place. Yes, I'm going through the same throes with the Booch Components at the moment. Having the ability to change components in place during iteration causes a whole lot of grief, in the BCs showing up as generic type Item is private; type Item_Ptr is access all Item; package BC.Containers is yecch ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: "out" or "access" 1998-11-03 0:00 ` Simon Wright @ 1998-11-16 0:00 ` Matthew Heaney 0 siblings, 0 replies; 24+ messages in thread From: Matthew Heaney @ 1998-11-16 0:00 UTC (permalink / raw) Simon Wright <simon@pogner.demon.co.uk> writes: > > From time-to-time, it's desirable to change the values of the items in > > the data structure, without resorting to inefficient "solutions" like > > copying the original data structure, and changing the source values > > prior to insertion into the target structure. You just want to change > > the values in place. > > Yes, I'm going through the same throes with the Booch Components at > the moment. > > Having the ability to change components in place during iteration > causes a whole lot of grief, in the BCs showing up as > > generic > type Item is private; > type Item_Ptr is access all Item; > package BC.Containers is Here are some ideas: o Just use a passive iterator: generic with procedure Process (Item : in out Item_Type; Quit : in out Boolean); procedure Modify_Items (Stack : in out Stack_Type); o Use an read-only active iterator, but with a special op that takes the structure as an access parameter: type Stack_Iterator is private; type Stack_Access is access constant Stack_Type; function Start_At_Top (Stack : Stack_Access) return Stack_Iterator; function Set_Item (Stack : access Stack_Type; Iterator : in Stack_Iterator) return Item_Access; Use it like: Stack : aliased Stack_Type; ... declare Iterator : Stack_Iterator := Start_At_Top (Stack'Access); begin for I in 1 .. Get_Length (Stack) loop declare Item : Item_Type renames Set_Item (Stack'Access, Iterator).all; begin Item := Item + 1; end; end loop; end; This is legal Ada, without requiring any "tricks." o Use an normally read-only active iterator, but use Sys.Addr_To_Acc_Conv to convert the read-only view of the structure into a read-write view: type Stack_Iterator is private; type Stack_Access is access constant Stack_Type; function Start_At_Top (Stack : Stack_Access) return Stack_Iterator; but now Set_Item looks like: function Set_Item (Iterator : Stack_Iterator) return Item_Access; The implementation is function Set_Item (Iterator : Stack_Iterator) return Item_Access is Read_Only : Stack_Type renames Iterator.Stack.all; package Conversions is new Sys.Addr_To_Acc_Conv (Stack_Type); use Conversions; Read_Write : Stack_Type renames To_Pointer (Read_Only'Address).all; begin return Read_Write.Items (Iterator.Index)'Access; end Set_Item; Now you only have to say: Stack : aliased Stack_Type; ... declare Iterator : Stack_Iterator := Start_At_Top (Stack'Access); begin for I in 1 .. Get_Length (Stack) loop declare Item : Item_Type renames Set_Item (Iterator).all; begin Item := Item + 1; end; end loop; end; ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~1998-11-16 0:00 UTC | newest] Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1998-10-21 0:00 "out" or "access" =:-) Vincent 1998-10-21 0:00 ` Jeff Carter 1998-10-21 0:00 ` Pat Rogers 1998-10-21 0:00 ` Martin C. Carlisle 1998-10-22 0:00 ` Pat Rogers 1998-10-22 0:00 ` Robert A Duff 1998-10-21 0:00 ` dennison 1998-10-21 0:00 ` Tucker Taft 1998-10-22 0:00 ` Pascal Obry 1998-10-29 0:00 ` Robert A Duff 1998-10-29 0:00 ` Matthew Heaney 1998-10-29 0:00 ` Robert A Duff 1998-10-30 0:00 ` dennison 1998-10-30 0:00 ` Matthew Heaney 1998-10-30 0:00 ` Robert A Duff 1998-10-31 0:00 ` dewar 1998-10-31 0:00 ` Matthew Heaney 1998-10-31 0:00 ` Matthew Heaney 1998-11-01 0:00 ` Robert A Duff 1998-11-01 0:00 ` Matthew Heaney 1998-11-01 0:00 ` Robert A Duff 1998-11-02 0:00 ` Matthew Heaney 1998-11-03 0:00 ` Simon Wright 1998-11-16 0:00 ` Matthew Heaney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox