comp.lang.ada
 help / color / mirror / Atom feed
* Two approaches of iterators for the key-value pairs
@ 2015-11-27 15:25 ytomino
  2015-11-27 16:30 ` Dmitry A. Kazakov
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: ytomino @ 2015-11-27 15:25 UTC (permalink / raw)


Hello, I'm reading AI12-0009-1 "Iterators for Directories and Environment_Variables".
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0009-1.txt?rev=1.4

And there is interesting difference between the new iterator of Ada.Environment_Variables and the existing iterators.
(The boolean trick of these new iterators is also interesting, but set aside.)

A loop for Ada.Environment_Variables would be like below, according to this AI:

for E *of* Ada.Environment_Variables.All_Variables loop
   -- E is Iterator_Element (Name_Value_Pair_Type)
   Name (E) -- key
   Value (E) -- value
end loop;

On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:

for I *in* The_Map_Object.Iterate loop
   -- I is Cursor
   Key (E) -- key
   Element (E), Reference (E).Element.all -- value
end loop;

If you create new iterator for some key-value pairs, which approach do you like?

-- 
Yuta Tomino

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 15:25 Two approaches of iterators for the key-value pairs ytomino
@ 2015-11-27 16:30 ` Dmitry A. Kazakov
  2015-11-27 18:08   ` ytomino
  2015-11-27 17:00 ` Pascal Obry
  2015-11-27 17:43 ` Brad Moore
  2 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-27 16:30 UTC (permalink / raw)


On Fri, 27 Nov 2015 07:25:57 -0800 (PST), ytomino wrote:

> Hello, I'm reading AI12-0009-1 "Iterators for Directories and Environment_Variables".
> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0009-1.txt?rev=1.4
> 
> And there is interesting difference between the new iterator of Ada.Environment_Variables and the existing iterators.
> (The boolean trick of these new iterators is also interesting, but set aside.)
> 
> A loop for Ada.Environment_Variables would be like below, according to this AI:
> 
> for E *of* Ada.Environment_Variables.All_Variables loop
>    -- E is Iterator_Element (Name_Value_Pair_Type)
>    Name (E) -- key
>    Value (E) -- value
> end loop;
> 
> On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:
> 
> for I *in* The_Map_Object.Iterate loop
>    -- I is Cursor
>    Key (E) -- key
>    Element (E), Reference (E).Element.all -- value
> end loop;
> 
> If you create new iterator for some key-value pairs, which approach do you like?

Rather this:

for Variable in All_Variables loop
   Put_Line (Variable.Name & "=" & Variable.Value);
end loop;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 15:25 Two approaches of iterators for the key-value pairs ytomino
  2015-11-27 16:30 ` Dmitry A. Kazakov
@ 2015-11-27 17:00 ` Pascal Obry
  2015-11-27 18:25   ` ytomino
  2015-11-27 17:43 ` Brad Moore
  2 siblings, 1 reply; 17+ messages in thread
From: Pascal Obry @ 2015-11-27 17:00 UTC (permalink / raw)


Le vendredi 27 novembre 2015 à 07:25 -0800, ytomino a écrit :
> If you create new iterator for some key-value pairs, which approach
> do you like?

I'd like to have tuples in Ada and be able to say:

   for (Name, Value) of Environment_Variables.All_Variables loop
      Put_Line (Name & " = " & Value);
   end loop;

In many cases tuple would be handy, avoiding creating record in some
cases just to be able to return two values from a function for example.

-- 
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://v2p.fr.eu.org
  http://www.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 15:25 Two approaches of iterators for the key-value pairs ytomino
  2015-11-27 16:30 ` Dmitry A. Kazakov
  2015-11-27 17:00 ` Pascal Obry
@ 2015-11-27 17:43 ` Brad Moore
  2015-11-27 19:38   ` ytomino
  2 siblings, 1 reply; 17+ messages in thread
From: Brad Moore @ 2015-11-27 17:43 UTC (permalink / raw)


On Friday, November 27, 2015 at 8:26:02 AM UTC-7, ytomino wrote:
> Hello, I'm reading AI12-0009-1 "Iterators for Directories and Environment_Variables".
> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0009-1.txt?rev=1.4
> 
> And there is interesting difference between the new iterator of Ada.Environment_Variables and the existing iterators.
> (The boolean trick of these new iterators is also interesting, but set aside.)

I'm not sure what is being referred to here as a "boolean trick". Perhaps you are referring to the mention of "Rosen Trick", which as Randy points out, should probably be called "Rosen Technique". However that has nothing to do with "Boolean". The Rosen technique is a coding technique that allows one to treat a read only "in" parameter as a modifiable "in out" parameter.

> 
> A loop for Ada.Environment_Variables would be like below, according to this AI:
> 
> for E *of* Ada.Environment_Variables.All_Variables loop
>    -- E is Iterator_Element (Name_Value_Pair_Type)
>    Name (E) -- key
>    Value (E) -- value
> end loop;
> 
> On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:
> 
> for I *in* The_Map_Object.Iterate loop
>    -- I is Cursor
>    Key (E) -- key
>    Element (E), Reference (E).Element.all -- value
> end loop;

All the existing containers are iterable containers, so they support
both using "of" and "in" syntax for loops. Using "of" is generally preferable
because cursors are implicit, and the code written by the user is therefore simpler. Using "in" syntax can also be used by obtaining an Iterator object, but this gives you a cursor instead of a container element, so you typically would need to write some extra calls to get to the container element from the cursor object.


This code excerpt you had above would not compile, so it is probably confusing people.
It think it would be better to perhaps show a full simple working example, such as incrementing each element of the container;
Here I show both forms of loop using a Hashed_Map container. As you can see,
the "of" format is simpler, and hopefully easier to read and understand.

with Ada.Containers.Hashed_Maps; use Ada;
procedure Test_Iterator is
   
   type Student_Id is new Positive;
   type Grade is new Natural range 0 .. 100;
   function Hash (Student : Student_Id) return Containers.Hash_Type is
     (Containers.Hash_Type (Student));
   
   package Maps is new Ada.Containers.Hashed_Maps 
     (Key_Type        => Student_Id,
      Element_Type    => Grade,
      Hash            => Hash,
      Equivalent_Keys => "=");

   School : Maps.Map;
   
begin

   School.Insert (Key      => 123456,    -- Student A
                  New_Item => 90);
   School.Insert (Key      => 789123,    -- Student B
                  New_Item => 65);

   -- Iterate using "in" syntax (for an iterator)
   for Cursor in School.Iterate loop
      School.Replace (Key => Maps.Key (Cursor), 
                      New_Item => Maps.Element (Cursor) + 1);
   end loop;

   -- Iterate using "of" syntax (for an iterable containter)
   for Grade of School loop
      Grade := Grade + 1;
   end loop;

   
end Test_Iterator;

For the AI for Ada 202x on Ada.Directories and Ada.Environment_Variables,
this is a work in progress, so it may end up looking very different in the end, or may even not make the cut for Ada 202x.

Essentially, the design choice discussed in the AI is whether to expose an Iterable Container type, or just an Iterator type.

Both choices could be made to have the same interface for the user, with the only difference being whether "in" or "of" appears in the loop.

If we expose an Iterable container though, that also gives the ability to use "in" syntax since an Iterable container is associated with an Iterator type, and that Iterator type could be used in the loop. However, in that case, as with other existing standard container types and as seen in my example above, using the "in" form would be a bit more awkward to use, compared to the "of" form, so I suspect most people would just use "of".

So the question really is, if we add Ada 2012 Iterator support to Ada.Directories and/or Ada.Environment_Variables, should the design be to 
expose just an Iterator type, or both an Iterator Type, and an Iterable container type?

My thought is that the latter might be better mostly because it would be more consistent with the other standard container types, but I could go either way.

A secondary question might be for anyone creating such abstractions of their own, are there cases where creating an Iterator type makes better sense than creating an Iterable container type?  The ACATS test involving the Prime number iterator could be an example of such an iterator type, but note I could have written that also as an Iterable Container type instead.

In other words, can general guidance be given about how to choose an approach, or does it not really matter, and the writer of such abstractions should choose which ever approach they fancy? 

Brad

> 
> If you create new iterator for some key-value pairs, which approach do you like?
> 
> -- 
> Yuta Tomino

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 16:30 ` Dmitry A. Kazakov
@ 2015-11-27 18:08   ` ytomino
  2015-11-27 20:50     ` Dmitry A. Kazakov
  2015-11-27 22:52     ` bj.mooremr
  0 siblings, 2 replies; 17+ messages in thread
From: ytomino @ 2015-11-27 18:08 UTC (permalink / raw)


On Saturday, November 28, 2015 at 1:30:23 AM UTC+9, Dmitry A. Kazakov wrote:
> On Fri, 27 Nov 2015 07:25:57 -0800 (PST), ytomino wrote:
> 
> > Hello, I'm reading AI12-0009-1 "Iterators for Directories and Environment_Variables".
> > http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0009-1.txt?rev=1.4
> > 
> > And there is interesting difference between the new iterator of Ada.Environment_Variables and the existing iterators.
> > (The boolean trick of these new iterators is also interesting, but set aside.)
> > 
> > A loop for Ada.Environment_Variables would be like below, according to this AI:
> > 
> > for E *of* Ada.Environment_Variables.All_Variables loop
> >    -- E is Iterator_Element (Name_Value_Pair_Type)
> >    Name (E) -- key
> >    Value (E) -- value
> > end loop;
> > 
> > On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:
> > 
> > for I *in* The_Map_Object.Iterate loop
> >    -- I is Cursor
> >    Key (E) -- key
> >    Element (E), Reference (E).Element.all -- value
> > end loop;
> > 
> > If you create new iterator for some key-value pairs, which approach do you like?
> 
> Rather this:
> 
> for Variable in All_Variables loop
>    Put_Line (Variable.Name & "=" & Variable.Value);
> end loop;

It sounds good.

However, the Cursor probably have to be tagged to implement it for dot-notation, and, I think it will be an double-dispatching error on First/Next because the iterator is also tagged.

I wish dot-notation for non-tagged type is allowed (with pragma?)


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 17:00 ` Pascal Obry
@ 2015-11-27 18:25   ` ytomino
  0 siblings, 0 replies; 17+ messages in thread
From: ytomino @ 2015-11-27 18:25 UTC (permalink / raw)


On Saturday, November 28, 2015 at 2:00:22 AM UTC+9, Pascal Obry wrote:
> Le vendredi 27 novembre 2015 à 07:25 -0800, ytomino a écrit :
> > If you create new iterator for some key-value pairs, which approach
> > do you like?
> 
> I'd like to have tuples in Ada and be able to say:
> 
>    for (Name, Value) of Environment_Variables.All_Variables loop
>       Put_Line (Name & " = " & Value);
>    end loop;
> 
> In many cases tuple would be handy, avoiding creating record in some
> cases just to be able to return two values from a function for example.

More good!
I want tuples, too.

Sorry, to be honest, I had not thought to extend the language, only felt awkward that the plural styles are mixed.
However it looks attractive.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 17:43 ` Brad Moore
@ 2015-11-27 19:38   ` ytomino
  2015-11-27 19:46     ` ytomino
  2015-11-27 23:11     ` Brad Moore
  0 siblings, 2 replies; 17+ messages in thread
From: ytomino @ 2015-11-27 19:38 UTC (permalink / raw)


Thank you, Brad. I'm glad your reply!

> I'm not sure what is being referred to here as a "boolean trick". Perhaps you are referring to the mention of "Rosen Trick", which as Randy points out, should probably be called "Rosen Technique". However that has nothing to do with "Boolean". The Rosen technique is a coding technique that allows one to treat a read only "in" parameter as a modifiable "in out" parameter.

I called the below point as "boolean trick".

    type Entry_Presence is new Boolean; -- the "cursor" type
    function Has_Element
      (EP : Entry_Presence) return Boolean is (Boolean (EP));

It's interesting for me because I had tried to implement the iterator for Ada.Environment_Variables.
Sorry a personal matter, and please excuse the difference from AI because I wrote this code with my image before the specific content has not been written into AI.

https://github.com/ytomino/drake/blob/master/source/environment/a-envvar.ads
https://github.com/ytomino/drake/blob/master/source/environment/machine-apple-darwin/s-naenva.ads

I made Cursor as pointer in the environment-block(envp), and used address-arithmetic to scan it.
So, "Cursor is new Boolean" is shocking for me.

Thanks to teach "Rosen Trick".
I has known this technique, but not known the name of the technique.

> > A loop for Ada.Environment_Variables would be like below, according to this AI:
> > 
> > for E *of* Ada.Environment_Variables.All_Variables loop
> >    -- E is Iterator_Element (Name_Value_Pair_Type)
> >    Name (E) -- key
> >    Value (E) -- value
> > end loop;
> > 
> > On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:
> > 
> > for I *in* The_Map_Object.Iterate loop
> >    -- I is Cursor
> >    Key (E) -- key
> >    Element (E), Reference (E).Element.all -- value
> > end loop;
> 
> All the existing containers are iterable containers, so they support
> both using "of" and "in" syntax for loops. Using "of" is generally preferable
> because cursors are implicit, and the code written by the user is therefore simpler. Using "in" syntax can also be used by obtaining an Iterator object, but this gives you a cursor instead of a container element, so you typically would need to write some extra calls to get to the container element from the cursor object.
> 
> 
> This code excerpt you had above would not compile, so it is probably confusing people.
> It think it would be better to perhaps show a full simple working example, such as incrementing each element of the container;
> Here I show both forms of loop using a Hashed_Map container. As you can see,
> the "of" format is simpler, and hopefully easier to read and understand.
> 
> with Ada.Containers.Hashed_Maps; use Ada;
> procedure Test_Iterator is
>    
>    type Student_Id is new Positive;
>    type Grade is new Natural range 0 .. 100;
>    function Hash (Student : Student_Id) return Containers.Hash_Type is
>      (Containers.Hash_Type (Student));
>    
>    package Maps is new Ada.Containers.Hashed_Maps 
>      (Key_Type        => Student_Id,
>       Element_Type    => Grade,
>       Hash            => Hash,
>       Equivalent_Keys => "=");
> 
>    School : Maps.Map;
>    
> begin
> 
>    School.Insert (Key      => 123456,    -- Student A
>                   New_Item => 90);
>    School.Insert (Key      => 789123,    -- Student B
>                   New_Item => 65);
> 
>    -- Iterate using "in" syntax (for an iterator)
>    for Cursor in School.Iterate loop
>       School.Replace (Key => Maps.Key (Cursor), 
>                       New_Item => Maps.Element (Cursor) + 1);
>    end loop;
> 
>    -- Iterate using "of" syntax (for an iterable containter)
>    for Grade of School loop
>       Grade := Grade + 1;
>    end loop;
> 
>    
> end Test_Iterator;

Thanks for writing the example.
However, I feel it's unfair because Hashed_Maps has Variable_Indexing.

   -- Iterate using "in" syntax (for an iterator)
   for Cursor in School.Iterate loop
      School (Cursor) := School (Cursor) + 1;
   end loop;

> For the AI for Ada 202x on Ada.Directories and Ada.Environment_Variables,
> this is a work in progress, so it may end up looking very different in the end, or may even not make the cut for Ada 202x.
> 
> Essentially, the design choice discussed in the AI is whether to expose an Iterable Container type, or just an Iterator type.

Sorry, I didn't have the intention to interrupt the discussion of AI.
I already has made some my iterators with self‐taught. So I want to know the preference of people.
I don't want to affect your work... Of course, I'm looking forward to the complete of this AI.
 
> Both choices could be made to have the same interface for the user, with the only difference being whether "in" or "of" appears in the loop.

Yes.
(And, Hashed_Maps/Ordered_Maps already use "in". So I felt "in" is suitable.)

> If we expose an Iterable container though, that also gives the ability to use "in" syntax since an Iterable container is associated with an Iterator type, and that Iterator type could be used in the loop. However, in that case, as with other existing standard container types and as seen in my example above, using the "in" form would be a bit more awkward to use, compared to the "of" form, so I suspect most people would just use "of".

Well...

> So the question really is, if we add Ada 2012 Iterator support to Ada.Directories and/or Ada.Environment_Variables, should the design be to 
> expose just an Iterator type, or both an Iterator Type, and an Iterable container type?
> 
> My thought is that the latter might be better mostly because it would be more consistent with the other standard container types, but I could go either way.

If I were to venture my opinion, the former is better to write a generic subprogram:

  generic
     type Cursor is private;
     with package Iterator_Interfaces is new Ada.Iterator_Interfaces (Cursor);
     with function Key (P : Cursor) return String;
     with function Element (P : Cursor) return String;
  procedure My_Logic (...);

This generic subprogram can be compatible with Hashed_Maps/Ordered_Maps and Environment_Variables.
Conversely, the latter is acceptable if Hashed_Maps/Ordered_Maps expose Key_Element_Pair_Type.

> A secondary question might be for anyone creating such abstractions of their own, are there cases where creating an Iterator type makes better sense than creating an Iterable container type?  The ACATS test involving the Prime number iterator could be an example of such an iterator type, but note I could have written that also as an Iterable Container type instead.
> 
> In other words, can general guidance be given about how to choose an approach, or does it not really matter, and the writer of such abstractions should choose which ever approach they fancy? 

I want to know it, too.
I sometime try to write the generic package like below:

  generic
     type Input_Cursor is private;
     with package Input_Iterator_Interfaces is new Ada.Iterator_Interfaces (Input_Cursor);
     Input_Iterator : Input_Iterator_Interfaces.Forward_Iterator'Class;
     type Element_Type (<>) is limited private;
     with function Element (Position : Input_Cursor) return Element_Type;
  package My_Filter is
     type Output_Cursor is private;
     package Output_Iterator_Interfaces is new Ada.Iterator_Interfaces (Output_Cursor);
     Output_Iterator : Output_Iterator_Interfaces.Forward_Iterator'Class := ...;
     ...

But, I can't get a sense of satisfaction.

Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 19:38   ` ytomino
@ 2015-11-27 19:46     ` ytomino
  2015-11-27 23:11     ` Brad Moore
  1 sibling, 0 replies; 17+ messages in thread
From: ytomino @ 2015-11-27 19:46 UTC (permalink / raw)


> > So the question really is, if we add Ada 2012 Iterator support to Ada.Directories and/or Ada.Environment_Variables, should the design be to 
> > expose just an Iterator type, or both an Iterator Type, and an Iterable container type?
> > 
> > My thought is that the latter might be better mostly because it would be more consistent with the other standard container types, but I could go either way.

Oh, I think the latter might be better for *Ada.Directories*, too, because its element (Directory_Entry_Type) is not the key-value pair.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 18:08   ` ytomino
@ 2015-11-27 20:50     ` Dmitry A. Kazakov
  2015-11-27 22:52     ` bj.mooremr
  1 sibling, 0 replies; 17+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-27 20:50 UTC (permalink / raw)


On Fri, 27 Nov 2015 10:08:23 -0800 (PST), ytomino wrote:

> On Saturday, November 28, 2015 at 1:30:23 AM UTC+9, Dmitry A. Kazakov wrote:
>> On Fri, 27 Nov 2015 07:25:57 -0800 (PST), ytomino wrote:
>> 
>>> Hello, I'm reading AI12-0009-1 "Iterators for Directories and Environment_Variables".
>>> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0009-1.txt?rev=1.4
>>> 
>>> And there is interesting difference between the new iterator of Ada.Environment_Variables and the existing iterators.
>>> (The boolean trick of these new iterators is also interesting, but set aside.)
>>> 
>>> A loop for Ada.Environment_Variables would be like below, according to this AI:
>>> 
>>> for E *of* Ada.Environment_Variables.All_Variables loop
>>>    -- E is Iterator_Element (Name_Value_Pair_Type)
>>>    Name (E) -- key
>>>    Value (E) -- value
>>> end loop;
>>> 
>>> On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:
>>> 
>>> for I *in* The_Map_Object.Iterate loop
>>>    -- I is Cursor
>>>    Key (E) -- key
>>>    Element (E), Reference (E).Element.all -- value
>>> end loop;
>>> 
>>> If you create new iterator for some key-value pairs, which approach do you like?
>> 
>> Rather this:
>> 
>> for Variable in All_Variables loop
>>    Put_Line (Variable.Name & "=" & Variable.Value);
>> end loop;
> 
> It sounds good.
> 
> However, the Cursor probably have to be tagged to implement it for
> dot-notation, and, I think it will be an double-dispatching error on
> First/Next because the iterator is also tagged.

Why should it be cursor? As Pascal said, Variable is a plain record type,
the element of the container (seen as a set).

And of course indices must work too:

   for Key in All_Variables.Keys loop
      Put_Line (Key & "=" & All_Variables (Key));
   end loop;

'Range instead of .Keys would be even better, but it is probably too much
to ask.

> I wish dot-notation for non-tagged type is allowed (with pragma?)

There is already mechanism for this:

   function Add (X, Y : T) return T;
   function "+" (X, Y : T) return T renames Add;

This is not any different to

   function Name (X : T) return String;
   function ".Name" (X : T) return String renames Name;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 18:08   ` ytomino
  2015-11-27 20:50     ` Dmitry A. Kazakov
@ 2015-11-27 22:52     ` bj.mooremr
  1 sibling, 0 replies; 17+ messages in thread
From: bj.mooremr @ 2015-11-27 22:52 UTC (permalink / raw)


On Friday, November 27, 2015 at 11:08:25 AM UTC-7, ytomino wrote:
> On Saturday, November 28, 2015 at 1:30:23 AM UTC+9, Dmitry A. Kazakov wrote:
> > Rather this:
> > 
> > for Variable in All_Variables loop
> >    Put_Line (Variable.Name & "=" & Variable.Value);
> > end loop;
> 
> It sounds good.
> 
> However, the Cursor probably have to be tagged to implement it for dot-notation, and, I think it will be an double-dispatching error on First/Next because the iterator is also tagged.
> 
> I wish dot-notation for non-tagged type is allowed (with pragma?)

My initial implementation of this was as an Iterator, rather than an Iterable container, and in my implementation, I got things to work this way without the Cursor being a tagged type.

My "proof of concept" implementation was for Ada.Directories, but the same approach would also work for Ada.Environment_Variables.

For Ada.Directories, I declared the Cursor type as;

type Cursor
  (Directory_Entry : not null access constant Directory_Entry_Type) is private
   with  Implicit_Dereference => Directory_Entry;

The Implicit_Dereference aspect was added to Ada 2012.

For Ada.Environment_Variables, I would have declared something like;

type Cursor
  (Name_Value_Pair : not null access constant Name_Value_Pair_Type) is private
   with  Implicit_Dereference => Name_Value_Pair;

And

   function Has_Element (Name_Value_Pair : Cursor) return Boolean;

   package Environment_Variable_Iterator_Interfaces is new
    Ada.Iterator_Interfaces
     (Cursor      => Cursor,
      Has_Element => Has_Element);

   function All_Variables
     return Environment_Variable_Iterator_Interfaces.Forward_Iterator'Class;


Then one would be able to write;

for Variable in All_Variables loop 
   Put_Line (Variable.Name & "=" & Variable.Value); 
end loop; 

Exactly as Dmitry had requested...

Brad


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 19:38   ` ytomino
  2015-11-27 19:46     ` ytomino
@ 2015-11-27 23:11     ` Brad Moore
  2015-11-28  8:58       ` Simon Wright
  2015-11-29 17:55       ` ytomino
  1 sibling, 2 replies; 17+ messages in thread
From: Brad Moore @ 2015-11-27 23:11 UTC (permalink / raw)


On Friday, November 27, 2015 at 12:38:27 PM UTC-7, ytomino wrote:
> Thank you, Brad. I'm glad your reply!
> 
> > I'm not sure what is being referred to here as a "boolean trick". Perhaps you are referring to the mention of "Rosen Trick", which as Randy points out, should probably be called "Rosen Technique". However that has nothing to do with "Boolean". The Rosen technique is a coding technique that allows one to treat a read only "in" parameter as a modifiable "in out" parameter.
> 
> I called the below point as "boolean trick".
> 
>     type Entry_Presence is new Boolean; -- the "cursor" type
>     function Has_Element
>       (EP : Entry_Presence) return Boolean is (Boolean (EP));
> 

OK, I see what you mean now.
If we were to go forward with this proposal, I think the type should probably be called Cursor instead of Entry_Presence, (to be consistent with other Container types), and it should be a private type. The fact that its just a boolean type is an implementation detail, and of no concern to the user's of the abstraction.

> It's interesting for me because I had tried to implement the iterator for Ada.Environment_Variables.
> Sorry a personal matter, and please excuse the difference from AI because I wrote this code with my image before the specific content has not been written into AI.
> 
> https://github.com/ytomino/drake/blob/master/source/environment/a-envvar.ads
> https://github.com/ytomino/drake/blob/master/source/environment/machine-apple-darwin/s-naenva.ads
> 
> I made Cursor as pointer in the environment-block(envp), and used address-arithmetic to scan it.
> So, "Cursor is new Boolean" is shocking for me.
> 
> Thanks to teach "Rosen Trick".
> I has known this technique, but not known the name of the technique.
> 
> > > A loop for Ada.Environment_Variables would be like below, according to this AI:
> > > 
> > > for E *of* Ada.Environment_Variables.All_Variables loop
> > >    -- E is Iterator_Element (Name_Value_Pair_Type)
> > >    Name (E) -- key
> > >    Value (E) -- value
> > > end loop;
> > > 
> > > On the other hand, as we already know, a loop for Ada.Containers.Hashed_Maps/Ordered_Maps:
> > > 
> > > for I *in* The_Map_Object.Iterate loop
> > >    -- I is Cursor
> > >    Key (E) -- key
> > >    Element (E), Reference (E).Element.all -- value
> > > end loop;
> > 
> > All the existing containers are iterable containers, so they support
> > both using "of" and "in" syntax for loops. Using "of" is generally preferable
> > because cursors are implicit, and the code written by the user is therefore simpler. Using "in" syntax can also be used by obtaining an Iterator object, but this gives you a cursor instead of a container element, so you typically would need to write some extra calls to get to the container element from the cursor object.
> > 
> > 
> > This code excerpt you had above would not compile, so it is probably confusing people.
> > It think it would be better to perhaps show a full simple working example, such as incrementing each element of the container;
> > Here I show both forms of loop using a Hashed_Map container. As you can see,
> > the "of" format is simpler, and hopefully easier to read and understand.
> > 
> > with Ada.Containers.Hashed_Maps; use Ada;
> > procedure Test_Iterator is
> >    
> >    type Student_Id is new Positive;
> >    type Grade is new Natural range 0 .. 100;
> >    function Hash (Student : Student_Id) return Containers.Hash_Type is
> >      (Containers.Hash_Type (Student));
> >    
> >    package Maps is new Ada.Containers.Hashed_Maps 
> >      (Key_Type        => Student_Id,
> >       Element_Type    => Grade,
> >       Hash            => Hash,
> >       Equivalent_Keys => "=");
> > 
> >    School : Maps.Map;
> >    
> > begin
> > 
> >    School.Insert (Key      => 123456,    -- Student A
> >                   New_Item => 90);
> >    School.Insert (Key      => 789123,    -- Student B
> >                   New_Item => 65);
> > 
> >    -- Iterate using "in" syntax (for an iterator)
> >    for Cursor in School.Iterate loop
> >       School.Replace (Key => Maps.Key (Cursor), 
> >                       New_Item => Maps.Element (Cursor) + 1);
> >    end loop;
> > 
> >    -- Iterate using "of" syntax (for an iterable containter)
> >    for Grade of School loop
> >       Grade := Grade + 1;
> >    end loop;
> > 
> >    
> > end Test_Iterator;
> 
> Thanks for writing the example.
> However, I feel it's unfair because Hashed_Maps has Variable_Indexing.
> 
>    -- Iterate using "in" syntax (for an iterator)
>    for Cursor in School.Iterate loop
>       School (Cursor) := School (Cursor) + 1;
>    end loop;

Good point..., a better way to write this using an Iterator.
> 
> > For the AI for Ada 202x on Ada.Directories and Ada.Environment_Variables,
> > this is a work in progress, so it may end up looking very different in the end, or may even not make the cut for Ada 202x.
> > 
> > Essentially, the design choice discussed in the AI is whether to expose an Iterable Container type, or just an Iterator type.
> 
> Sorry, I didn't have the intention to interrupt the discussion of AI.
> I already has made some my iterators with self‐taught. So I want to know the preference of people.
> I don't want to affect your work... Of course, I'm looking forward to the complete of this AI.

Getting feedback on the preferences of people could influence the direction that the AI takes, and ultimately we want to make the best decisions, so its good to hear the feedback.

>  
> > Both choices could be made to have the same interface for the user, with the only difference being whether "in" or "of" appears in the loop.
> 
> Yes.
> (And, Hashed_Maps/Ordered_Maps already use "in". So I felt "in" is suitable.)

Not sure what you mean here. Hashed_Maps/Ordered_Maps also already uses "of", 
you can use either today, so how is one more suitable than the other?
I think the "of" form involves less clutter that that user has to write, so I would generally try to use that, unless you really need a Cursor somewhere in the loop.

> 
> > If we expose an Iterable container though, that also gives the ability to use "in" syntax since an Iterable container is associated with an Iterator type, and that Iterator type could be used in the loop. However, in that case, as with other existing standard container types and as seen in my example above, using the "in" form would be a bit more awkward to use, compared to the "of" form, so I suspect most people would just use "of".
> 
> Well...
> 
> > So the question really is, if we add Ada 2012 Iterator support to Ada.Directories and/or Ada.Environment_Variables, should the design be to 
> > expose just an Iterator type, or both an Iterator Type, and an Iterable container type?
> > 
> > My thought is that the latter might be better mostly because it would be more consistent with the other standard container types, but I could go either way.
> 
> If I were to venture my opinion, the former is better to write a generic subprogram:
> 
>   generic
>      type Cursor is private;
>      with package Iterator_Interfaces is new Ada.Iterator_Interfaces (Cursor);
>      with function Key (P : Cursor) return String;
>      with function Element (P : Cursor) return String;
>   procedure My_Logic (...);
> 
> This generic subprogram can be compatible with Hashed_Maps/Ordered_Maps and Environment_Variables.
> Conversely, the latter is acceptable if Hashed_Maps/Ordered_Maps expose Key_Element_Pair_Type.
> 
> > A secondary question might be for anyone creating such abstractions of their own, are there cases where creating an Iterator type makes better sense than creating an Iterable container type?  The ACATS test involving the Prime number iterator could be an example of such an iterator type, but note I could have written that also as an Iterable Container type instead.
> > 
> > In other words, can general guidance be given about how to choose an approach, or does it not really matter, and the writer of such abstractions should choose which ever approach they fancy? 
> 
> I want to know it, too.
> I sometime try to write the generic package like below:

My sense is that if you dont need a container as part of the abstraction, then perhaps it's better to just provide an Iterator type. All the existing containers already were containers, so for those it made sense to make them Iterable containers.  Ada.Directories and Ada.Environment_Variables do not currently have Containers associated with them, so perhaps an argument can be made that they should be Iterators, rather than concoct a Container type so that Iterable container syntax can be used.

Brad

> 
>   generic
>      type Input_Cursor is private;
>      with package Input_Iterator_Interfaces is new Ada.Iterator_Interfaces (Input_Cursor);
>      Input_Iterator : Input_Iterator_Interfaces.Forward_Iterator'Class;
>      type Element_Type (<>) is limited private;
>      with function Element (Position : Input_Cursor) return Element_Type;
>   package My_Filter is
>      type Output_Cursor is private;
>      package Output_Iterator_Interfaces is new Ada.Iterator_Interfaces (Output_Cursor);
>      Output_Iterator : Output_Iterator_Interfaces.Forward_Iterator'Class := ...;
>      ...
> 
> But, I can't get a sense of satisfaction.
> 
> Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 23:11     ` Brad Moore
@ 2015-11-28  8:58       ` Simon Wright
  2015-11-28 19:54         ` Brad Moore
  2015-11-29 16:17         ` Simon Wright
  2015-11-29 17:55       ` ytomino
  1 sibling, 2 replies; 17+ messages in thread
From: Simon Wright @ 2015-11-28  8:58 UTC (permalink / raw)


Brad Moore <bmoore.ada@gmail.com> writes:

> My sense is that if you dont need a container as part of the
> abstraction, then perhaps it's better to just provide an Iterator
> type. All the existing containers already were containers, so for
> those it made sense to make them Iterable containers.  Ada.Directories
> and Ada.Environment_Variables do not currently have Containers
> associated with them, so perhaps an argument can be made that they
> should be Iterators, rather than concoct a Container type so that
> Iterable container syntax can be used.

I don't see it as concocting a Container type; it's an Iterable
type. Containers happen to be Iterable.

It's unfortunate (but understandable!) that 4.1.6 and 5.5.1, .2 use
container-related language.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-28  8:58       ` Simon Wright
@ 2015-11-28 19:54         ` Brad Moore
  2015-11-28 23:34           ` Simon Wright
  2015-11-29 16:17         ` Simon Wright
  1 sibling, 1 reply; 17+ messages in thread
From: Brad Moore @ 2015-11-28 19:54 UTC (permalink / raw)


On Saturday, November 28, 2015 at 1:58:47 AM UTC-7, Simon Wright wrote:
> Brad Moore <bmoore.ada@gmail.com> writes:
> 
> > My sense is that if you dont need a container as part of the
> > abstraction, then perhaps it's better to just provide an Iterator
> > type. All the existing containers already were containers, so for
> > those it made sense to make them Iterable containers.  Ada.Directories
> > and Ada.Environment_Variables do not currently have Containers
> > associated with them, so perhaps an argument can be made that they
> > should be Iterators, rather than concoct a Container type so that
> > Iterable container syntax can be used.
> 
> I don't see it as concocting a Container type; it's an Iterable
> type. Containers happen to be Iterable.
> 
> It's unfortunate (but understandable!) that 4.1.6 and 5.5.1, .2 use
> container-related language.

I suspect my comment was misunderstood here.

My comment was about having to create an extra declaration in the packages Ada.Directories and Ada.Environment_Variables to define a container type.
For Directories, I had a Directory_Listing type, and for Environment_Variables, the container type could be called Environment. If we went with the Iterator approach instead of the container approach, this wouldn't be needed. In both cases, an Iterator type would be needed. Having to create a container type isn't unreasonable, because one can think of a Directory_Listing as being a container of file names, or an Environment as being a container of Environment variables. However, these extra declarations could be viewed as extra "clutter" to add to the standard packages. If we went with the Iterator approach, there would be less clutter, yet achieve basically the same objective.

Brad

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-28 19:54         ` Brad Moore
@ 2015-11-28 23:34           ` Simon Wright
  2015-11-29 21:17             ` Bob Duff
  0 siblings, 1 reply; 17+ messages in thread
From: Simon Wright @ 2015-11-28 23:34 UTC (permalink / raw)


Brad Moore <bmoore.ada@gmail.com> writes:

> My comment was about having to create an extra declaration in the
> packages Ada.Directories and Ada.Environment_Variables to define a
> container type.

Yes, I got that. I'm just saying that we call this extra type a
container type because it was invented in the context of Ada.Containers;
ARM 5.5.2(3) says

   "For the second form of iterator_specification [that is, the form
   that uses 'of'], the expected type for the iterable_name is any array
   or iterable container type. If the iterable_name denotes an array
   object, the iterator_specification is called an array component
   iterator; otherwise it is called a container element iterator."

but we are now discovering that we don't just want to use it for
containers, rather for anything we might want to iterate over, such as
directory entries, prime numbers, ...

I suspect we could delete the word 'container' throughout the existing
5.5.2 (and 4.1.6) without losing anything significant. There'd have to
be a hint about the point of it all, of course!


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-28  8:58       ` Simon Wright
  2015-11-28 19:54         ` Brad Moore
@ 2015-11-29 16:17         ` Simon Wright
  1 sibling, 0 replies; 17+ messages in thread
From: Simon Wright @ 2015-11-29 16:17 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> Brad Moore <bmoore.ada@gmail.com> writes:
>
>> My sense is that if you dont need a container as part of the
>> abstraction, then perhaps it's better to just provide an Iterator
>> type. All the existing containers already were containers, so for
>> those it made sense to make them Iterable containers.  Ada.Directories
>> and Ada.Environment_Variables do not currently have Containers
>> associated with them, so perhaps an argument can be made that they
>> should be Iterators, rather than concoct a Container type so that
>> Iterable container syntax can be used.
>
> I don't see it as concocting a Container type; it's an Iterable
> type. Containers happen to be Iterable.
>
> It's unfortunate (but understandable!) that 4.1.6 and 5.5.1, .2 use
> container-related language.

I think there's a lot to be said for consistency. If users see that they
can iterate over directories, won't they be surprised and disappointed
to find that they have to use the clumsier 'in' form?

The implementer might be happier with a Container-ish object to support
the 'of' form, but surely the users won't care? It's all a black mystery
to them anyway (and quite right, too).

I had fun with my Date_Iteration example to support the 'of' form
without an extra type; the extras needed are the aspects on Date_Set and
the function Element.

   type Date_Set is new Iterator_Interfaces.Forward_Iterator with private
   with
     Constant_Indexing => Element,
     Default_Iterator => Iterate,
     Iterator_Element => Ada.Calendar.Time;

   function Element (Set : Date_Set; C : Cursor) return Ada.Calendar.Time;

(Date_Set is acceptable to GNAT but not to emacs ada-mode, which gets
thoroughly confused)

I must say I got quite confused about what the second parameter of
Element should be until I read ARM5.5.2(13).


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-27 23:11     ` Brad Moore
  2015-11-28  8:58       ` Simon Wright
@ 2015-11-29 17:55       ` ytomino
  1 sibling, 0 replies; 17+ messages in thread
From: ytomino @ 2015-11-29 17:55 UTC (permalink / raw)


> > > Both choices could be made to have the same interface for the user, with the only difference being whether "in" or "of" appears in the loop.
> > 
> > Yes.
> > (And, Hashed_Maps/Ordered_Maps already use "in". So I felt "in" is suitable.)
> 
> Not sure what you mean here. Hashed_Maps/Ordered_Maps also already uses "of", 
> you can use either today, so how is one more suitable than the other?
> I think the "of" form involves less clutter that that user has to write, so I would generally try to use that, unless you really need a Cursor somewhere in the loop.

Well, Hashed_Maps/Ordered_Maps don't have a pair type similar to Name_Value_Pair_Type.

  for E of The_Map_Object loop

This E is Element_Type. We can not get the key of it with "of".
In this case, the indexing function accepting Cursor is Element or Reference, and it returns Element_Type.
On the other hand, in AI:

  for Pair of Ada.Environment_Variables.All_Variables loop

This Pair is Name_Value_Pair_Type.
The indexing function accepting Cursor is Current_Variable, and it returns not String but Name_Value_Pair_Type.
I think this difference prevents us from writing a generic subprogram for common use.

Sorry that the explanation of mine was lacking.

By the way, the indexing function of std::map of C++ STL returns a pair.
I have been pointed out it by one C++ user.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Two approaches of iterators for the key-value pairs
  2015-11-28 23:34           ` Simon Wright
@ 2015-11-29 21:17             ` Bob Duff
  0 siblings, 0 replies; 17+ messages in thread
From: Bob Duff @ 2015-11-29 21:17 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> but we are now discovering that we don't just want to use it for
> containers, rather for anything we might want to iterate over, such as
> directory entries, prime numbers, ...

"anything we might want to iterate over" = "container".
At least, that's one way to look at it.  E.g. the set of all prime
numbers is a set, and a set is a container.  A "virtual container"
I suppose, because you're not going to store all the prime numbers
in memory at once.

- Bob

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2015-11-29 21:17 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-27 15:25 Two approaches of iterators for the key-value pairs ytomino
2015-11-27 16:30 ` Dmitry A. Kazakov
2015-11-27 18:08   ` ytomino
2015-11-27 20:50     ` Dmitry A. Kazakov
2015-11-27 22:52     ` bj.mooremr
2015-11-27 17:00 ` Pascal Obry
2015-11-27 18:25   ` ytomino
2015-11-27 17:43 ` Brad Moore
2015-11-27 19:38   ` ytomino
2015-11-27 19:46     ` ytomino
2015-11-27 23:11     ` Brad Moore
2015-11-28  8:58       ` Simon Wright
2015-11-28 19:54         ` Brad Moore
2015-11-28 23:34           ` Simon Wright
2015-11-29 21:17             ` Bob Duff
2015-11-29 16:17         ` Simon Wright
2015-11-29 17:55       ` ytomino

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox