comp.lang.ada
 help / color / mirror / Atom feed
* A few questions
@ 2015-02-07 17:43 Laurent
  2015-02-07 22:15 ` Brad Moore
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent @ 2015-02-07 17:43 UTC (permalink / raw)


Hi

1) Trying to implement a search function in my linked list. Doesn't compile because the return type :List_Ptr is not visible in the ads file?

spec:

   function Search (L : in List; Element : in Element_Type) return List_Ptr;
   -- Pre: L is defined; L may be empty; Element is a scalar type
   -- Post: returns access to found node

body

   function Search (L : in List; Element : in Element_Type) return List_Ptr is
      Temp : List_Ptr;
      Current : List;

   begin
      Current := L.Head;
      while Current.Head /= null loop
         if Equals(Current.Head.Element, Element) then
            Temp:= Current.Head;
            return Temp;
         end if;
         Current.Head := Current.Head.Next;
      end loop;
   end Search;

The List_Ptr is defined as:

private

   ----------
   -- List --
   ----------

   type List_Node;
   type List_Ptr is access List_Node;
   type List_Node is record
      Element : Element_Type;
      Next    : List_Ptr;
      Previous:List_Ptr;
   end record;

   type List is record
      Head : List_Ptr;
      Tail : List_Ptr;
   end record;

I have put the search function in a child package.

2) Tried the same thing but this time using an iterator but fails with 

        65:20 (Ada 2005) cannot copy object of a limited type (RM-2005 6.5(5.5/2))
        65:20 return by reference not permitted in Ada 2005
on 

return It;

spec

   function Search (L : access List; Element : Element_Type) return Iterator;
   -- Pre: L is defined; L may be empty; Element is a scalar type
   -- Post: returns access to found node

body

   function Search (L : access List; Element : Element_Type) return  Iterator is
      It : Iterator (L);

   begin
      Start (It);
      while not Done (It) loop
         if Equals (It.This.Element, Element) then
            return It;
         end if;
         Next(It);
      end loop;
   end Search;

The Iterator is defined as:

private

   --------------
   -- Iterator --
   --------------

   type Iterator (L : access List) is limited
      record
         This :  List_Ptr;
      end record;

I have tried to understand RM-2005 6.5(5.5/2) but don't know what 

"If the result subtype of the function is defined by a subtype_mark, the return_subtype_indication shall be a subtype_indication. The type of the subtype_indication shall be the result type of the function"

is supposed to look like. 

If someone could enlighten me on both problems.

https://github.com/Chutulu/Chapter-15.git

3) How can I take a look at the assembler code of both versions? Just curious to see if there is actually a difference between both versions. I have no idea of assembler but that doesn't keep me from trying.

Thanks

Laurent

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

* Re: A few questions
  2015-02-07 17:43 Laurent
@ 2015-02-07 22:15 ` Brad Moore
  2015-02-08 22:37   ` Laurent
  0 siblings, 1 reply; 73+ messages in thread
From: Brad Moore @ 2015-02-07 22:15 UTC (permalink / raw)


On 15-02-07 10:43 AM, Laurent wrote:
> Hi
>
> 1) Trying to implement a search function in my linked list. Doesn't compile because the return type :List_Ptr is not visible in the ads file?

The compiler is telling you that List_Ptr can't be used in the visible 
part of a package (the part before the word private), if it hasn't been 
defined yet. (ie the definition is not seen until further down in the 
file inside the private part of the package.

Your abstraction in this case involves the use of something called 
List_Ptr, and users of your abstraction should be able to use your 
package without having to look inside the private part of the package.

One way to get around this, is to define List_Ptr as a private type in 
the visible part of the package.

  eg.

    type List_Ptr is private;


The full definition of List_Ptr still occurs in the private part of the 
package as you have it, but the private type declaration in the visible 
part of the package exposes the name of the type in the visible part so 
that it can be used there.



>
> spec:
>
>     function Search (L : in List; Element : in Element_Type) return List_Ptr;
>     -- Pre: L is defined; L may be empty; Element is a scalar type
>     -- Post: returns access to found node
>
> body
>
>     function Search (L : in List; Element : in Element_Type) return List_Ptr is
>        Temp : List_Ptr;
>        Current : List;
>
>     begin
>        Current := L.Head;
>        while Current.Head /= null loop
>           if Equals(Current.Head.Element, Element) then
>              Temp:= Current.Head;
>              return Temp;
>           end if;
>           Current.Head := Current.Head.Next;
>        end loop;
>     end Search;
>
> The List_Ptr is defined as:
>
> private
>
>     ----------
>     -- List --
>     ----------
>
>     type List_Node;
>     type List_Ptr is access List_Node;
>     type List_Node is record
>        Element : Element_Type;
>        Next    : List_Ptr;
>        Previous:List_Ptr;
>     end record;
>
>     type List is record
>        Head : List_Ptr;
>        Tail : List_Ptr;
>     end record;
>
> I have put the search function in a child package.

A child package isn't necessary for this purpose.


>
> 2) Tried the same thing but this time using an iterator but fails with
>
>          65:20 (Ada 2005) cannot copy object of a limited type (RM-2005 6.5(5.5/2))

The compiler is complaining because you have declared It as a local 
object inside your Search function, and you are trying to return that 
object as the result of a function call, which involves copying the 
object to wherever the result of the function call is to be placed.

Limited types are not copyable. Is there a reason why you declared your 
Iterator type to be a limited type, (ie. with the keyword limited)?

If you do want it to be a limited type you can return an object of that 
type in a function call in certain contexts. You have to use an extended 
return statement though.

See RM 6.5 (2.1/2) and 6.5 (28/2) for an example.

That would allow the return object to be built in place where the 
function result is to be placed, and thus avoids copying any object.

Such a function that returns a limited type is usable only to initialize 
a declaration of a limited type. You cannot use it to change the value 
of the limited type once it has been initialized. This may be too 
restrictive for your needs, so perhaps you should consider not making 
this type limited.


>          65:20 return by reference not permitted in Ada 2005
> on
>
> return It;
>
> spec
>
>     function Search (L : access List; Element : Element_Type) return Iterator;
>     -- Pre: L is defined; L may be empty; Element is a scalar type
>     -- Post: returns access to found node
>
> body
>
>     function Search (L : access List; Element : Element_Type) return  Iterator is
>        It : Iterator (L);
>
>     begin
>        Start (It);
>        while not Done (It) loop
>           if Equals (It.This.Element, Element) then
>              return It;
>           end if;
>           Next(It);
>        end loop;
>     end Search;
>
> The Iterator is defined as:
>
> private
>
>     --------------
>     -- Iterator --
>     --------------
>
>     type Iterator (L : access List) is limited
>        record
>           This :  List_Ptr;
>        end record;
>
> I have tried to understand RM-2005 6.5(5.5/2) but don't know what
>
> "If the result subtype of the function is defined by a subtype_mark, the return_subtype_indication shall be a subtype_indication. The type of the subtype_indication shall be the result type of the function"
>
> is supposed to look like.

I believe you are referring to 6.5(5.2/2) not 6.5(5.5/2)

This applies to an extended return statement. In your example, you are 
using a simple return statement, if you want to use an extended return, 
you need to use that syntax.

The result subtype of your function is defined by a subtype_mark 
(Iterator), so 6.5(5.2/2) is saying that the declaration of the result 
object in the extended return must also be an Iterator, but you may 
optionally add further constraints on the declaration. In your case, you 
need to add a discriminant constraint for the access to the List 
discriminant, since you want the result to have that value.

eg.

    return Result (L) : Iterator do
      null;
    end return;

Brad

>
> If someone could enlighten me on both problems.
>
> https://github.com/Chutulu/Chapter-15.git
>
> 3) How can I take a look at the assembler code of both versions? Just curious to see if there is actually a difference between both versions. I have no idea of assembler but that doesn't keep me from trying.
>
> Thanks
>
> Laurent
>


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

* Re: A few questions
  2015-02-07 22:15 ` Brad Moore
@ 2015-02-08 22:37   ` Laurent
  2015-02-09 13:56     ` Brad Moore
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent @ 2015-02-08 22:37 UTC (permalink / raw)


On Saturday, February 7, 2015 at 11:14:46 PM UTC+1, Brad Moore wrote:

> One way to get around this, is to define List_Ptr as a private type in 
> the visible part of the package.
> 
>   eg.
> 
>     type List_Ptr is private;

Ok that makes sense. As the package is based on an example from my Ada95 book, only the List type is visible. But the author had probably a good reason to design it like this? 

> A child package isn't necessary for this purpose.
Has to do with the fact that the "Insert_In_Order" procedure requires overriding of >= and <, if Element_Type is a record... So a child package makes things easier if I don't need this procedure. Same is true for the search function which requires an overridden =. So I put it in the child package. 

> >          65:20 (Ada 2005) cannot copy object of a limited type (RM-2005 6.5(5.5/2))

Oops wrong paragraphe, indeed meant 6.5(5.5/2) copied the wrong one

> The compiler is complaining because you have declared It as a local 
> object inside your Search function, and you are trying to return that 
> object as the result of a function call, which involves copying the 
> object to wherever the result of the function call is to be placed.
> 
> Limited types are not copyable. Is there a reason why you declared your 
> Iterator type to be a limited type, (ie. with the keyword limited)?

No idea why it is limited. Took the example of the active iterator from John Barnes Ada 2005 book. 

But again I suppose that the author had a good reason to make the Iterator limited?

> If you do want it to be a limited type you can return an object of that 
> type in a function call in certain contexts. You have to use an extended 
> return statement though.
> 
> See RM 6.5 (2.1/2) and 6.5 (28/2) for an example.
> 
> That would allow the return object to be built in place where the 
> function result is to be placed, and thus avoids copying any object.
> 
> Such a function that returns a limited type is usable only to initialize 
> a declaration of a limited type. You cannot use it to change the value 
> of the limited type once it has been initialized. This may be too 
> restrictive for your needs, so perhaps you should consider not making 
> this type limited.
> 

Hm yes was peaking inside the double_linked_list provided with gnat, hoping to find something
similar to my construction. I think I saw an example of what you mean. To complicate for the
moment. Probably much easier to remove the limited.

> This applies to an extended return statement. In your example, you are 
> using a simple return statement, if you want to use an extended return, 
> you need to use that syntax.
> 
> The result subtype of your function is defined by a subtype_mark 
> (Iterator), so 6.5(5.2/2) is saying that the declaration of the result 
> object in the extended return must also be an Iterator, but you may 
> optionally add further constraints on the declaration. In your case, you 
> need to add a discriminant constraint for the access to the List 
> discriminant, since you want the result to have that value.
> 
> eg.
> 
>     return Result (L) : Iterator do
>       null;
>     end return;

Result(L): Iterator -- compiler not happy. 
Result: Iterator(L) do -- works. 

So I modified Iterator to private only and adapted the search function:

   function Search (L : access List; Element : Element_Type) return  Iterator is
      It : Iterator (L);

   begin
      Start (It);
      while not Done (It) loop
         if Equals (It.This.Element, Element) then
            return Result : Iterator (L) do
               Result := It;
            end return;
         end if;
         Next (It);
      end loop;
      return Result : Iterator (L) do
         It.This:= null;
         Result := It; 
      end return;
   end Search;

Is that correct or just garbage. At least it compiles but that doesn't mean anything.
Compiler is quite picky: 

 It.This:= null;
 Result := It;

That compiles but Result := null; won't, expecting Iterator getting access?

Thanks for your patience

Laurent

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

* Re: A few questions
  2015-02-08 22:37   ` Laurent
@ 2015-02-09 13:56     ` Brad Moore
  2015-02-09 18:36       ` Laurent
  0 siblings, 1 reply; 73+ messages in thread
From: Brad Moore @ 2015-02-09 13:56 UTC (permalink / raw)


On 15-02-08 03:37 PM, Laurent wrote:
> On Saturday, February 7, 2015 at 11:14:46 PM UTC+1, Brad Moore wrote:
>
>> One way to get around this, is to define List_Ptr as a private type in
>> the visible part of the package.
>>
>>    eg.
>>
>>      type List_Ptr is private;
>
> Ok that makes sense. As the package is based on an example from my Ada95 book, only the List type is visible. But the author had probably a good reason to design it like this?

I believe you are referring to the example which appears on page 524 in 
John's 2005 book.

I think it is generally desirable to not expose access types in the
visible part of a package, and generally this should be possible.

For a list package, exposing an Iterator or Cursor type is a cleaner
approach, since you can hide any access values it may contain in the
private part of the package. Users of the package have a nice Iterator
abstraction without having to deal with access types and access values.

In John's example, his Iterator type has an anonymous access 
discriminant pointing to a List object. This allows the user to declare 
Iterator objects and tie them to a List object. The discriminant is not 
mutable so once the Iterator is declared, it always points to that 
particular list object.

I would probably go one step further and try to hide the discriminant 
and provide a function that accepts a List object as a parameter, and 
returns an Iterator object. This would be used to initialize a 
declaration of an iterator object.

The Iterator could still have an anonymous access discriminant for a 
list in the private part, (or alternatively as a regular component of 
the Iterator object).

If you want the Iterator to keep the discriminant, you can still hide it
somewhat in the public part by declaring with unknown discriminants.

i.e.

    type Iterator (<>) is limited private;


This would also enforce that the only way to obtain an iterator would be 
through the function call.

>
>>>           65:20 (Ada 2005) cannot copy object of a limited type (RM-2005 6.5(5.5/2))
>
> Oops wrong paragraphe, indeed meant 6.5(5.5/2) copied the wrong one
>
>> The compiler is complaining because you have declared It as a local
>> object inside your Search function, and you are trying to return that
>> object as the result of a function call, which involves copying the
>> object to wherever the result of the function call is to be placed.
>>
>> Limited types are not copyable. Is there a reason why you declared your
>> Iterator type to be a limited type, (ie. with the keyword limited)?
>
> No idea why it is limited. Took the example of the active iterator from John Barnes Ada 2005 book.
>
> But again I suppose that the author had a good reason to make the Iterator limited?

He probably wanted to enforce that users of the package are not allowed 
to copy Iterator objects, or reinitialize them. A good design 
restriction as it might prevent users from using the abstraction is some 
ways that were not intended by the designer of the package.

It's generally better to use limited types if you can live with the 
restrictions. In this case, the designer doesn't want the user to copy 
iterator objects, which seems like a reasonable restriction.

If you want to avoid returning limited types from function calls, (and 
having to use extended return statements), you might want to consider 
passing the Iterator as an in out parameter to the call, as in John's 
example for his "Next" procedure. This avoids copying objects of limited 
type.

>
> Hm yes was peaking inside the double_linked_list provided with gnat, hoping to find something
> similar to my construction. I think I saw an example of what you mean. To complicate for the
> moment. Probably much easier to remove the limited.

I'd suggest you keep the limited, but try the above


>> eg.
>>
>>      return Result (L) : Iterator do
>>        null;
>>      end return;
>
> Result(L): Iterator -- compiler not happy.
> Result: Iterator(L) do -- works.

Yes I realized that after I hit send. I figured you'd figure it out 
though, as you did.

>
> So I modified Iterator to private only and adapted the search function:
>
>     function Search (L : access List; Element : Element_Type) return  Iterator is
>        It : Iterator (L);
>
>     begin
>        Start (It);
>        while not Done (It) loop
>           if Equals (It.This.Element, Element) then
>              return Result : Iterator (L) do
>                 Result := It;
>              end return;

Result.This := It.This;  Instead of Result := It?
If Iterator is no longer limited, then you could just use a simple return,
i.e.
      return It;

But keeping this as limited, I think it would be better as an in out 
parameter. Then the Search can be used on an Iterator object that 
already is declared. Returning as a function result means Search can 
only be used to initialize an Iterator object.


>           end if;
>           Next (It);
>        end loop;
>        return Result : Iterator (L) do
>           It.This:= null;
>           Result := It;
>        end return;
>     end Search;
>
> Is that correct or just garbage. At least it compiles but that doesn't mean anything.

At first glance this looks OK, but I think you should consider rewriting 
as an in out parameter. I think you'll like the result better.


> Compiler is quite picky:

That's what's great about Ada. :-)

>
>   It.This:= null;
>   Result := It;
>
> That compiles but Result := null; won't, expecting Iterator getting access?

Result is a record type, not an access type, so setting it to null 
shouldn't be possible. Did you want
   Result.This := null;

instead?

Brad

>
> Thanks for your patience
>
> Laurent
>

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

* Re: A few questions
  2015-02-09 13:56     ` Brad Moore
@ 2015-02-09 18:36       ` Laurent
  0 siblings, 0 replies; 73+ messages in thread
From: Laurent @ 2015-02-09 18:36 UTC (permalink / raw)



> I believe you are referring to the example which appears on page 524 in 
> John's 2005 book.
> 
Yes

>    Result.This := null;
Yes found it out after a few hours of sleep. Happens quite often to me that I find the solution when
I don't try to force it. 

Thanks for the detailed explanations. A lot of information to digest.

Laurent 

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

* A few questions
@ 2015-10-31 20:29 Laurent
  2015-10-31 20:49 ` Dmitry A. Kazakov
                   ` (6 more replies)
  0 siblings, 7 replies; 73+ messages in thread
From: Laurent @ 2015-10-31 20:29 UTC (permalink / raw)


Hi

I need a range of Dates.

So I tried this:

Begin_Date: Dates.Object; 
End_Date: Dates.Object;
-- Dates is a package from an earlier example in my Ada95 book. It is based on Ada.Calendars. I prefer to use
-- Dates because I actually need only the date, I don't care/ need the hour. I also find the name "Time" for 
-- something like "2015/10/31 21:00:00" confusing but that's just my opinion.

That doesn't work unfortunately and the compiler is right to complain:

subtype Period is range Begin_Date .. End_Date;

I naively thought that it could be so easy.

I could solve this problem with a few loops and filling an array or a list with the generated dates but the loop thing will be probably very ugly/complicated. 

For the array I also have to know how many dates I actually have between Begin_Date and End_Date. I have tried to 

I have found in Ada.Calendar a: function "-" (L,R:Time) return Duration

Is it possible to make a casting to convert my Date type in (Ada.Calendar) Time type:

Today : Ada.Calendar.Time:= Time(Date); -- or something like that.

I could of course use the Getters from Dates and then construct a new Time. More of curiosity than an actual problem.

Well of course I could simply use Ada.Calendar.

So is there an existing package which generates a range of Dates from .. to ?
Feels like cheating but causes less frustration. 

 Thanks

Laurent

PS: need this range of dates because the log files I want to read and extract informations from are all named like this: vba-yyyymmdd.log where obviously yyyymmdd is the date. The program generates a new file every date an stores the communication it treated in it.

I want to read this files and extract the messages which passed. Is more an exercise than actually a need to do it.

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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
@ 2015-10-31 20:49 ` Dmitry A. Kazakov
  2015-11-01 13:16   ` Laurent
  2015-11-01  0:25 ` Jeffrey R. Carter
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-10-31 20:49 UTC (permalink / raw)


On Sat, 31 Oct 2015 13:29:51 -0700 (PDT), Laurent wrote:

> I need a range of Dates.
>
> So I tried this:
> 
> Begin_Date: Dates.Object; 
> End_Date: Dates.Object;
> -- Dates is a package from an earlier example in my Ada95 book. It is based on Ada.Calendars. I prefer to use
> -- Dates because I actually need only the date, I don't care/ need the hour. I also find the name "Time" for 
> -- something like "2015/10/31 21:00:00" confusing but that's just my opinion.
> 
> That doesn't work unfortunately and the compiler is right to complain:
> 
> subtype Period is range Begin_Date .. End_Date;

1. How is this subtype would be different from Date? 

2. Date is not a numeric type to have ranges

3. Date cannot be a numeric type because arithmetic operations would not
make sense: D1 + D2 is what?

> I naively thought that it could be so easy.

Yes, because it is wrong.

> I have found in Ada.Calendar a: function "-" (L,R:Time) return Duration

Similarly D1 - D2 is a Duration, not a date. Likewise you can add duration
to a date, but not a date to date.

> Is it possible to make a casting to convert my Date type in (Ada.Calendar) Time type:
> 
> Today : Ada.Calendar.Time:= Time(Date); -- or something like that.

No problem. You would have an equivalent of Year, Month, Day functions
defined for Date. Then you would call Time_Of. That is.

> So is there an existing package which generates a range of Dates from .. to?

No, but you could have an abstract iterator for dates in Ada 2012.

> PS: need this range of dates because the log files I want to read and
> extract informations from are all named like this: vba-yyyymmdd.log where
> obviously yyyymmdd is the date. The program generates a new file every
> date an stores the communication it treated in it.

See Ada.Calendar.Formatting.Image.
 
-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
  2015-10-31 20:49 ` Dmitry A. Kazakov
@ 2015-11-01  0:25 ` Jeffrey R. Carter
  2015-11-01 13:30   ` Laurent
  2015-11-03  6:25   ` Randy Brukardt
  2015-11-01  9:05 ` Jacob Sparre Andersen
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 73+ messages in thread
From: Jeffrey R. Carter @ 2015-11-01  0:25 UTC (permalink / raw)


On 10/31/2015 01:29 PM, Laurent wrote:
> 
> I need a range of Dates.
> 
> So is there an existing package which generates a range of Dates from .. to
> ?
> 
> PS: need this range of dates because the log files I want to read and extract
> informations from are all named like this: vba-yyyymmdd.log where obviously
> yyyymmdd is the date. The program generates a new file every date an stores
> the communication it treated in it.
> 
> I want to read this files and extract the messages which passed. Is more an
> exercise than actually a need to do it.

I'm not aware of any such pkg. On the other hand, I'm not sure you need it. Do
you really need to store all the dates in the range? You could process the file
for date D, then the file for date D + 1, ..., until you have processed all the
desired files.

Conceptually the idea of an operation

function "+" (Left : in Dates.Object; Right : in Integer) return Dates.Object;

makes sense; without knowing the details of the implementation of Dates.Object I
have no idea how easy it would be. For Ada.Calendar.Time, one would simply add
Right * Ada.Calendar.Day_Duration'Last.

-- 
Jeff Carter
"Monsieur Arthur King, who has the brain of a duck, you know."
Monty Python & the Holy Grail
09


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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
  2015-10-31 20:49 ` Dmitry A. Kazakov
  2015-11-01  0:25 ` Jeffrey R. Carter
@ 2015-11-01  9:05 ` Jacob Sparre Andersen
  2015-11-01 13:40   ` Laurent
  2015-11-01 13:42 ` brbarkstrom
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 73+ messages in thread
From: Jacob Sparre Andersen @ 2015-11-01  9:05 UTC (permalink / raw)


Laurent <lutgenl@icloud.com> writes:

> I need a range of Dates.

As a type?

   subtype Period is Date
     with Dynamic_Predicate => Begin_Date <= Period and Period <= End_Date;

As an object?

      type Dates is array (Positive range <>) of Date;
      Period : constant Dates := (Begin_Date,
                                  Begin_Date + 1 * Days,
                                  Begin_Date + 2 * Days,
                                  ...
                                  End_Date);

As an iterator?

   --  Too much work to write here. :-)

Greetings,

Jacob
-- 
"The pictures on radio are always so much better than those on TV."
                                       -- Pratchet, Stewart & Cohen

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

* Re: A few questions
  2015-10-31 20:49 ` Dmitry A. Kazakov
@ 2015-11-01 13:16   ` Laurent
  0 siblings, 0 replies; 73+ messages in thread
From: Laurent @ 2015-11-01 13:16 UTC (permalink / raw)


On Saturday, 31 October 2015 21:49:24 UTC+1, Dmitry A. Kazakov  wrote:

> > subtype Period is range Begin_Date .. End_Date;
> 
> 1. How is this subtype would be different from Date? 
> 
Perhaps in some declarative language where lists are an fundamental part of the language itself the compiler could be smart enough to make Period a list and fill it with dates from..to? Yeah I know mind-reading compiler and World of Fantasycraft :)

> 2. Date is not a numeric type to have ranges

Agreed

> 3. Date cannot be a numeric type because arithmetic operations would not
> make sense: D1 + D2 is what?

Nonsense :)

> > I naively thought that it could be so easy.
> 
> Yes, because it is wrong.

What? Being naive or thinking that it could/should be easy? :)
 
> > I have found in Ada.Calendar a: function "-" (L,R:Time) return Duration
> 
> Similarly D1 - D2 is a Duration, not a date. Likewise you can add duration
> to a date, but not a date to date.
> 
> > Is it possible to make a casting to convert my Date type in (Ada.Calendar) Time type:
> > 
> > Today : Ada.Calendar.Time:= Time(Date); -- or something like that.
> 
> No problem. You would have an equivalent of Year, Month, Day functions
> defined for Date. Then you would call Time_Of. That is.

I actually mentioned the "-" only because it would spare me from having to roll my own to figure out how many days are between D1 and D2. 

But I think that it is probably not necessary at all.

> > So is there an existing package which generates a range of Dates from .. to?
> 
> No, but you could have an abstract iterator for dates in Ada 2012.
> 
> > PS: need this range of dates because the log files I want to read and
> > extract informations from are all named like this: vba-yyyymmdd.log where
> > obviously yyyymmdd is the date. The program generates a new file every
> > date an stores the communication it treated in it.
> 
> See Ada.Calendar.Formatting.Image.

I think getting the names done is the easiest part.

When first took a look at the log files I thought that it would be difficult to extract the informations I am looking for. But no getting some continuous dates from .. to is the real PITA.

Otherwise it would be boring.

Thanks

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

* Re: A few questions
  2015-11-01  0:25 ` Jeffrey R. Carter
@ 2015-11-01 13:30   ` Laurent
  2015-11-03  6:25   ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Laurent @ 2015-11-01 13:30 UTC (permalink / raw)


On Sunday, 1 November 2015 01:25:22 UTC+1, Jeffrey R. Carter  wrote:

> I'm not aware of any such pkg. On the other hand, I'm not sure you need it. Do
> you really need to store all the dates in the range? You could process the file
> for date D, then the file for date D + 1, ..., until you have processed all the
> desired files.

I don't think that I need to store them. It would allow me to use a simple loop later on and hide the ugly things somewhere else.

> Conceptually the idea of an operation
> 
> function "+" (Left : in Dates.Object; Right : in Integer) return Dates.Object;
> 
> makes sense; without knowing the details of the implementation of Dates.Object I
> have no idea how easy it would be. For Ada.Calendar.Time, one would simply add
> Right * Ada.Calendar.Day_Duration'Last.

Sounds like a good idea. 

I am actually reinventing the wheel because most of the functionality already is in the Calendar package. I tried to understand how this package works but there are few intermediate steps which I don't get. IE: Time_Rep? And there are others. They are probably required for managing one special problem which happens once a century.

At least I will perhaps learn why the package has been designed like this.

Thanks



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

* Re: A few questions
  2015-11-01  9:05 ` Jacob Sparre Andersen
@ 2015-11-01 13:40   ` Laurent
  2015-11-01 18:14     ` Jacob Sparre Andersen
  0 siblings, 1 reply; 73+ messages in thread
From: Laurent @ 2015-11-01 13:40 UTC (permalink / raw)


On Sunday, 1 November 2015 10:05:17 UTC+1, Jacob Sparre Andersen  wrote:
 
> As a type?
> 
>    subtype Period is Date
>      with Dynamic_Predicate => Begin_Date <= Period and Period <= End_Date;

And that would allow me to use it like this:

for I in Period'Range loop...

Feels to much like magic that it could actually work :)

> As an object?
> 
>       type Dates is array (Positive range <>) of Date;
>       Period : constant Dates := (Begin_Date,
>                                   Begin_Date + 1 * Days,
>                                   Begin_Date + 2 * Days,
>                                   ...
>                                   End_Date);
> 
> As an iterator?

Don't think that is necessary. Could still try to feed it to my self rolled linked list package to find out if it is able to store the dates. 

Thanks


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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
                   ` (2 preceding siblings ...)
  2015-11-01  9:05 ` Jacob Sparre Andersen
@ 2015-11-01 13:42 ` brbarkstrom
  2015-11-01 13:52   ` Laurent
  2015-11-01 15:15   ` Dennis Lee Bieber
  2015-11-01 16:33 ` gautier_niouzes
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 73+ messages in thread
From: brbarkstrom @ 2015-11-01 13:42 UTC (permalink / raw)


You could translate the YYYYMMDD time into a continuous numerical value
and then use Ada.Real_Time to convert that value to time in seconds from
some selected starting point.

The way astronomers track time is to go over to counting seconds from 
Jan. 0, 2013 BCE.  The variable is called Astronomical Julian Date.
The current value is fairly large, particularly if you want a time 
resolution in microseconds.  GPS time is close to Julian Date, but
uses a starting date closer to the present.

Seidelmann, P. K., 2006: Explanatory Supplement to the Astronomical
Almanac, University Science Books, Sausalito, CA

is the definitive reference.  

Savage, N., 2015: Split Second, Comm. ACM, 58, No. 9, 12-14

deals with "The issue of whether to add a `leap second' to square
the clock with the Earth's orbit pits time specialists against IT."
(quoting from the index to that issue of CACM).

To put it simply, Astronomical Julian Date (and relatives) produces 
a uniform time record in seconds,  It also makes sure that all dates/times
are reduced to the same time zone at the Greenwich meridian.  The usual
IT convention (YYYYMMDD) is non-uniform (for example, Feb. may have 28
or 29 days - while Jul. always has 31).  It would seem that if your
application might move to a geographically distributed environment,
the Julian Date would be sensible.  On the other hand, Julian Date is
not readily interpretable to humans.

Bruce B.


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

* Re: A few questions
  2015-11-01 13:42 ` brbarkstrom
@ 2015-11-01 13:52   ` Laurent
  2015-11-01 17:59     ` Jeffrey R. Carter
  2015-11-02 13:25     ` brbarkstrom
  2015-11-01 15:15   ` Dennis Lee Bieber
  1 sibling, 2 replies; 73+ messages in thread
From: Laurent @ 2015-11-01 13:52 UTC (permalink / raw)


On Sunday, 1 November 2015 14:42:17 UTC+1, brbar...@gmail.com  wrote:
> You could translate the YYYYMMDD time into a continuous numerical value
> and then use Ada.Real_Time to convert that value to time in seconds from
> some selected starting point.
> 
> The way astronomers track time is to go over to counting seconds from 
> Jan. 0, 2013 BCE.  The variable is called Astronomical Julian Date.
> The current value is fairly large, particularly if you want a time 
> resolution in microseconds.  GPS time is close to Julian Date, but
> uses a starting date closer to the present.
> 
> Seidelmann, P. K., 2006: Explanatory Supplement to the Astronomical
> Almanac, University Science Books, Sausalito, CA
> 
> is the definitive reference.  
> 
> Savage, N., 2015: Split Second, Comm. ACM, 58, No. 9, 12-14
> 
> deals with "The issue of whether to add a `leap second' to square
> the clock with the Earth's orbit pits time specialists against IT."
> (quoting from the index to that issue of CACM).
> 
> To put it simply, Astronomical Julian Date (and relatives) produces 
> a uniform time record in seconds,  It also makes sure that all dates/times
> are reduced to the same time zone at the Greenwich meridian.  The usual
> IT convention (YYYYMMDD) is non-uniform (for example, Feb. may have 28
> or 29 days - while Jul. always has 31).  It would seem that if your
> application might move to a geographically distributed environment,
> the Julian Date would be sensible.  On the other hand, Julian Date is
> not readily interpretable to humans.
> 
> Bruce B.

Thanks for the info but I fear that it is more than overkill. 

It also shows that most "standards" have gotten this status only because things have been like that before and not because they are the best possible solution. 

So if you have a better solution than the actual one but are not part of a large community which supports this, then you can burn it immediately. Only because no one wants to change a thing and prefer to use some crappy solution over changing something and investing time and effort.

Somehow this world sucks.


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

* Re: A few questions
  2015-11-01 13:42 ` brbarkstrom
  2015-11-01 13:52   ` Laurent
@ 2015-11-01 15:15   ` Dennis Lee Bieber
  1 sibling, 0 replies; 73+ messages in thread
From: Dennis Lee Bieber @ 2015-11-01 15:15 UTC (permalink / raw)


On Sun, 1 Nov 2015 05:42:16 -0800 (PST), brbarkstrom@gmail.com declaimed
the following:

>To put it simply, Astronomical Julian Date (and relatives) produces 
>a uniform time record in seconds,  It also makes sure that all dates/times
>are reduced to the same time zone at the Greenwich meridian.  The usual
>IT convention (YYYYMMDD) is non-uniform (for example, Feb. may have 28
>or 29 days - while Jul. always has 31).  It would seem that if your
>application might move to a geographically distributed environment,
>the Julian Date would be sensible.  On the other hand, Julian Date is
>not readily interpretable to humans.
>

	There's also the minor touch that the "day" rolls over at noon, not
midnight. After all, when one's work runs the dark hours, who wants to
fiddle with a day change in the middle of one's observations.

	If the dates don't need to go back too far (Nov 17 1858, Modified
Julian Date is usable, and puts the day change back to midnight. As I
recall MJD was the reference point used by the VMS operating system.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
                   ` (3 preceding siblings ...)
  2015-11-01 13:42 ` brbarkstrom
@ 2015-11-01 16:33 ` gautier_niouzes
  2015-11-01 16:36   ` gautier_niouzes
  2015-11-01 18:17 ` Stephen Leake
  2015-11-02 17:45 ` Simon Wright
  6 siblings, 1 reply; 73+ messages in thread
From: gautier_niouzes @ 2015-11-01 16:33 UTC (permalink / raw)


What about something like this:

  Begin_Date: Time:= ...;
  End_Date: Time:= ...;
  Day_Seconds: constant Duration:= 86400.0;
  Days: constant Natural:= Natural(End_Date-Begin_Date) / Day_Seconds;
  subtype Period is Natural range 0..Days;

?
As a bonus, you have below a display function from my toolbox :-) .
_________________________
Gautier's Ada programming
http://gautiersblog.blogspot.com/search/label/Ada
NB: follow the above link for a valid e-mail address


--  Time_display returns date & time, current or given.
--  E.g.: "2013/08/01  05:49:51"
--  Useful for a log file or a display of a lengthy operation.
--  This is Ada 83 compatible. Format accepted by SQL queries.
--
--    32- or 64-bit: DEC/Compaq/HP Ada (83), GNAT (95/2005), ObjectAda (95)
--    16-bit:        Meridian (83) -> Long_Integer is 32-bit
--    16-bit:        Janus 2.x (83): KO: no Long_Integer
--
--  Test program in following comment:
--
--   with Text_IO,Time_display;procedure Test is begin Text_IO.Put(Time_display);end;

with Calendar;

function Time_display(
  T        : Calendar.Time:= Calendar.Clock;
  Seconds  : Boolean      := True;
  Intra_day: Boolean      := True
)
  return String
is
  use Calendar;
  subtype Sec_int is Long_Integer; -- must contain 86_400
  s : constant Sec_int:= Sec_int( Calendar.Seconds(T) );
  m : constant Sec_int:= s / 60;
  -- + 100: trick for obtaining 0x
  sY : constant String:= Integer'Image( Year(T));
  sM : constant String:= Integer'Image( Month(T) + 100);
  sD : constant String:= Integer'Image(  Day(T)  + 100);
  shr: constant String:= Sec_int'Image( m  /  60 + 100);
  smn: constant String:= Sec_int'Image( m mod 60 + 100);
  ssc: constant String:= Sec_int'Image( s mod 60 + 100);
  --
  function Optional_seconds return String is
  begin
    if Seconds then
      return ':' & ssc( ssc'Last-1 .. ssc'Last );
    else
      return "";
    end if;
  end Optional_seconds;
  --
  function Optional_intra_day return String is
  begin
    if Intra_day then
      return
        "  " &
        shr( shr'Last-1 .. shr'Last ) & ':' &
        smn( smn'Last-1 .. smn'Last ) & Optional_seconds;
    else
      return "";
    end if;
  end Optional_intra_day;

begin
  return
    sY( sY'Last-3 .. sY'Last ) & '/' &  -- not Year 10'000 compliant.
    sM( sM'Last-1 .. sM'Last ) & '/' &
    sD( sD'Last-1 .. sD'Last ) &
    Optional_intra_day;
end Time_display;


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

* Re: A few questions
  2015-11-01 16:33 ` gautier_niouzes
@ 2015-11-01 16:36   ` gautier_niouzes
  0 siblings, 0 replies; 73+ messages in thread
From: gautier_niouzes @ 2015-11-01 16:36 UTC (permalink / raw)


>   Days: constant Natural:= Natural(End_Date-Begin_Date) / Day_Seconds;

Probably better so :-) : Natural((End_Date-Begin_Date) / Day_Seconds);
_________________________ 
Gautier's Ada programming 
http://sf.net/users/gdemont

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

* Re: A few questions
  2015-11-01 13:52   ` Laurent
@ 2015-11-01 17:59     ` Jeffrey R. Carter
  2015-11-01 18:35       ` Laurent
  2015-11-02 13:25     ` brbarkstrom
  1 sibling, 1 reply; 73+ messages in thread
From: Jeffrey R. Carter @ 2015-11-01 17:59 UTC (permalink / raw)


On 11/01/2015 06:52 AM, Laurent wrote:
> 
> So if you have a better solution than the actual one but are not part of a
> large community which supports this, then you can burn it immediately. Only
> because no one wants to change a thing and prefer to use some crappy solution
> over changing something and investing time and effort.

Sure. Thirty years ago I worked on a research project funded by a black project.
The researcher said at the beginning that the project wouldn't use our results,
no matter how good they were, because the project wasn't in trouble. The
standard approach to the problem was quite complex and very calculation
intensive. The researcher's approach worked, was more accurate than the
theoretical minimum for the standard approach, and required fewer calculations.
The project stuck with the standard approach.

> Somehow this world sucks.

Then you die.

-- 
Jeff Carter
"It's symbolic of his struggle against reality."
Monty Python's Life of Brian
78


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

* Re: A few questions
  2015-11-01 13:40   ` Laurent
@ 2015-11-01 18:14     ` Jacob Sparre Andersen
  2015-11-01 18:40       ` Laurent
  0 siblings, 1 reply; 73+ messages in thread
From: Jacob Sparre Andersen @ 2015-11-01 18:14 UTC (permalink / raw)


Laurent <lutgenl@icloud.com> writes:

>>    subtype Period is Date
>>      with Dynamic_Predicate => Begin_Date <= Period and Period <= End_Date;
>
> And that would allow me to use it like this:
>
> for I in Period'Range loop...

No.  That wasn't what you asked for.

>> As an iterator?
>
> Don't think that is necessary. Could still try to feed it to my self
> rolled linked list package to find out if it is able to store the
> dates.

Why worry about storing the dates, if you just want to iterate over a
range?

Greetings,

Jacob
-- 
"Lots of information, strong cast, but a bit weak on the narrative."
              -- Pratchet, Stewart & Cohen reviews a phone directory


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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
                   ` (4 preceding siblings ...)
  2015-11-01 16:33 ` gautier_niouzes
@ 2015-11-01 18:17 ` Stephen Leake
  2015-11-01 18:53   ` Laurent
  2015-11-02 17:45 ` Simon Wright
  6 siblings, 1 reply; 73+ messages in thread
From: Stephen Leake @ 2015-11-01 18:17 UTC (permalink / raw)


Laurent <lutgenl@icloud.com> writes:

> Hi
>
> I need a range of Dates.

Why?

What will that do for you that your current Date package will not do?

Until we know that, it's hard to say what code you should implement.

> Begin_Date: Dates.Object; 
> End_Date: Dates.Object;

Why isn't this enough for your needs?

> subtype Period is range Begin_Date .. End_Date;

What operations to do want to have for this type?

-- 
-- Stephe


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

* Re: A few questions
  2015-11-01 17:59     ` Jeffrey R. Carter
@ 2015-11-01 18:35       ` Laurent
  0 siblings, 0 replies; 73+ messages in thread
From: Laurent @ 2015-11-01 18:35 UTC (permalink / raw)


On Sunday, 1 November 2015 18:59:47 UTC+1, Jeffrey R. Carter  wrote:
 
> > Somehow this world sucks.
> 
> Then you die.

True for everybody independently of the fact that the world sucks. Which only has an influence on the when and how  :)

But that belongs into some other google group

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

* Re: A few questions
  2015-11-01 18:14     ` Jacob Sparre Andersen
@ 2015-11-01 18:40       ` Laurent
  0 siblings, 0 replies; 73+ messages in thread
From: Laurent @ 2015-11-01 18:40 UTC (permalink / raw)


On Sunday, 1 November 2015 19:14:09 UTC+1, Jacob Sparre Andersen  wrote:

> >>    subtype Period is Date
> >>      with Dynamic_Predicate => Begin_Date <= Period and Period <= End_Date;
> >
> > And that would allow me to use it like this:
> >
> > for I in Period'Range loop...
> 
> No.  That wasn't what you asked for.

No didn't ask in the beginning but it was my intention since the begin to use it like that. Sorry my error of not mentioning it immediately.

> Why worry about storing the dates, if you just want to iterate over a
> range?

Curiosity


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

* Re: A few questions
  2015-11-01 18:17 ` Stephen Leake
@ 2015-11-01 18:53   ` Laurent
  2015-11-02  0:41     ` Dennis Lee Bieber
  2015-11-02 16:42     ` Stephen Leake
  0 siblings, 2 replies; 73+ messages in thread
From: Laurent @ 2015-11-01 18:53 UTC (permalink / raw)


On Sunday, 1 November 2015 19:17:44 UTC+1, Stephen Leake  wrote:

> > I need a range of Dates.
> 
> Why?
> 
> What will that do for you that your current Date package will not do?
> 
> Until we know that, it's hard to say what code you should implement.
> 
> > Begin_Date: Dates.Object; 
> > End_Date: Dates.Object;
> 
> Why isn't this enough for your needs?

No because my package had nothing else than set/get the different components of Date and a constructor.

and an IO package for formatting

I have now added "+" (L: Date, R : Positive) return Date

which should work the way I think it should. Perhaps . First need to test if the result is correct. Another day.

> > subtype Period is range Begin_Date .. End_Date;
> 
> What operations to do want to have for this type?

Hm none. Just would need the possibility to use it in a loop for the 'Range. But hey I am a noob so I quite often asks silly questions :)


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

* Re: A few questions
  2015-11-01 18:53   ` Laurent
@ 2015-11-02  0:41     ` Dennis Lee Bieber
  2015-11-02 16:42     ` Stephen Leake
  1 sibling, 0 replies; 73+ messages in thread
From: Dennis Lee Bieber @ 2015-11-02  0:41 UTC (permalink / raw)


On Sun, 1 Nov 2015 10:53:31 -0800 (PST), Laurent <lutgenl@icloud.com>
declaimed the following:

>
>Hm none. Just would need the possibility to use it in a loop for the 'Range. But hey I am a noob so I quite often asks silly questions :)

	And the simplest is probably to have some procedure/function that
converts between a calendar (day month year) and some cardinal/integer
referenced to some epoch date. So your range becomes a range of cardinal
values.

	Which puts us back to JD, MJD (you probably don't want JD since xxxx.0
is NOON, and midnight is xxxx.5), C/UNIX seconds since some epoch based on
some date in 1970, etc.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/


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

* Re: A few questions
  2015-11-01 13:52   ` Laurent
  2015-11-01 17:59     ` Jeffrey R. Carter
@ 2015-11-02 13:25     ` brbarkstrom
  1 sibling, 0 replies; 73+ messages in thread
From: brbarkstrom @ 2015-11-02 13:25 UTC (permalink / raw)



> Thanks for the info but I fear that it is more than overkill. 
> 
> It also shows that most "standards" have gotten this status only because things have been like that before and not because they are the best possible solution. 
> 
> So if you have a better solution than the actual one but are not part of a large community which supports this, then you can burn it immediately. Only because no one wants to change a thing and prefer to use some crappy solution over changing something and investing time and effort.
> 
> Somehow this world sucks.

That's a bit oversimplified.  "Standards" get adopted because some group
reaches a consensus.  In the case of botany, getting to agreement on the
standard Linnean nomenclature required about a century (roughly 1800-1900)
and five or six international congresses.  In the IT world, UDDI was of
interest to a number of large businesses - and then they dropped the effort
because it didn't seem to be in their interest to continue.

Note also that there may not be an agreement on what is the "best" solution.
That's particularly the case with time standards.  A classical astronomer
would probably prefer a time standard that kept the Sun in the same place
for a given day of the year - and would put up with leap seconds on an 
occasional basis.  A physicist would prefer that time marches uniformly,
like atomic clocks.  An IT specialist may prefer using civil time because
it's understandable - but suffers from complicated representations and
irregularities, as well as the possibility that someone forgot to put in
a standard time zone.

Bruce B.


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

* Re: A few questions
  2015-11-01 18:53   ` Laurent
  2015-11-02  0:41     ` Dennis Lee Bieber
@ 2015-11-02 16:42     ` Stephen Leake
  1 sibling, 0 replies; 73+ messages in thread
From: Stephen Leake @ 2015-11-02 16:42 UTC (permalink / raw)


Laurent <lutgenl@icloud.com> writes:

> On Sunday, 1 November 2015 19:17:44 UTC+1, Stephen Leake  wrote:
>
>> > subtype Period is range Begin_Date .. End_Date;
>> 
>> What operations to do want to have for this type?
>
> Hm none. Just would need the possibility to use it in a loop for the
> 'Range. 

I'm guessing you want the loop to cover each day in the date range?

In that case, Julian Days (or days since some other epoch) will allow
this in a "for" loop.

Or you can write a function:

function Next_Day (I : in Date) return Date;

and use that in an "exit" loop.

-- 
-- Stephe


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

* Re: A few questions
  2015-10-31 20:29 A few questions Laurent
                   ` (5 preceding siblings ...)
  2015-11-01 18:17 ` Stephen Leake
@ 2015-11-02 17:45 ` Simon Wright
  2015-11-02 18:48   ` Simon Wright
  2015-11-03  6:40   ` Randy Brukardt
  6 siblings, 2 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-02 17:45 UTC (permalink / raw)


Laurent <lutgenl@icloud.com> writes:

> Hi
>
> I need a range of Dates.

I wrote the attached, using generalized iteration, which bears a strong
resemblance to the standard container iteration (the names bear too
strong a resemblance! but this way you can see the commonality).

I'd have liked to support

   for D in Period loop
      ...

but "array type required in indexed component" (which I think means that
Date_Container needs the Constant_Indexing aspect?).

Running this test just now,

   with Date_Iteration;
   with Ada.Calendar.Formatting;
   with Ada.Text_IO; use Ada.Text_IO;
   procedure Date_Iteration_Test is
      use type Ada.Calendar.Time;
      Period : Date_Iteration.Date_Container;
      Day : constant Duration := 86_400.0;
   begin
      Period.Initialize (Start_Time => Ada.Calendar.Clock,
                         End_Time   => Ada.Calendar.Clock + Day * 10,
                         Interval   => Day / 2);
      for C in Period.Iterate loop
         Put_Line (Ada.Calendar.Formatting.Image (Date_Iteration.Element (C)));
      end loop;
   end Date_Iteration_Test;

I got

   $ ./date_iteration_test
   2015-11-02 17:35:03
   2015-11-03 05:35:03
   2015-11-03 17:35:03
   2015-11-04 05:35:03
   2015-11-04 17:35:03
   2015-11-05 05:35:03
   2015-11-05 17:35:03
   2015-11-06 05:35:03
   2015-11-06 17:35:03
   2015-11-07 05:35:03
   2015-11-07 17:35:03
   2015-11-08 05:35:03
   2015-11-08 17:35:03
   2015-11-09 05:35:03
   2015-11-09 17:35:03
   2015-11-10 05:35:03
   2015-11-10 17:35:03
   2015-11-11 05:35:03
   2015-11-11 17:35:03
   2015-11-12 05:35:03
   2015-11-12 17:35:03

========================================================================
with Ada.Calendar;
with Ada.Iterator_Interfaces;
package Date_Iteration is
   type Date_Container is tagged private
   with
     Default_Iterator => Iterate,
     Iterator_Element => Ada.Calendar.Time;
   procedure Initialize (D          : out Date_Container;
                         Start_Time :     Ada.Calendar.Time;
                         End_Time   :     Ada.Calendar.Time;
                         Interval   :     Duration := 86_400.0);

   type Cursor is private;
   No_Element : constant Cursor;

   function First (Container : Date_Container) return Cursor;
   function Next (Position : Cursor) return Cursor;
   function Element (Position : Cursor) return Ada.Calendar.Time;

   function Has_Element (C : Cursor) return Boolean;
   package Iterator_Interfaces
     is new Ada.Iterator_Interfaces (Cursor, Has_Element);
   function Iterate (Container : Date_Container)
                    return Iterator_Interfaces.Forward_Iterator'Class;
private
   type Date_Container is tagged record
      Start_Time : Ada.Calendar.Time;
      End_Time   : Ada.Calendar.Time;
      Interval   : Duration;
   end record;
   type Date_Container_Access is access all Date_Container;
   for Date_Container_Access'Storage_Size use 0;

   type Cursor is record
      Container : Date_Container_Access;
      Index     : Ada.Calendar.Time;
   end record;
   No_Element : constant Cursor
     := (Container => null, Index => Ada.Calendar.Clock);

   type Iterator is new Iterator_Interfaces.Forward_Iterator
      with record
         Container : Date_Container_Access;
      end record;
   overriding
   function First (Object : Iterator) return Cursor;
   overriding
   function Next (Object : Iterator; Position : Cursor) return Cursor;
end Date_Iteration;

package body Date_Iteration is
   procedure Initialize (D          : out Date_Container;
                         Start_Time :     Ada.Calendar.Time;
                         End_Time   :     Ada.Calendar.Time;
                         Interval   :     Duration := 86_400.0) is
   begin
      D := (Start_Time => Start_Time,
            End_Time   => End_Time,
            Interval   => Interval);
   end;

   function First (Container : Date_Container) return Cursor is
   begin
      return C : Cursor do
         C.Container := Container'Unrestricted_Access;
         C.Index := Container.Start_Time;
      end return;
   end First;

   function Next (Position : Cursor) return Cursor is
      use type Ada.Calendar.Time;
   begin
      if Position.Container = null then
         return No_Element;
      end if;
      return C : Cursor do
         C.Container := Position.Container;
         C.Index := Position.Index + Position.Container.Interval;
      end return;
   end Next;

   function Element (Position : Cursor) return Ada.Calendar.Time is
     (Position.Index);

   function Has_Element (C : Cursor) return Boolean is
      use type Ada.Calendar.Time;
   begin
      return C.Index <= C.Container.End_Time;
   end Has_Element;

   function Iterate (Container : Date_Container)
                    return Iterator_Interfaces.Forward_Iterator'Class is
   begin
      return It : Iterator do
         It.Container := Container'Unrestricted_Access;
      end return;
   end Iterate;

   function First (Object : Iterator) return Cursor is
   begin
      return Object.Container.First;
   end First;

   function Next (Object : Iterator; Position : Cursor) return Cursor is
   begin
      if Position.Container = null then
         return No_Element;
      end if;
      if Position.Container /= Object.Container then
         raise Program_Error with "container/cursor mismatch";
      end if;
      return Next (Position);
   end Next;
end Date_Iteration;

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

* Re: A few questions
  2015-11-02 17:45 ` Simon Wright
@ 2015-11-02 18:48   ` Simon Wright
  2015-11-03  6:33     ` Randy Brukardt
  2015-11-03  6:40   ` Randy Brukardt
  1 sibling, 1 reply; 73+ messages in thread
From: Simon Wright @ 2015-11-02 18:48 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> I'd have liked to support
>
>    for D in Period loop

Oops, I meant "for D of Period", i.e.

   for D : Ada.Calendar.Time of Period loop
      ...

but you'd need

   function Constant_Reference
     (Container : aliased Date_Container;
      Position  : Cursor) return Constant_Reference_Type;

returning

   type Constant_Reference_Type
      (Element : not null access constant Ada.Calendar.Time) is private
   with
      Implicit_Dereference => Element;

which is clearly meant for actual containers and here would require - I
think - allocating an Ada.Calendar.Time, and of course freeing it
eventually.

Shame, it makes it tricky to support lazy evaluation. But perhaps we
shouldn't want to ...

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

* Re: A few questions
  2015-11-01  0:25 ` Jeffrey R. Carter
  2015-11-01 13:30   ` Laurent
@ 2015-11-03  6:25   ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-03  6:25 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message 
news:n13m1a$p3c$1@dont-email.me...
> On 10/31/2015 01:29 PM, Laurent wrote:
>>
>> I need a range of Dates.
>>
>> So is there an existing package which generates a range of Dates from .. 
>> to
>> ?
>>
>> PS: need this range of dates because the log files I want to read and 
>> extract
>> informations from are all named like this: vba-yyyymmdd.log where 
>> obviously
>> yyyymmdd is the date. The program generates a new file every date an 
>> stores
>> the communication it treated in it.
>>
>> I want to read this files and extract the messages which passed. Is more 
>> an
>> exercise than actually a need to do it.
>
> I'm not aware of any such pkg. On the other hand, I'm not sure you need 
> it. Do
> you really need to store all the dates in the range? You could process the 
> file
> for date D, then the file for date D + 1, ..., until you have processed 
> all the
> desired files.
>
> Conceptually the idea of an operation
>
> function "+" (Left : in Dates.Object; Right : in Integer) return 
> Dates.Object;
>
> makes sense; without knowing the details of the implementation of 
> Dates.Object I
> have no idea how easy it would be. For Ada.Calendar.Time, one would simply 
> add
> Right * Ada.Calendar.Day_Duration'Last.

Or easier still, just use Ada.Calendar.Arithmetic, which has operations for 
adding numbers of days to a Ada.Calendar.Time (added in Ada 2005). (This is 
hard to do in Ada 95 if you need to add more than one day at a time.)

                                         Randy.


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

* Re: A few questions
  2015-11-02 18:48   ` Simon Wright
@ 2015-11-03  6:33     ` Randy Brukardt
  2015-11-03  8:26       ` Simon Wright
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-03  6:33 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly1tc8me4w.fsf@pushface.org...
> Simon Wright <simon@pushface.org> writes:
>
>> I'd have liked to support
>>
>>    for D in Period loop
>
> Oops, I meant "for D of Period", i.e.
>
>   for D : Ada.Calendar.Time of Period loop
>      ...
>
> but you'd need
>
>   function Constant_Reference
>     (Container : aliased Date_Container;
>      Position  : Cursor) return Constant_Reference_Type;
>
> returning
>
>   type Constant_Reference_Type
>      (Element : not null access constant Ada.Calendar.Time) is private
>   with
>      Implicit_Dereference => Element;
>
> which is clearly meant for actual containers and here would require - I
> think - allocating an Ada.Calendar.Time, and of course freeing it
> eventually.
>
> Shame, it makes it tricky to support lazy evaluation. But perhaps we
> shouldn't want to ...

If you *only* need constants, the Constant_Indexing function can be a normal 
function (no implicit dereference required). In that case, the 
implementation will do the memory management. Note the difference in wording 
between 4.1.6(2/3) and 4.1.6(3/3) (there is no requirement on the return 
type for Constant_Indexing).

OTOH, I think GNAT got that wrong somehow when I constructed an ACATS test 
to try that (don't recall the details). So it may not work in your copy of 
GNAT, most likely it will in a future version.

                                       Randy.




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

* Re: A few questions
  2015-11-02 17:45 ` Simon Wright
  2015-11-02 18:48   ` Simon Wright
@ 2015-11-03  6:40   ` Randy Brukardt
  2015-11-03  8:34     ` Simon Wright
  1 sibling, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-03  6:40 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly611kmh1g.fsf@pushface.org...
...
> I wrote the attached, using generalized iteration, which bears a strong
> resemblance to the standard container iteration (the names bear too
> strong a resemblance! but this way you can see the commonality).

I suspect you could have written this in a lot simpler fashion. Something 
similar to the Prime_Numbers iterator found in the ACATS foundation 
(F552A00, look in the support subdirectory, specifically 
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/acats/support/f552a00.a) would be 
a starting point. (Thanks again to Brad Moore for creating this foundation 
and the associated ACATS tests to give all Ada implementers something to use 
as a correct example of iterators.)

                                             Randy.


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

* Re: A few questions
  2015-11-03  6:33     ` Randy Brukardt
@ 2015-11-03  8:26       ` Simon Wright
  0 siblings, 0 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-03  8:26 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Simon Wright" <simon@pushface.org> wrote in message 

>>   function Constant_Reference
>>     (Container : aliased Date_Container;
>>      Position  : Cursor) return Constant_Reference_Type;
>>
>> returning
>>
>>   type Constant_Reference_Type
>>      (Element : not null access constant Ada.Calendar.Time) is private
>>   with
>>      Implicit_Dereference => Element;

> If you *only* need constants, the Constant_Indexing function can be a
> normal function (no implicit dereference required). In that case, the
> implementation will do the memory management. Note the difference in
> wording between 4.1.6(2/3) and 4.1.6(3/3) (there is no requirement on
> the return type for Constant_Indexing).

Worked a treat!

> OTOH, I think GNAT got that wrong somehow when I constructed an ACATS
> test to try that (don't recall the details). So it may not work in
> your copy of GNAT, most likely it will in a future version.

No problem (for the constant case) with GCC 5.1.0 or GNAT GPL 2015.

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

* Re: A few questions
  2015-11-03  6:40   ` Randy Brukardt
@ 2015-11-03  8:34     ` Simon Wright
  2015-11-04 16:19       ` Simon Wright
  0 siblings, 1 reply; 73+ messages in thread
From: Simon Wright @ 2015-11-03  8:34 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Simon Wright" <simon@pushface.org> wrote in message 
> news:ly611kmh1g.fsf@pushface.org...
> ...
>> I wrote the attached, using generalized iteration, which bears a
>> strong resemblance to the standard container iteration (the names
>> bear too strong a resemblance! but this way you can see the
>> commonality).
>
> I suspect you could have written this in a lot simpler
> fashion. Something similar to the Prime_Numbers iterator found in the
> ACATS foundation (F552A00, look in the support subdirectory,
> specifically
> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/acats/support/f552a00.a)
> would be a starting point. (Thanks again to Brad Moore for creating
> this foundation and the associated ACATS tests to give all Ada
> implementers something to use as a correct example of iterators.)

Great pointer. Though I think the Date case would be a bit more
complicated, because you couldn't constrain a Date_Set by Times or
Durations.


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

* Re: A few questions
  2015-11-03  8:34     ` Simon Wright
@ 2015-11-04 16:19       ` Simon Wright
  2015-11-05  1:20         ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Simon Wright @ 2015-11-04 16:19 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> "Simon Wright" <simon@pushface.org> wrote in message 
>> news:ly611kmh1g.fsf@pushface.org...
>> ...
>>> I wrote the attached, using generalized iteration, which bears a
>>> strong resemblance to the standard container iteration (the names
>>> bear too strong a resemblance! but this way you can see the
>>> commonality).
>>
>> I suspect you could have written this in a lot simpler
>> fashion. Something similar to the Prime_Numbers iterator found in the
>> ACATS foundation (F552A00, look in the support subdirectory,
>> specifically
>> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/acats/support/f552a00.a)
>> would be a starting point. (Thanks again to Brad Moore for creating
>> this foundation and the associated ACATS tests to give all Ada
>> implementers something to use as a correct example of iterators.)
>
> Great pointer. Though I think the Date case would be a bit more
> complicated, because you couldn't constrain a Date_Set by Times or
> Durations.

And I was hoping to write

   with Ada.Text_IO;
   with F552A00_Prime_Numbers;
   procedure Primes is
   begin
      for P of F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
         Ada.Text_IO.Put_Line (P'Img);
      end loop;
   end Primes;

but (surprise)

   primes.adb:5:08: cannot iterate over "Prime_Number_Set"

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

* Re: A few questions
  2015-11-04 16:19       ` Simon Wright
@ 2015-11-05  1:20         ` Randy Brukardt
  2015-11-05  8:34           ` briot.emmanuel
  2015-11-05  8:45           ` Simon Wright
  0 siblings, 2 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-05  1:20 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:lybnb9lote.fsf@pushface.org...
> Simon Wright <simon@pushface.org> writes:
>
>> "Randy Brukardt" <randy@rrsoftware.com> writes:
>>
>>> "Simon Wright" <simon@pushface.org> wrote in message
>>> news:ly611kmh1g.fsf@pushface.org...
>>> ...
>>>> I wrote the attached, using generalized iteration, which bears a
>>>> strong resemblance to the standard container iteration (the names
>>>> bear too strong a resemblance! but this way you can see the
>>>> commonality).
>>>
>>> I suspect you could have written this in a lot simpler
>>> fashion. Something similar to the Prime_Numbers iterator found in the
>>> ACATS foundation (F552A00, look in the support subdirectory,
>>> specifically
>>> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/acats/support/f552a00.a)
>>> would be a starting point. (Thanks again to Brad Moore for creating
>>> this foundation and the associated ACATS tests to give all Ada
>>> implementers something to use as a correct example of iterators.)
>>
>> Great pointer. Though I think the Date case would be a bit more
>> complicated, because you couldn't constrain a Date_Set by Times or
>> Durations.
>
> And I was hoping to write
>
>   with Ada.Text_IO;
>   with F552A00_Prime_Numbers;
>   procedure Primes is
>   begin
>      for P of F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) 
> loop
>         Ada.Text_IO.Put_Line (P'Img);
>      end loop;
>   end Primes;
>
> but (surprise)
>
>   primes.adb:5:08: cannot iterate over "Prime_Number_Set"

Prime_Number_Set is (directly) an iterator, so you use "in" to iterate over 
it:

 for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop

The "of" form is for iterating over an array or a container whose type has 
the Default_Iterator aspect (which gives the iterator to use).

I can hear the head slap from here. ;-)

                                    Randy.




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

* Re: A few questions
  2015-11-05  1:20         ` Randy Brukardt
@ 2015-11-05  8:34           ` briot.emmanuel
  2015-11-12 18:28             ` Randy Brukardt
  2015-11-05  8:45           ` Simon Wright
  1 sibling, 1 reply; 73+ messages in thread
From: briot.emmanuel @ 2015-11-05  8:34 UTC (permalink / raw)


> The "of" form is for iterating over an array or a container whose type has 
> the Default_Iterator aspect (which gives the iterator to use).

The main drawback, though, is that you then get a Cursor, not an Element, so
you still need to call the functions Element or Reference to get to the actual
element. This is slightly less convenient (syntax-wise). I wish it was possible
to use "of" to indicate that we want to get an element, even when the
right-side is an iterator (which for instance would be convenient when
writing graph data structures where there really are lots of different ways
to iterate, and a single Default_Iterator is not enough


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

* Re: A few questions
  2015-11-05  1:20         ` Randy Brukardt
  2015-11-05  8:34           ` briot.emmanuel
@ 2015-11-05  8:45           ` Simon Wright
  2015-11-05  8:52             ` Simon Wright
  1 sibling, 1 reply; 73+ messages in thread
From: Simon Wright @ 2015-11-05  8:45 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> Prime_Number_Set is (directly) an iterator, so you use "in" to iterate
> over it:
>
>  for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
>
> The "of" form is for iterating over an array or a container whose type
> has the Default_Iterator aspect (which gives the iterator to use).
>
> I can hear the head slap from here. ;-)

Yes, but;

     1. with Ada.Text_IO;
     2. with F552A00_Prime_Numbers;
     3. procedure Primes is
     4. begin
     5.    for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
                                                          |
        >>> expected a discrete type
        >>> found type "Prime_Number_Set" defined at f552a00_prime_numbers.ads:74

     6.       Ada.Text_IO.Put_Line (P'Img);
     7.    end loop;
     8. end Primes;

Perhaps this is the GNAT problem you spoke of? (FSF GCC 5.1.0, GNAT GPL 2015)


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

* Re: A few questions
  2015-11-05  8:45           ` Simon Wright
@ 2015-11-05  8:52             ` Simon Wright
  2015-11-12 18:29               ` Randy Brukardt
  2015-11-12 18:32               ` Randy Brukardt
  0 siblings, 2 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-05  8:52 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> Prime_Number_Set is (directly) an iterator, so you use "in" to iterate
>> over it:
>>
>>  for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
>>
>> The "of" form is for iterating over an array or a container whose type
>> has the Default_Iterator aspect (which gives the iterator to use).
>>
>> I can hear the head slap from here. ;-)
>
> Yes, but;
>
>      1. with Ada.Text_IO;
>      2. with F552A00_Prime_Numbers;
>      3. procedure Primes is
>      4. begin
>      5.    for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
>                                                           |
>         >>> expected a discrete type
>         >>> found type "Prime_Number_Set" defined at
>         >>> f552a00_prime_numbers.ads:74
>
>      6.       Ada.Text_IO.Put_Line (P'Img);
>      7.    end loop;
>      8. end Primes;
>
> Perhaps this is the GNAT problem you spoke of? (FSF GCC 5.1.0, GNAT GPL 2015)

Oh, it should have been

   for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31).Iterate
      loop

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

* Re: A few questions
  2015-11-05  8:34           ` briot.emmanuel
@ 2015-11-12 18:28             ` Randy Brukardt
  2015-11-12 20:19               ` Simon Wright
                                 ` (2 more replies)
  0 siblings, 3 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-12 18:28 UTC (permalink / raw)


<briot.emmanuel@gmail.com> wrote in message 
news:aa0cf839-651e-494d-a826-c2ce31a7afd3@googlegroups.com...
>> The "of" form is for iterating over an array or a container whose type 
>> has
>> the Default_Iterator aspect (which gives the iterator to use).
>
> The main drawback, though, is that you then get a Cursor, not an Element, 
> so
> you still need to call the functions Element or Reference to get to the 
> actual
> element. This is slightly less convenient (syntax-wise).

Sure, but not in a case like the OP's, where the "cursor" is the actual data 
and there is no element. In that case, "of" is just overkill.

> I wish it was possible
> to use "of" to indicate that we want to get an element, even when the
> right-side is an iterator (which for instance would be convenient when
> writing graph data structures where there really are lots of different 
> ways
> to iterate, and a single Default_Iterator is not enough

That doesn't make sense, though, as the iterator interface doesn't contain 
the information necessary to do "of" iteration. In particular, it doesn't 
provide the container or Reference function -- nor could it, as there may 
not be a container.

Personally, I find the "of" form unnecessary; we've iterated arrays for 
decades without direct access to the element (using the "cursor", that is 
the array index), so why are containers different? Especially as the 
indexing form works on all of the language-defined containers (you never 
need to explicitly call Reference or Element). So an "in" iterator looks 
just like the array iteration that we've been using from the beginning of 
time. What's so hard about that?

                                        Randy.


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

* Re: A few questions
  2015-11-05  8:52             ` Simon Wright
@ 2015-11-12 18:29               ` Randy Brukardt
  2015-11-12 18:32               ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-12 18:29 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:lyziyskeu2.fsf@pushface.org...
> Simon Wright <simon@pushface.org> writes:
>
>> "Randy Brukardt" <randy@rrsoftware.com> writes:
>>
>>> Prime_Number_Set is (directly) an iterator, so you use "in" to iterate
>>> over it:
>>>
>>>  for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
>>>
>>> The "of" form is for iterating over an array or a container whose type
>>> has the Default_Iterator aspect (which gives the iterator to use).
>>>
>>> I can hear the head slap from here. ;-)
>>
>> Yes, but;
>>
>>      1. with Ada.Text_IO;
>>      2. with F552A00_Prime_Numbers;
>>      3. procedure Primes is
>>      4. begin
>>      5.    for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 
>> 31) loop
>>                                                           |
>>         >>> expected a discrete type
>>         >>> found type "Prime_Number_Set" defined at
>>         >>> f552a00_prime_numbers.ads:74
>>
>>      6.       Ada.Text_IO.Put_Line (P'Img);
>>      7.    end loop;
>>      8. end Primes;
>>
>> Perhaps this is the GNAT problem you spoke of? (FSF GCC 5.1.0, GNAT GPL 
>> 2015)
>
> Oh, it should have been
>
>   for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 
> 31).Iterate
>      loop

Right. You got two head slaps for the price of one. :-)

                     Randy.



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

* Re: A few questions
  2015-11-05  8:52             ` Simon Wright
  2015-11-12 18:29               ` Randy Brukardt
@ 2015-11-12 18:32               ` Randy Brukardt
  2015-11-12 20:02                 ` Simon Wright
  1 sibling, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-12 18:32 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:lyziyskeu2.fsf@pushface.org...
> Simon Wright <simon@pushface.org> writes:
>
>> "Randy Brukardt" <randy@rrsoftware.com> writes:
>>
>>> Prime_Number_Set is (directly) an iterator, so you use "in" to iterate
>>> over it:
>>>
>>>  for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 31) loop
>>>
>>> The "of" form is for iterating over an array or a container whose type
>>> has the Default_Iterator aspect (which gives the iterator to use).
>>>
>>> I can hear the head slap from here. ;-)
>>
>> Yes, but;
>>
>>      1. with Ada.Text_IO;
>>      2. with F552A00_Prime_Numbers;
>>      3. procedure Primes is
>>      4. begin
>>      5.    for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 
>> 31) loop
>>                                                           |
>>         >>> expected a discrete type
>>         >>> found type "Prime_Number_Set" defined at
>>         >>> f552a00_prime_numbers.ads:74
>>
>>      6.       Ada.Text_IO.Put_Line (P'Img);
>>      7.    end loop;
>>      8. end Primes;
>>
>> Perhaps this is the GNAT problem you spoke of? (FSF GCC 5.1.0, GNAT GPL 
>> 2015)
>
> Oh, it should have been
>
>   for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 
> 31).Iterate
>      loop

I probably would have made type Prime_Number_Set directly the iterator type 
(I don't see any other need for it), which would get rid of the need for the 
".Iterate". An iterator doesn't necessarily have to have anything to do with 
a container!

                               Randy.


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

* Re: A few questions
  2015-11-12 18:32               ` Randy Brukardt
@ 2015-11-12 20:02                 ` Simon Wright
  2015-11-12 21:08                   ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Simon Wright @ 2015-11-12 20:02 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Simon Wright" <simon@pushface.org> wrote in message 
> news:lyziyskeu2.fsf@pushface.org...

>> Oh, it should have been
>>
>>   for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value => 
>> 31).Iterate
>>      loop
>
> I probably would have made type Prime_Number_Set directly the iterator
> type (I don't see any other need for it), which would get rid of the
> need for the ".Iterate". An iterator doesn't necessarily have to have
> anything to do with a container!

Hmm.

A Prime_Number_Set is a new Prime_Number_Iterator.Forward_Iterator;
Iterate returns a Prime_Number_Iterator.Forward_Iterator'Class.

I tried without the .Iterate, as before, and with

   for P in Prime_Number_Set'Class (Prime_Number_Set'(Max_Value => 30))

(just in case) and as before got the 'expected a discrete type' error.

Perhaps this is a GNAT bug?

On the other hand, why did Brad include function Iterate?

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

* Re: A few questions
  2015-11-12 18:28             ` Randy Brukardt
@ 2015-11-12 20:19               ` Simon Wright
  2015-11-12 20:56               ` Dmitry A. Kazakov
  2015-11-13  8:45               ` briot.emmanuel
  2 siblings, 0 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-12 20:19 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> <briot.emmanuel@gmail.com> wrote in message 
> news:aa0cf839-651e-494d-a826-c2ce31a7afd3@googlegroups.com...
>>> The "of" form is for iterating over an array or a container whose
>>> type has the Default_Iterator aspect (which gives the iterator to
>>> use).
>>
>> The main drawback, though, is that you then get a Cursor, not an
>> Element, so you still need to call the functions Element or Reference
>> to get to the actual element. This is slightly less convenient
>> (syntax-wise).
>
> Sure, but not in a case like the OP's, where the "cursor" is the
> actual data and there is no element. In that case, "of" is just
> overkill.

There's one problem for Times; how to determine when to end the loop if
the cursor is the actual data?

I ended up with

   type Cursor (Valid : Boolean := True) is record
      case Valid is
         when True =>
            Date : Ada.Calendar.Time;
         when False =>
            null;
      end case;
   end record;

where both First and Next set Valid to False if the iteration has ended.

I spent a lot too much time without giving Valid a default value; there
is an assignment, but it's hidden inside the generated code, so at the
end of the loop the discriminant changes ...

I think this may be related to the way that F552A00_Prime_Numbers
doesn't support an upper bound of 2; the loop terminates when Is_Prime
returns false, and of course 2 + 1 = 3 which .. Is_Prime.


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

* Re: A few questions
  2015-11-12 18:28             ` Randy Brukardt
  2015-11-12 20:19               ` Simon Wright
@ 2015-11-12 20:56               ` Dmitry A. Kazakov
  2015-11-12 21:15                 ` Randy Brukardt
  2015-11-13  8:45               ` briot.emmanuel
  2 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-12 20:56 UTC (permalink / raw)


On Thu, 12 Nov 2015 12:28:46 -0600, Randy Brukardt wrote:

> Personally, I find the "of" form unnecessary; we've iterated arrays for 
> decades without direct access to the element (using the "cursor", that is 
> the array index), so why are containers different?

Of course it is different. Index does not iterate array, it does the
array's index range. That is the difference.

You can iterate elements of a container or indices of a container. It is
not same.

> Especially as the 
> indexing form works on all of the language-defined containers (you never 
> need to explicitly call Reference or Element). So an "in" iterator looks 
> just like the array iteration that we've been using from the beginning of 
> time. What's so hard about that?

There could be cases when a container does not have any natural index. E.g.
a bag, a set, a files directory etc. You could iterate elements of without
inventing indices. Especially when the index is volatile. Consider an
implementation that gets a result set of a DB query and then iterates the
result.

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

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

* Re: A few questions
  2015-11-12 20:02                 ` Simon Wright
@ 2015-11-12 21:08                   ` Randy Brukardt
  2015-11-15 17:56                     ` Brad Moore
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-12 21:08 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly4mgrj8ab.fsf@pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> "Simon Wright" <simon@pushface.org> wrote in message
>> news:lyziyskeu2.fsf@pushface.org...
>
>>> Oh, it should have been
>>>
>>>   for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value =>
>>> 31).Iterate
>>>      loop
>>
>> I probably would have made type Prime_Number_Set directly the iterator
>> type (I don't see any other need for it), which would get rid of the
>> need for the ".Iterate". An iterator doesn't necessarily have to have
>> anything to do with a container!
>
> Hmm.
>
> A Prime_Number_Set is a new Prime_Number_Iterator.Forward_Iterator;
> Iterate returns a Prime_Number_Iterator.Forward_Iterator'Class.
>
> I tried without the .Iterate, as before, and with
>
>   for P in Prime_Number_Set'Class (Prime_Number_Set'(Max_Value => 30))
>
> (just in case) and as before got the 'expected a discrete type' error.

It should work either way. But does it work if you write:

   for P in Prime_Number_Iterator.Forward_Iterator'Class 
(Prime_Number_Set'(Max_Value => 30))

?? If so, GNAT surely has a bug (the type conversion shouldn't change 
anything). You could also try:

   for P in 
Prime_Number_Iterator.Forward_Iterator'(Prime_Number_Set'(Max_Value => 30))

which also shouldn't change anything.

> Perhaps this is a GNAT bug?

Looks like it to me.

> On the other hand, why did Brad include function Iterate?

It appears that he wanted tracing of the initialization (as that is all it 
does other than making a new iterator that is a copy of the first). It 
shouldn't be necessary.

                                          Randy.



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

* Re: A few questions
  2015-11-12 20:56               ` Dmitry A. Kazakov
@ 2015-11-12 21:15                 ` Randy Brukardt
  2015-11-13  8:40                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-12 21:15 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:hs9mu83acmqt$.5liwfglzrr7q.dlg@40tude.net...
> On Thu, 12 Nov 2015 12:28:46 -0600, Randy Brukardt wrote:
>
>> Personally, I find the "of" form unnecessary; we've iterated arrays for
>> decades without direct access to the element (using the "cursor", that is
>> the array index), so why are containers different?
>
> Of course it is different. Index does not iterate array, it does the
> array's index range. That is the difference.
>
> You can iterate elements of a container or indices of a container. It is
> not same.

Surely it is not the same. But why do we need the first? An array is surely 
a container, and we got along just fine for 30 years without being able to 
iterate elements of arrays. There is absolutely no difference for any other 
sort of container (especially as the array syntax can be used for any 
container).

Iterating on elements of a container is unnecessary overkill. (It's also 
harmless overkill, unlike, say, anonymous access types).

>> Especially as the
>> indexing form works on all of the language-defined containers (you never
>> need to explicitly call Reference or Element). So an "in" iterator looks
>> just like the array iteration that we've been using from the beginning of
>> time. What's so hard about that?
>
> There could be cases when a container does not have any natural index. 
> E.g.
> a bag, a set, a files directory etc. You could iterate elements of without
> inventing indices. Especially when the index is volatile. Consider an
> implementation that gets a result set of a DB query and then iterates the
> result.

There is always *something* that works as an index. If there isn't, you 
can't iterate (because you can't figure out a reproducible order for which 
item is next). In any case, Ada does not support iteration without something 
being a cursor; the "of" form of iteration is a direct translation of the 
"in" form of iteration (it's purely syntactic with no semantics of its own).

                                              Randy.



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

* Re: A few questions
  2015-11-12 21:15                 ` Randy Brukardt
@ 2015-11-13  8:40                   ` Dmitry A. Kazakov
  2015-11-13 17:52                     ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-13  8:40 UTC (permalink / raw)


On Thu, 12 Nov 2015 15:15:45 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:hs9mu83acmqt$.5liwfglzrr7q.dlg@40tude.net...
>> On Thu, 12 Nov 2015 12:28:46 -0600, Randy Brukardt wrote:
>>
>>> Personally, I find the "of" form unnecessary; we've iterated arrays for
>>> decades without direct access to the element (using the "cursor", that is
>>> the array index), so why are containers different?
>>
>> Of course it is different. Index does not iterate array, it does the
>> array's index range. That is the difference.
>>
>> You can iterate elements of a container or indices of a container. It is
>> not same.
> 
> Surely it is not the same. But why do we need the first?

For doing this:

   for Line in Read (Text_File) loop
       ...
   end loop;

Operation Read provides an iterateable container-view of Text_File. There
cannot be any index, because the "buffer" will contain just single line. 

Providing index will be error-prone and cause run-time overhead (index
checks). Add here naming issues, you need a name for the container-view:

   for Line_No in Read (Text_File) loop
       declare
           Next_Line : String := ??? (Index + 1);  -- Oops!
       begin
           ...
       end;
   end loop;

An array interface would promise more than there actually is. It would be
bad design.

> An array is surely 
> a container, and we got along just fine for 30 years without being able to 
> iterate elements of arrays.

Not every container is an array. There are lots of containers which
semantically have no index.

> There is absolutely no difference for any other 
> sort of container (especially as the array syntax can be used for any 
> container).

It cannot be, e.g. for a general case graph, but that is another story.

> Iterating on elements of a container is unnecessary overkill. (It's also 
> harmless overkill, unlike, say, anonymous access types).
> 
>>> Especially as the
>>> indexing form works on all of the language-defined containers (you never
>>> need to explicitly call Reference or Element). So an "in" iterator looks
>>> just like the array iteration that we've been using from the beginning of
>>> time. What's so hard about that?
>>
>> There could be cases when a container does not have any natural index. E.g.
>> a bag, a set, a files directory etc. You could iterate elements of without
>> inventing indices. Especially when the index is volatile. Consider an
>> implementation that gets a result set of a DB query and then iterates the
>> result.
> 
> There is always *something* that works as an index. If there isn't, you 
> can't iterate (because you can't figure out a reproducible order for which 
> item is next).

First, index is more than iteration. Index assumes random access and an
ability to access any number of times. Iteration requires only sequential
access and only visit once. If you equate both, you either burden the
implementation with unnecessary functionality or the clients in order to
catch unsupported actions. Not good.

Secondly, it is an implementation driven view. The problem space may have
no index even when the implementation could have one. Exposing
implementation details is bad.

> In any case, Ada does not support iteration without something 
> being a cursor; the "of" form of iteration is a direct translation of the 
> "in" form of iteration (it's purely syntactic with no semantics of its own).

Yes, Ada has a lot of issues with abstract interfaces.

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

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

* Re: A few questions
  2015-11-12 18:28             ` Randy Brukardt
  2015-11-12 20:19               ` Simon Wright
  2015-11-12 20:56               ` Dmitry A. Kazakov
@ 2015-11-13  8:45               ` briot.emmanuel
  2015-11-13 17:41                 ` Randy Brukardt
  2 siblings, 1 reply; 73+ messages in thread
From: briot.emmanuel @ 2015-11-13  8:45 UTC (permalink / raw)


On Thursday, November 12, 2015 at 7:28:49 PM UTC+1, Randy Brukardt wrote:
> That doesn't make sense, though, as the iterator interface doesn't contain 
> the information necessary to do "of" iteration. In particular, it doesn't 
> provide the container or Reference function -- nor could it, as there may 
> not be a container.

Absolutely, we cannot do that with Ada, as defined in the standard. But that's
exactly what I am complaining about. The aspects should have been defined
on the Iterator, not on the container itself, as in:

    type Graph is tagged private
         with Default_Iterator => Depth_First_Search;

    type DFS_Iterator is private
         with Reference => Reference,
                 Iterator_Element => Element_Tye;
    function Depth_First_Search (Self : Graph) return DFS_Iterator;

    type BFS_Iterator is private
         with Reference => Reference,
                 Iterator_Element => Element_Tye;
    function Breadth_First_Search (Self : Graph) return BFS_Iterator;

With such a separation, I could then do something like:

    G : Graph;

    for E of G loop    --  depth first search
        null;
    end loop;

    for E of G.Breadth_First_Search loop   --  breadth first search, get element
        null;
    end loop;

    for C in G.Breadth_First_Search loop   --  breadth first search, get cursor
        null;
    end loop;

The aspects were put at the wrong level, and iterators end up being hidden
magical objects, rather than first class citizens with their own role in the
design of containers.


> Personally, I find the "of" form unnecessary; we've iterated arrays for 
> decades without direct access to the element (using the "cursor", that is 
> the array index), so why are containers different? Especially as the 
> indexing form works on all of the language-defined containers (you never 
> need to explicitly call Reference or Element). So an "in" iterator looks 
> just like the array iteration that we've been using from the beginning of 
> time. What's so hard about that?

There are lots of things we have been doing for decades. We have been
inserting explicit tests and asserts, and now we are adding pre and post
conditions, just to find one example. Languages evolve, as you well know
of course, and the goal is to make them more expressive. I like to clearly
state what I mean in the code, but on the other hand why should I have
to specify "Element (C)" when I can just use "E" ?



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

* Re: A few questions
  2015-11-13  8:45               ` briot.emmanuel
@ 2015-11-13 17:41                 ` Randy Brukardt
  2015-11-14 19:57                   ` briot.emmanuel
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-13 17:41 UTC (permalink / raw)



<briot.emmanuel@gmail.com> wrote in message 
news:db3ea03a-07cc-4f1a-96aa-a7a18d5e2145@googlegroups.com...
> On Thursday, November 12, 2015 at 7:28:49 PM UTC+1, Randy Brukardt wrote:
>> That doesn't make sense, though, as the iterator interface doesn't 
>> contain
>> the information necessary to do "of" iteration. In particular, it doesn't
>> provide the container or Reference function -- nor could it, as there may
>> not be a container.
>
> Absolutely, we cannot do that with Ada, as defined in the standard. But 
> that's
> exactly what I am complaining about. The aspects should have been defined
> on the Iterator, not on the container itself, as in:
>
>    type Graph is tagged private
>         with Default_Iterator => Depth_First_Search;
>
>    type DFS_Iterator is private
>         with Reference => Reference,
>                 Iterator_Element => Element_Tye;
>    function Depth_First_Search (Self : Graph) return DFS_Iterator;
>
>    type BFS_Iterator is private
>         with Reference => Reference,
>                 Iterator_Element => Element_Tye;
>    function Breadth_First_Search (Self : Graph) return BFS_Iterator;
>
> With such a separation, I could then do something like:

No, you couldn't, because there still is no way for the compiler to identify 
the container to pass to the Reference aspect.

If you mean to magically extract it from the call to Depth_First_Search, I 
would be strongly against as there is no need for an actual container object 
for an iterator (and the model specifically was designed to allow that 
possibility). It would be *much* more limiting to assume a container.

I suppose you could add a third aspect to specify which parameter is the 
container, and then use additional magic to add a renames of that parameter 
(with all of the attendant restrictions on what that parameter could be). 
Definitely a lot more complicated than what we have (and what we have is too 
complicated).

>    for E of G.Breadth_First_Search loop   --  breadth first search, get 
> element
>        null;
>    end loop;

Again, how does the compiler know that G is the container in this iterator? 
"G.Breadth_First_Search" is just a function call. On top of which, you now 
have two different and unrelated expected types for the iterator, which 
would be a new concept in Ada.

> The aspects were put at the wrong level, and iterators end up being hidden
> magical objects, rather than first class citizens with their own role in 
> the
> design of containers.

Well, I disagree. The iterators are certainly a first-class type, so long as 
you use the "in" form. And it's impossible to use the "of" form for all 
possible iterations; it's way too limiting for the general case.

>> Personally, I find the "of" form unnecessary; we've iterated arrays for
>> decades without direct access to the element (using the "cursor", that is
>> the array index), so why are containers different? Especially as the
>> indexing form works on all of the language-defined containers (you never
>> need to explicitly call Reference or Element). So an "in" iterator looks
>> just like the array iteration that we've been using from the beginning of
>> time. What's so hard about that?
>
> There are lots of things we have been doing for decades. We have been
> inserting explicit tests and asserts, and now we are adding pre and post
> conditions, just to find one example. Languages evolve, as you well know
> of course, and the goal is to make them more expressive.

Umm, no, the goal is to provide new capabilities to allow Ada to solve 
additional problems. (Pre and Post are definitely new capabilities - see the 
class-wide versions and 'Old; pragma Assert was too much of a blunt 
instrument to be of much use.)

Making a language "more expressive" is code for "easier to write", which 
never was a goal of Ada. To the extent that we've made the language "more 
expressive", it's been to make ADTs more like the capabilities of the 
built-in types (for instance, arrays). Going beyond that is unnecessary and 
probably harmful.

> I like to clearly
> state what I mean in the code, but on the other hand why should I have
> to specify "Element (C)" when I can just use "E" ?

Readability, of course. I don't believe that you should ever have been 
allowed to just specify E. I lost that argument 'cause it wasn't 
sufficiently evil to waste scarce political capital on, but I don't see any 
reason to expand the evil, or worry because it doesn't work in some cases. 
(That was clearly understood when we defined it; it was intended to be a 
quicky shorthand, not the way to do most iterations.)

                     Randy.



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

* Re: A few questions
  2015-11-13  8:40                   ` Dmitry A. Kazakov
@ 2015-11-13 17:52                     ` Randy Brukardt
  2015-11-13 20:37                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-13 17:52 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1dolqizyi8gxi.t3173bhifuu1.dlg@40tude.net...
> On Thu, 12 Nov 2015 15:15:45 -0600, Randy Brukardt wrote:
...
>> Surely it is not the same. But why do we need the first?
>
> For doing this:
>
>   for Line in Read (Text_File) loop
>       ...
>   end loop;

Note that you used "in" rather than "of" here. And if you did that, there is 
no problem implementing this in the existing Ada, even as you suggest.

...
> Operation Read provides an iterateable container-view of Text_File. There
> cannot be any index, because the "buffer" will contain just single line.

A "cursor" is not necessarily an array index, as I pointed out earlier in 
this thread. For anything "on demand", the cursor probably ought to be the 
data itself. (You'd probably have to use an unbounded string for that, but 
that's a different problem unrelated to iteration.)

...
>> An array is surely
>> a container, and we got along just fine for 30 years without being able 
>> to
>> iterate elements of arrays.
>
> Not every container is an array. There are lots of containers which
> semantically have no index.

Then provide an iterator implementation where the cursor is an access to the 
element.

...
>> There is always *something* that works as an index. If there isn't, you
>> can't iterate (because you can't figure out a reproducible order for 
>> which
>> item is next).
>
> First, index is more than iteration. Index assumes random access and an
> ability to access any number of times. Iteration requires only sequential
> access and only visit once. If you equate both, you either burden the
> implementation with unnecessary functionality or the clients in order to
> catch unsupported actions. Not good.

You are giving more properties than necessary to an iteration cursor (which 
is what we are talking about). There is absolutely no problem with it 
providing sequential one-time access. You have to program it that way, of 
course, but it's not hard to do (see the implementation in the ACATS, for 
one example).

I might have confused you by calling it an "index", because it's clear that 
you're assigning properties to it that I am not. There's no reason that you 
have to use a for loop parameter as an index! (I often write traditional 
loops where the loop parameter is not an index.)

> Secondly, it is an implementation driven view. The problem space may have
> no index even when the implementation could have one. Exposing
> implementation details is bad.

That's the Bag arrgument again. I think that particular data structure is a 
fraud, because it cannot be created in practice -- plus you have to have 
some sort of access to the elements, so you end up with a cursor of some 
sort anyway. There's a reason there is no Bag in the Ada.Containers library!

              Randy.


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

* Re: A few questions
  2015-11-13 17:52                     ` Randy Brukardt
@ 2015-11-13 20:37                       ` Dmitry A. Kazakov
  2015-11-13 22:15                         ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-13 20:37 UTC (permalink / raw)


On Fri, 13 Nov 2015 11:52:29 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1dolqizyi8gxi.t3173bhifuu1.dlg@40tude.net...
>> On Thu, 12 Nov 2015 15:15:45 -0600, Randy Brukardt wrote:
> ...
>>> Surely it is not the same. But why do we need the first?
>>
>> For doing this:
>>
>>   for Line in Read (Text_File) loop
>>       ...
>>   end loop;
> 
> Note that you used "in" rather than "of" here.

Yes, because Ada always had this syntax for iterating elements of a set. It
is:

   for I in A'Range loop

It is not

   for I in A loop

If the later were legal then loop parameter must have been a pair (Index,
Element), because that is what an array is: a set of pairs.

[ "of" is rubbish of course. It is "in" that iterates / enumerates a set.
If "of" should ever be used then for something else. ]

> And if you did that, there is 
> no problem implementing this in the existing Ada, even as you suggest.

I am not sure about that.

>> Operation Read provides an iterateable container-view of Text_File. There
>> cannot be any index, because the "buffer" will contain just single line.
> 
> A "cursor" is not necessarily an array index, as I pointed out earlier in 
> this thread.

Array does not contain "cursors." Cursor is an evil idea, but that is
unrelated to the issue of iteration over a general set.

>>> An array is surely
>>> a container, and we got along just fine for 30 years without being able 
>>> to iterate elements of arrays.
>>
>> Not every container is an array. There are lots of containers which
>> semantically have no index.
> 
> Then provide an iterator implementation where the cursor is an access to the 
> element.

Why do I need extra data types, bad types as they involve pointers?

>>> There is always *something* that works as an index. If there isn't, you
>>> can't iterate (because you can't figure out a reproducible order for 
>>> which
>>> item is next).
>>
>> First, index is more than iteration. Index assumes random access and an
>> ability to access any number of times. Iteration requires only sequential
>> access and only visit once. If you equate both, you either burden the
>> implementation with unnecessary functionality or the clients in order to
>> catch unsupported actions. Not good.
> 
> You are giving more properties than necessary to an iteration cursor (which 
> is what we are talking about). There is absolutely no problem with it 
> providing sequential one-time access. You have to program it that way, of 
> course, but it's not hard to do (see the implementation in the ACATS, for 
> one example).

Maybe yes, maybe no. But cursor is neither index nor element. Cursor is
same as a pointer.

> I might have confused you by calling it an "index", because it's clear that 
> you're assigning properties to it that I am not. There's no reason that you 
> have to use a for loop parameter as an index! (I often write traditional 
> loops where the loop parameter is not an index.)
> 
>> Secondly, it is an implementation driven view. The problem space may have
>> no index even when the implementation could have one. Exposing
>> implementation details is bad.
> 
> That's the Bag arrgument again. I think that particular data structure is a 
> fraud, because it cannot be created in practice -- plus you have to have 
> some sort of access to the elements, so you end up with a cursor of some 
> sort anyway.

No way. The bag is a set that only supports insertion and iteration.
Nothing more. It is very useful, e.g. to hold strong references to
allocated data. References are thrown into a bag. At some point the bag is
iterated and all references invalidated releasing resources.

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


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

* Re: A few questions
  2015-11-13 20:37                       ` Dmitry A. Kazakov
@ 2015-11-13 22:15                         ` Randy Brukardt
  2015-11-14 11:42                           ` Dmitry A. Kazakov
  2015-11-14 12:37                           ` Simon Wright
  0 siblings, 2 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-13 22:15 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1705bpj6jrld0.1lc44o5yo6bj7$.dlg@40tude.net...
> On Fri, 13 Nov 2015 11:52:29 -0600, Randy Brukardt wrote:
...
>> And if you did that, there is
>> no problem implementing this in the existing Ada, even as you suggest.
>
> I am not sure about that.

I am. :-)

You'd probably keep some state in the iterator object (some access to the 
file, at a minimum, possibly a buffer). The "cursor" would be the character. 
Each call to Next would put the following character into the "cursor". 
Easy-peasy. :-)

Thinking of an iterator "cursor" as having to be some sort of index obscures 
the real possibilities of the interface.

>>> Operation Read provides an iterateable container-view of Text_File. 
>>> There
>>> cannot be any index, because the "buffer" will contain just single line.
>>
>> A "cursor" is not necessarily an array index, as I pointed out earlier in
>> this thread.
>
> Array does not contain "cursors." Cursor is an evil idea, but that is
> unrelated to the issue of iteration over a general set.

We're not talking about arrays, we're talking about iteration. And for this 
purpose, "cursor" could just as well be called "blob". It's a type parameter 
to the interface, nothing more. One might give it additional semantics for 
some particular implementation, but that's not inherent in the model.

>>>> An array is surely
>>>> a container, and we got along just fine for 30 years without being able
>>>> to iterate elements of arrays.
>>>
>>> Not every container is an array. There are lots of containers which
>>> semantically have no index.
>>
>> Then provide an iterator implementation where the cursor is an access to 
>> the
>> element.
>
> Why do I need extra data types, bad types as they involve pointers?

An iterator is an extra data type. And you surely don't need to involve 
pointers, if copying the element is OK. If you want to modify the element in 
place, then some sort of pointer is always required (outside of the built-in 
array type).

...
...
>> You are giving more properties than necessary to an iteration cursor 
>> (which
>> is what we are talking about). There is absolutely no problem with it
>> providing sequential one-time access. You have to program it that way, of
>> course, but it's not hard to do (see the implementation in the ACATS, for
>> one example).
>
> Maybe yes, maybe no. But cursor is neither index nor element. Cursor is
> same as a pointer.

Definitely not, in the iterator interface. It is anything you want it to be. 
Surely, for discrete unmodifiable values, it's better that the "cursor" be 
directly that value. (The read from a file example, the prime numbers 
example, and the OPs example all have this property.) "Cursor" is just the 
name of the type in the generic interface. Just because it has that name 
(and is commonly used as an index), doesn't mean that it always has to be 
used that way.

...
>> That's the Bag arrgument again. I think that particular data structure is 
>> a
>> fraud, because it cannot be created in practice -- plus you have to have
>> some sort of access to the elements, so you end up with a cursor of some
>> sort anyway.
>
> No way. The bag is a set that only supports insertion and iteration.
> Nothing more. It is very useful, e.g. to hold strong references to
> allocated data. References are thrown into a bag. At some point the bag is
> iterated and all references invalidated releasing resources.

Your description points out the problem: it's "a set", at which point a set 
implementation is appropriate. And the implementation is identical to any 
other set, so there is almost no value to having a separate bag 
implementation (it provides no performance improvements over an ordered set, 
for instance).

Whether its useful or not is irrelevant -- it is indistiguishable from any 
other set (the extra operations having no effect or overhead if not used). 
So there is no real value to having a separate Bag abstraction.

                                         Randy.


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

* Re: A few questions
  2015-11-13 22:15                         ` Randy Brukardt
@ 2015-11-14 11:42                           ` Dmitry A. Kazakov
  2015-11-14 12:37                           ` Simon Wright
  1 sibling, 0 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-14 11:42 UTC (permalink / raw)


On Fri, 13 Nov 2015 16:15:01 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1705bpj6jrld0.1lc44o5yo6bj7$.dlg@40tude.net...
>> On Fri, 13 Nov 2015 11:52:29 -0600, Randy Brukardt wrote:
> ...
>>> And if you did that, there is
>>> no problem implementing this in the existing Ada, even as you suggest.
>>
>> I am not sure about that.
> 
> I am. :-)
> 
> You'd probably keep some state in the iterator object (some access to the 
> file, at a minimum, possibly a buffer). The "cursor" would be the character. 
> Each call to Next would put the following character into the "cursor". 
> Easy-peasy. :-)

It would be nice to see a demonstration for iterating lines of a text
file... (:-))

>>>>> An array is surely
>>>>> a container, and we got along just fine for 30 years without being able
>>>>> to iterate elements of arrays.
>>>>
>>>> Not every container is an array. There are lots of containers which
>>>> semantically have no index.
>>>
>>> Then provide an iterator implementation where the cursor is an access to 
>>> the element.
>>
>> Why do I need extra data types, bad types as they involve pointers?
> 
> An iterator is an extra data type. And you surely don't need to involve 
> pointers, if copying the element is OK.

And a pointer to the container.

>>> That's the Bag arrgument again. I think that particular data structure is a
>>> fraud, because it cannot be created in practice -- plus you have to have
>>> some sort of access to the elements, so you end up with a cursor of some
>>> sort anyway.
>>
>> No way. The bag is a set that only supports insertion and iteration.
>> Nothing more. It is very useful, e.g. to hold strong references to
>> allocated data. References are thrown into a bag. At some point the bag is
>> iterated and all references invalidated releasing resources.
> 
> Your description points out the problem: it's "a set", at which point a set 
> implementation is appropriate. And the implementation is identical to any 
> other set, so there is almost no value to having a separate bag 
> implementation (it provides no performance improvements over an ordered set, 
> for instance).

A bag need not to be sorted, no overhead to keep the order, no need for
elements to have "=" and "<".

> Whether its useful or not is irrelevant -- it is indistiguishable from any 
> other set (the extra operations having no effect or overhead if not used). 

It is. The implementation will likely choose a singly linked list of
element buckets.

> So there is no real value to having a separate Bag abstraction.

Even if the implementation were same, abstraction is called abstraction
because it is not implementation.

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


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

* Re: A few questions
  2015-11-13 22:15                         ` Randy Brukardt
  2015-11-14 11:42                           ` Dmitry A. Kazakov
@ 2015-11-14 12:37                           ` Simon Wright
  2015-11-14 17:24                             ` Shark8
  2015-11-15 18:54                             ` Brad Moore
  1 sibling, 2 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-14 12:37 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> You'd probably keep some state in the iterator object (some access to
> the file, at a minimum, possibly a buffer). The "cursor" would be the
> character.  Each call to Next would put the following character into
> the "cursor".  Easy-peasy. :-)

It's a pity that Next takes the iterator object as an 'in'
parameter. This means that, in general, the cursor needs to hold the
state. It certainly needs some way of indicating end-of-iteration;
perhaps a sentinel value.

Can I use the same iterator more than once? (so long as the container
hasn't changed, of course - I expect that would count as tampering,
though) If so, that'd explain why Next.Object is an in parameter!


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

* Re: A few questions
  2015-11-14 12:37                           ` Simon Wright
@ 2015-11-14 17:24                             ` Shark8
  2015-11-14 20:09                               ` Simon Wright
  2015-11-15 18:54                             ` Brad Moore
  1 sibling, 1 reply; 73+ messages in thread
From: Shark8 @ 2015-11-14 17:24 UTC (permalink / raw)


On Saturday, November 14, 2015 at 5:37:32 AM UTC-7, Simon Wright wrote:
> 
> It's a pity that Next takes the iterator object as an 'in'
> parameter. This means that, in general, the cursor needs to hold the
> state. It certainly needs some way of indicating end-of-iteration;
> perhaps a sentinel value.

Sentinel values, or exceptions?
C-style strings use ASCII.NUL as a sentinel value, and look at the trouble that causes. (Of course part of that is due to the anemic idea of arrays that C has.)

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

* Re: A few questions
  2015-11-13 17:41                 ` Randy Brukardt
@ 2015-11-14 19:57                   ` briot.emmanuel
  2015-11-16 19:13                     ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: briot.emmanuel @ 2015-11-14 19:57 UTC (permalink / raw)


> No, you couldn't, because there still is no way for the compiler to identify 
> the container to pass to the Reference aspect.

You seem to be mixing the particular implementation you would use with
what the standard should allow. There is nothing in the spec of a reference
type that mandates knowing the container (and the way it currently is done
in the implementations is to use a 'Unrestricted_Access, which is ugly to
say the least).

> If you mean to magically extract it from the call to Depth_First_Search, I 
> would be strongly against as there is no need for an actual container object 
> for an iterator (and the model specifically was designed to allow that 
> possibility). It would be *much* more limiting to assume a container.

If I want my iterator to implement depth_first_search, it would indeed need to
know the container (like most iterators would need to know the container,
in fact). The reference type itself (the end product of the iteration) doesn't
need to know that though. The container is necessary for the iteration or
traversal of itself, but certainly not once you manipulate an element.

My example assumed nothing.

The implementation you seem to have in your head seems indeed to assume
a lot of unnecessary things.


> Definitely a lot more complicated than what we have (and what we have is too 
> complicated).

What we have is both too complicated and too limited. Too complicated because
nobody that hasn't spent a full week will be able to explain how the aspects
combine with iterators to end up with cursors and the for-of loop. They just
happen to work for existing containers, but as this thread has proven, anyone
who tries to actually implement them for other uses that the few official
containers quickly hits sever limitations.


> 
> >    for E of G.Breadth_First_Search loop   --  breadth first search, get 
> > element
> >        null;
> >    end loop;
> 
> Again, how does the compiler know that G is the container in this iterator? 
> "G.Breadth_First_Search" is just a function call. On top of which, you now 
> have two different and unrelated expected types for the iterator, which 
> would be a new concept in Ada.

It is a function call that returns the iterator. So obviously it is allowed to have
a relationship between the return value and the parameters. The iterator
is therefore allowed (but not mandated, that would depend on the actual
container we are talking about) to have a reference to the container.
This is called flexibility. Something lacking in the current standard.

I do not understand your last sentence about the two unexpected types.

> Making a language "more expressive" is code for "easier to write", which 
> never was a goal of Ada.

That's one of the issue here. The goal for Ada, as I understand it, has always
been to be "easier to read". There is no reason why "easier to write" should
be in opposition to that goal.

> > I like to clearly
> > state what I mean in the code, but on the other hand why should I have
> > to specify "Element (C)" when I can just use "E" ?
> 
> Readability, of course. I don't believe that you should ever have been 
> allowed to just specify E. I lost that argument 'cause it wasn't 
> sufficiently evil to waste scarce political capital on, but I don't see any 

Now I understand. You are re-fighting a fight you lost apparently. But from
talking to all my colleagues (all of whom are of course Ada experts), we all
much prefer the form with just "E" in practice. So that change was a great
improvement in the standard, if not quite wide reaching enough.

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

* Re: A few questions
  2015-11-14 17:24                             ` Shark8
@ 2015-11-14 20:09                               ` Simon Wright
  0 siblings, 0 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-14 20:09 UTC (permalink / raw)


Shark8 <onewingedshark@gmail.com> writes:

> On Saturday, November 14, 2015 at 5:37:32 AM UTC-7, Simon Wright wrote:
>> 
>> It's a pity that Next takes the iterator object as an 'in'
>> parameter. This means that, in general, the cursor needs to hold the
>> state. It certainly needs some way of indicating end-of-iteration;
>> perhaps a sentinel value.
>
> Sentinel values, or exceptions?  C-style strings use ASCII.NUL as a
> sentinel value, and look at the trouble that causes. (Of course part
> of that is due to the anemic idea of arrays that C has.)

Next (Iterator, Cursor) return Cursor is the operation that would detect
End_Of_File or whatever and indicate in the result Cursor that the
iteration had ended. Although it would indeed quit the loop, I don't
think using an exception would be good (especially in a restricted
runtime without exception propagation).

If no sentinel value is possible, you're stuck (I think) with

   type Cursor (Running : Boolean := True) is record
      case Running is
         when True  => Element : Whatever;
         when False => null;
      end case;
   end record;
   


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

* Re: A few questions
  2015-11-12 21:08                   ` Randy Brukardt
@ 2015-11-15 17:56                     ` Brad Moore
  2015-11-15 21:42                       ` Simon Wright
  2015-11-16 19:16                       ` Randy Brukardt
  0 siblings, 2 replies; 73+ messages in thread
From: Brad Moore @ 2015-11-15 17:56 UTC (permalink / raw)


On Thursday, November 12, 2015 at 2:08:54 PM UTC-7, Randy Brukardt wrote:
> "Simon Wright" <simon@pushface.org> wrote in message 
> news:ly4mgrj8ab.fsf@pushface.org...
> > "Randy Brukardt" <randy@rrsoftware.com> writes:
> >
> >> "Simon Wright" <simon@pushface.org> wrote in message
> >> news:lyziyskeu2.fsf@pushface.org...
> >
> >>> Oh, it should have been
> >>>
> >>>   for P in F552A00_Prime_Numbers.Prime_Number_Set'(Max_Value =>
> >>> 31).Iterate
> >>>      loop
> >>
> >> I probably would have made type Prime_Number_Set directly the iterator
> >> type (I don't see any other need for it), which would get rid of the
> >> need for the ".Iterate". An iterator doesn't necessarily have to have
> >> anything to do with a container!
> >
> > Hmm.
> >
> > A Prime_Number_Set is a new Prime_Number_Iterator.Forward_Iterator;
> > Iterate returns a Prime_Number_Iterator.Forward_Iterator'Class.
> >
> > I tried without the .Iterate, as before, and with
> >
> >   for P in Prime_Number_Set'Class (Prime_Number_Set'(Max_Value => 30))
> >
> > (just in case) and as before got the 'expected a discrete type' error.
> 
> It should work either way. But does it work if you write:
> 
>    for P in Prime_Number_Iterator.Forward_Iterator'Class 
> (Prime_Number_Set'(Max_Value => 30))

This doesn't work either

> 
> ?? If so, GNAT surely has a bug (the type conversion shouldn't change 
> anything). You could also try:
> 
>    for P in 
> Prime_Number_Iterator.Forward_Iterator'(Prime_Number_Set'(Max_Value => 30))

This doesn't work also.

However, if I declare the iterator as a declared object as in;

   Iterator : constant Prime_Number_Iterator.Forward_Iterator'Class :=
     Prime_Number_Set'(Max_Value => 30);

Then I can do this;

   for Prime in Iterator loop
      Put_Line (Integer'Image (Prime));   
   end loop;

However, if I declare it this way...

   Iterator : constant Prime_Number_Set :=
     Prime_Number_Set'(Max_Value => 30);

Then the loop above does not compile.

So it seems to me that there are some GNAT bugs in this area.

> 
> which also shouldn't change anything.
> 
> > Perhaps this is a GNAT bug?
> 
> Looks like it to me.
> 
> > On the other hand, why did Brad include function Iterate?
> 
> It appears that he wanted tracing of the initialization (as that is all it 
> does other than making a new iterator that is a copy of the first). It 
> shouldn't be necessary.

It's been a while since I wrote that example, and I'm not entirely sure why I did it that way, but to be honest, I think I started with the existing container iterators as my starting point example, which all have an Iterate function, and I may have just assumed I needed a function which returned an class-wide object.

If the Prime Number Iterator is useful as an example for others, it would be nice to eliminate the Iterate function from the example. It seems also that there should be some more tests written to cover the failure cases that we are discovering now. I'd be happy to update this ACATS test, if Randy thinks its worthwhile.

Brad


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

* Re: A few questions
  2015-11-14 12:37                           ` Simon Wright
  2015-11-14 17:24                             ` Shark8
@ 2015-11-15 18:54                             ` Brad Moore
  1 sibling, 0 replies; 73+ messages in thread
From: Brad Moore @ 2015-11-15 18:54 UTC (permalink / raw)


On Saturday, November 14, 2015 at 5:37:32 AM UTC-7, Simon Wright wrote:
> "Randy Brukardt" <randy@rrsoftware.com> writes:
> 
> > You'd probably keep some state in the iterator object (some access to
> > the file, at a minimum, possibly a buffer). The "cursor" would be the
> > character.  Each call to Next would put the following character into
> > the "cursor".  Easy-peasy. :-)
> 
> It's a pity that Next takes the iterator object as an 'in'
> parameter. This means that, in general, the cursor needs to hold the
> state. It certainly needs some way of indicating end-of-iteration;
> perhaps a sentinel value.

I found this to be a problem also. I have been working on an AI to potentially add iterators to Ada.Directories and Ada.Environment_Variables for consideration for Ada 202x (Ada 2019?). I was able to get a working implementation using both an Iterator approach, and an Iterable container approach. So far the Iterable container approach seems like a better choice here because it lets the programmer choose between either "in" or "of" syntax for the loops.
With the Iterator approach, you can only use "in" loops, although that's really not a big deal, in my opinion.

For both of these approaches, I found I also needed "in out" parameters for these interfaces. In fact, looking at my iterable container implementation it appears that First, Next, and Iterate all need to have 'in out' parameters. For Ada.Directories, it made sense to have the container contain a Search_Type component, and the Iterator type to contain a Directory_Entry component, which contains the current directory entry for the loop. The Next function needs to update its Directory_Entry component to get the next directory entry, so it needs read-write access.

I was able to work around this by using the Rosen trick to acquire read-write access to the "in" parameters for these functions. However, this is awkward, and it tells me that we have the wrong interfaces for iterators, or at least we have missing interfaces. One shouldn't have to jump through such hoops to write iterators for abstract data types.

Brad

> 
> Can I use the same iterator more than once? (so long as the container
> hasn't changed, of course - I expect that would count as tampering,
> though) If so, that'd explain why Next.Object is an in parameter!

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

* Re: A few questions
  2015-11-15 17:56                     ` Brad Moore
@ 2015-11-15 21:42                       ` Simon Wright
  2015-11-16 19:16                       ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-15 21:42 UTC (permalink / raw)


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

> However, if I declare it this way...
>
>    Iterator : constant Prime_Number_Set :=
>      Prime_Number_Set'(Max_Value => 30);
>
> Then the loop above does not compile.

Indeed, gives a GNAT bug box! (GPL 2015, 5.1.0, 6.0.0 all behave the same)

> So it seems to me that there are some GNAT bugs in this area.

Yes. I reported it on Saturday .. hoping for a response.


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

* Re: A few questions
  2015-11-14 19:57                   ` briot.emmanuel
@ 2015-11-16 19:13                     ` Randy Brukardt
  2015-11-16 20:47                       ` Dmitry A. Kazakov
                                         ` (2 more replies)
  0 siblings, 3 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-16 19:13 UTC (permalink / raw)


<briot.emmanuel@gmail.com> wrote in message 
news:5007b311-5d2e-448c-b8c8-fc2e2d88ea5e@googlegroups.com...
>> No, you couldn't, because there still is no way for the compiler to 
>> identify
>> the container to pass to the Reference aspect.
>
> You seem to be mixing the particular implementation you would use with
> what the standard should allow. There is nothing in the spec of a 
> reference
> type that mandates knowing the container (and the way it currently is done
> in the implementations is to use a 'Unrestricted_Access, which is ugly to
> say the least).

Huh? You are suggesting an alternative description for the existing 
iterators for the existing containers. (If you're suggesting anything else, 
you're wasting everybodies time, 'cause something that won't work with the 
existing containers is a non-starter.) And the Reference function in the 
existing containers (and in any container I can imagine) takes a container 
parameter. That parameter has to come from somewhere, and it can't come from 
the iterator interface (it doesn't include a container in the description). 
So where does it come from??

Since 'Unrestricted_Access is GNAT junk, it's doesn't have any value for a 
sample implementation (if you really need 'Unrestricted_Access, then the 
interface can't be implemented in Ada, and that would be a major problem.) 
So far as I know, you might need to use 'Unchecked_Access, but that's 
necessary anytime one needs to get a pointer to save the evaluated version 
of something. ('Access being useless for 98% of uses; I've only once in my 
entire programming career been able to use 'Access rather than 
'Unchecked_Access).

>> If you mean to magically extract it from the call to Depth_First_Search, 
>> I
>> would be strongly against as there is no need for an actual container 
>> object
>> for an iterator (and the model specifically was designed to allow that
>> possibility). It would be *much* more limiting to assume a container.
>
> If I want my iterator to implement depth_first_search, it would indeed 
> need to
> know the container (like most iterators would need to know the container,
> in fact). The reference type itself (the end product of the iteration) 
> doesn't
> need to know that though. The container is necessary for the iteration or
> traversal of itself, but certainly not once you manipulate an element.

You're speaking nonsense. The element is part of the container, and the only 
way to access it is from the container. You can't create a reference to an 
element of a container without having the container. But your proposed 
interface does not have the container anywhere. How does the reference get 
created???

> My example assumed nothing.

Your example is nonsense, IMHO.

> The implementation you seem to have in your head seems indeed to assume
> a lot of unnecessary things.

???

I'm mapping iteration onto the existing containers. That is straightforward 
with the existing description, but it's not possible with your proposed 
redefinition without some modifications. The current definition has a very 
specific expansion of shorthands into other, existing features. But that's 
not possible with your proposal. You seem to be expecting magic rather than 
explaining how to get from A to B, and that's not a possibility with the 
language standard.

>> Definitely a lot more complicated than what we have (and what we have is 
>> too
>> complicated).
>
> What we have is both too complicated and too limited. Too complicated 
> because
> nobody that hasn't spent a full week will be able to explain how the 
> aspects
> combine with iterators to end up with cursors and the for-of loop. They 
> just
> happen to work for existing containers, but as this thread has proven, 
> anyone
> who tries to actually implement them for other uses that the few official
> containers quickly hits sever limitations.

The limitations aren't that severe, and seem mostly to be related to having 
the iterator object be an "in" parameter. (That's probably happened because 
"in out" parameters on functions seem weird, but they clearly make more 
sense in this case.)

>> >    for E of G.Breadth_First_Search loop   --  breadth first search, get 
>> > element
>> >        null;
>> >    end loop;
>>
>> Again, how does the compiler know that G is the container in this 
>> iterator?
>> "G.Breadth_First_Search" is just a function call. On top of which, you 
>> now
>> have two different and unrelated expected types for the iterator, which
>> would be a new concept in Ada.
>
> It is a function call that returns the iterator. So obviously it is 
> allowed to have
> a relationship between the return value and the parameters. The iterator
> is therefore allowed (but not mandated, that would depend on the actual
> container we are talking about) to have a reference to the container.
> This is called flexibility. Something lacking in the current standard.

So the iterator has a reference to the container. How would it be used 
(references being something not related to iterators)? We certainly don't 
want to be introducing special reference routines *just* for iterators 
(that's the sort of extra complexity that would have never flown).

As for "flexibility", there is plenty; people just seem to have a lack of 
imagination about this interface (see my replies to Dmitry). I agree that it 
would have been better if the iterator parameters had been "in out", but 
that's about it. You're imagining "sever" problems -- Brad had pretty good 
results with the ACATS test and with the directory iterators. These things 
aren't expected to be easy to write -- hardly anyone should be doing that 
anyway (much like generics) -- ease of use is paramount.

> I do not understand your last sentence about the two unexpected types.

"for E of G loop" -- The expected type is a container with a 
Default_Iterator aspect.
"for E of G.Breadth_First_Search loop" -- The expected type is an iterator 
with a Default_Iterator aspect.

This is two different, unrelated expected types. One could solve that by 
making this context an "any type" context, and making the checking into 
Legality Rules, but that means that some expressions would not be allowed 
("any type" contexts having restrictions beyond those of other contexts). 
One could have not allowed the first form, but since that is the only thing 
people seemed to be asking for, I think that would have been a non-starter.

We discussed the question of whether we needed multiple iterators for the 
"of" form, and the decision was that it was a special shorthand for which 
additional flexibility -- meaning additional text to write -- would be 
detremental. I doubt very much that we ever would have allowed multiple 
expected types - that's evil wherever it appears.

>> Making a language "more expressive" is code for "easier to write", which
>> never was a goal of Ada.
>
> That's one of the issue here. The goal for Ada, as I understand it, has 
> always
> been to be "easier to read". There is no reason why "easier to write" 
> should
> be in opposition to that goal.

"Easier to write" almost always is in opposition, because it means using 
shorthands that cannot easily be deciphered by a human. The "for E of 
Container loop" is certainly in that category, we only allow it because no 
one other than implementers need to understand how it works in detail. The 
way one expects it to work is in fact how it works when read - but if you 
need to understand the details, it's a disaster.

>> > I like to clearly
>> > state what I mean in the code, but on the other hand why should I have
>> > to specify "Element (C)" when I can just use "E" ?
>>
>> Readability, of course. I don't believe that you should ever have been
>> allowed to just specify E. I lost that argument 'cause it wasn't
>> sufficiently evil to waste scarce political capital on, but I don't see 
>> any
>
> Now I understand. You are re-fighting a fight you lost apparently. But 
> from
> talking to all my colleagues (all of whom are of course Ada experts), we 
> all
> much prefer the form with just "E" in practice. So that change was a great
> improvement in the standard, if not quite wide reaching enough.

I'm not "refighting" it; you're saying that some nonsense that won't even 
work is some sort of improvement when it actually would harm 
understandability of the text. That's an expansion of the functionality, and 
I'm definitely against any expansion of this idea. One reason is that Ada is 
gaining too many nice-to-have bells and whistles, to the point that we're 
losing implementations (after all, there are no Ada 2012 implementations 
other than GNAT). We can't keep adding cruft, especially when important 
stuff (parallel operations, for instance) need addressing.

                                         Randy.


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

* Re: A few questions
  2015-11-15 17:56                     ` Brad Moore
  2015-11-15 21:42                       ` Simon Wright
@ 2015-11-16 19:16                       ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-16 19:16 UTC (permalink / raw)


"Brad Moore" <bmoore.ada@gmail.com> wrote in message 
news:68087ee3-fc89-4c13-b5c4-3cd8984e9643@googlegroups.com...
On Thursday, November 12, 2015 at 2:08:54 PM UTC-7, Randy Brukardt wrote:
...
>> > On the other hand, why did Brad include function Iterate?
>>
>> It appears that he wanted tracing of the initialization (as that is all 
>> it
>> does other than making a new iterator that is a copy of the first). It
>> shouldn't be necessary.
>
>It's been a while since I wrote that example, and I'm not entirely sure why 
>I did it
>that way, but to be honest, I think I started with the existing container 
>iterators as
>my starting point example, which all have an Iterate function, and I may 
>have just
>assumed I needed a function which returned an class-wide object.

>If the Prime Number Iterator is useful as an example for others, it would 
>be nice to
>eliminate the Iterate function from the example. It seems also that there 
>should be
>some more tests written to cover the failure cases that we are discovering 
>now. I'd
>be happy to update this ACATS test, if Randy thinks its worthwhile.

I think it would be good to have a separate test using this model (you 
wouldn't need to change the foundation to do it - I think - you'd just not 
call the Iterate function). I don't want to change existing ACATS tests 
unless they are actually wrong (and none of these are).

                              Randy.



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

* Re: A few questions
  2015-11-16 19:13                     ` Randy Brukardt
@ 2015-11-16 20:47                       ` Dmitry A. Kazakov
  2015-11-17 21:30                         ` Randy Brukardt
  2015-11-16 21:50                       ` Simon Wright
  2015-11-17  8:49                       ` briot.emmanuel
  2 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-16 20:47 UTC (permalink / raw)


On Mon, 16 Nov 2015 13:13:05 -0600, Randy Brukardt wrote:

> You're speaking nonsense. The element is part of the container, and the only 
> way to access it is from the container.

I think you are confusing indices with iterators. The very concept of the
iterator is accessing elements without the container as opposed to the
index.

> You can't create a reference to an 
> element of a container without having the container. But your proposed 
> interface does not have the container anywhere. How does the reference get 
> created???

From the old reference of course. Iterators are pointers. Both concepts of
iterator and index have fundamental operations to create a new instance
referencing some other element (next, previous, sibling, parent, neighbour
etc)

>>> Making a language "more expressive" is code for "easier to write", which
>>> never was a goal of Ada.
>>
>> That's one of the issue here. The goal for Ada, as I understand it, has always
>> been to be "easier to read". There is no reason why "easier to write" should
>> be in opposition to that goal.
> 
> "Easier to write" almost always is in opposition, because it means using 
> shorthands that cannot easily be deciphered by a human. The "for E of 
> Container loop" is certainly in that category, we only allow it because no 
> one other than implementers need to understand how it works in detail. The 
> way one expects it to work is in fact how it works when read - but if you 
> need to understand the details, it's a disaster.

A disaster is when nobody can understand the details. The concept of
iteration is simple, so an implementation of its syntax sugar (nothing more
than sugar) must be easily readable and writeable, since all work is
already done in the container.

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


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

* Re: A few questions
  2015-11-16 19:13                     ` Randy Brukardt
  2015-11-16 20:47                       ` Dmitry A. Kazakov
@ 2015-11-16 21:50                       ` Simon Wright
  2015-11-17 21:33                         ` Randy Brukardt
  2015-11-17  8:49                       ` briot.emmanuel
  2 siblings, 1 reply; 73+ messages in thread
From: Simon Wright @ 2015-11-16 21:50 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> Since 'Unrestricted_Access is GNAT junk, it's doesn't have any value
> for a sample implementation (if you really need 'Unrestricted_Access,
> then the interface can't be implemented in Ada, and that would be a
> major problem.)  So far as I know, you might need to use
> 'Unchecked_Access, but that's necessary anytime one needs to get a
> pointer to save the evaluated version of something.

I can't of course speak for AdaCore, but I think that the problem is
to do with obtaining a writable view of an in parameter; for example, in
the Bounded Hashed Map (GCC 5) there is

   function Iterate
     (Container : Map) return Map_Iterator_Interfaces.Forward_Iterator'Class
   is
      B  : Natural renames Container'Unrestricted_Access.all.Busy;
   begin
      return It : constant Iterator :=
        (Limited_Controlled with
           Container => Container'Unrestricted_Access)
      do
         B := B + 1;
      end return;
   end Iterate;

I dare say something could be done with 'Address and Address To Access
Conversions.


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

* Re: A few questions
  2015-11-16 19:13                     ` Randy Brukardt
  2015-11-16 20:47                       ` Dmitry A. Kazakov
  2015-11-16 21:50                       ` Simon Wright
@ 2015-11-17  8:49                       ` briot.emmanuel
  2015-11-17 22:09                         ` Randy Brukardt
  2 siblings, 1 reply; 73+ messages in thread
From: briot.emmanuel @ 2015-11-17  8:49 UTC (permalink / raw)


> Huh? You are suggesting an alternative description for the existing 
> iterators for the existing containers. (If you're suggesting anything else, 
> you're wasting everybodies time, 'cause something that won't work with the 
> existing containers is a non-starter.)

I am trying to think of things should have been done, so that perhaps we can find a
way to fix them in future versions of the language. As this discussion as shown, there
are lots of very knowledgeable people who are having difficulties with the current
design and its limitations. If you think this is wasting your time, by all means feel free
to ignore this thread. I have found it pretty interesting so far.


> And the Reference function in the 
> existing containers (and in any container I can imagine) takes a container 
> parameter. That parameter has to come from somewhere, and it can't come from 
> the iterator interface (it doesn't include a container in the description). 
> So where does it come from??

I was talking of the Reference_Type (which doesn't need a container in the public
spec, although it is convenient sometimes to have one to ensure the lifetime of
the container is greater than that of the reference -- with all the additional
performance costs).
The Iterator interface is an interface, so of course it doesn't contain anything. An
actual Iterator implementation is free to store a reference to the container if it needs
it to implement complex algorithms. An iterator could return a reference by building
it directly, it doesn't need to go through the Reference function for this.

> You're speaking nonsense. The element is part of the container, and the only 
> way to access it is from the container. You can't create a reference to an 
> element of a container without having the container. But your proposed 
> interface does not have the container anywhere. How does the reference get 
> created???

I'll forward you to the discussion you are having with Dmitry. Your notion of
Index vs Cursor vs Iterators seems to be wrong.

> I'm mapping iteration onto the existing containers. That is straightforward 
> with the existing description,

No it is not. Anyone who has already tried to implement their own iterators
has failed the first time (at AdaCore, but also Simon Wright in the initial
message here, at courses we have given in various places,....)

> The limitations aren't that severe, and seem mostly to be related to having 
> the iterator object be an "in" parameter. (That's probably happened because 
> "in out" parameters on functions seem weird, but they clearly make more 
> sense in this case.)

I'll stop this discussion which indeed is leading nowhere. You started by saying
that for-of is useless, so all the rest is moot from your point of view. I can
understand where you are coming from. You can't understand where we want
to go.



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

* Re: A few questions
  2015-11-16 20:47                       ` Dmitry A. Kazakov
@ 2015-11-17 21:30                         ` Randy Brukardt
  2015-11-18  9:53                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-17 21:30 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:8hw612c7lfik.1cy0uanjjnpzv$.dlg@40tude.net...
> On Mon, 16 Nov 2015 13:13:05 -0600, Randy Brukardt wrote:
>
>> You're speaking nonsense. The element is part of the container, and the 
>> only
>> way to access it is from the container.
>
> I think you are confusing indices with iterators. The very concept of the
> iterator is accessing elements without the container as opposed to the
> index.

That's surely not my idea of an iterator. And it doesn't work for Ada in any 
case, as that would allow altering elements of constant containers (we 
prevent that in the containers library by requiring an "in out" container 
parameter in all cases where modifications are allowed).

>> You can't create a reference to an
>> element of a container without having the container. But your proposed
>> interface does not have the container anywhere. How does the reference 
>> get
>> created???
>
> From the old reference of course. Iterators are pointers.

Nonsense.

> Both concepts of
> iterator and index have fundamental operations to create a new instance
> referencing some other element (next, previous, sibling, parent, neighbour
> etc)

The C++ containers mix up the ideas of iterators and cursors (they're 
essentially the same thing there). By your description, you want them to be 
the same -- but in that case, just use the cursors and be done with it. You 
will sacrifice safety and ease-of-use to do so, but whatever.

>>>> Making a language "more expressive" is code for "easier to write", 
>>>> which
>>>> never was a goal of Ada.
>>>
>>> That's one of the issue here. The goal for Ada, as I understand it, has 
>>> always
>>> been to be "easier to read". There is no reason why "easier to write" 
>>> should
>>> be in opposition to that goal.
>>
>> "Easier to write" almost always is in opposition, because it means using
>> shorthands that cannot easily be deciphered by a human. The "for E of
>> Container loop" is certainly in that category, we only allow it because 
>> no
>> one other than implementers need to understand how it works in detail. 
>> The
>> way one expects it to work is in fact how it works when read - but if you
>> need to understand the details, it's a disaster.
>
> A disaster is when nobody can understand the details. The concept of
> iteration is simple, so an implementation of its syntax sugar (nothing 
> more
> than sugar) must be easily readable and writeable, since all work is
> already done in the container.

Well, that's what we did, but you don't seem to be able to see it. Can't 
help with that...

                   Randy.


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

* Re: A few questions
  2015-11-16 21:50                       ` Simon Wright
@ 2015-11-17 21:33                         ` Randy Brukardt
  2015-11-17 23:14                           ` Simon Wright
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-17 21:33 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly1tbpipgd.fsf@pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> Since 'Unrestricted_Access is GNAT junk, it's doesn't have any value
>> for a sample implementation (if you really need 'Unrestricted_Access,
>> then the interface can't be implemented in Ada, and that would be a
>> major problem.)  So far as I know, you might need to use
>> 'Unchecked_Access, but that's necessary anytime one needs to get a
>> pointer to save the evaluated version of something.
>
> I can't of course speak for AdaCore, but I think that the problem is
> to do with obtaining a writable view of an in parameter; for example, in
> the Bounded Hashed Map (GCC 5) there is
>
>   function Iterate
>     (Container : Map) return 
> Map_Iterator_Interfaces.Forward_Iterator'Class
>   is
>      B  : Natural renames Container'Unrestricted_Access.all.Busy;
>   begin
>      return It : constant Iterator :=
>        (Limited_Controlled with
>           Container => Container'Unrestricted_Access)
>      do
>         B := B + 1;
>      end return;
>   end Iterate;
>
> I dare say something could be done with 'Address and Address To Access
> Conversions.

As Brad noted, you have to use the Rosen technique here. Not hacks like 
'Unrestricted_Access. (The Rosen technique is not a "trick", it's an 
intended part of the language in Ada 2012. I admit it originally was 
accidental, but it's too widely used to eliminate.)

                         Randy.


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

* Re: A few questions
  2015-11-17  8:49                       ` briot.emmanuel
@ 2015-11-17 22:09                         ` Randy Brukardt
  0 siblings, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-17 22:09 UTC (permalink / raw)


<briot.emmanuel@gmail.com> wrote in message 
news:64a2a1bd-7519-4d66-bfb6-9b2a1fb1773b@googlegroups.com...
>> Huh? You are suggesting an alternative description for the existing
>> iterators for the existing containers. (If you're suggesting anything 
>> else,
>> you're wasting everybodies time, 'cause something that won't work with 
>> the
>> existing containers is a non-starter.)
>
> I am trying to think of things should have been done, so that perhaps we 
> can find a
> way to fix them in future versions of the language. As this discussion as 
> shown, there
> are lots of very knowledgeable people who are having difficulties with the 
> current
> design and its limitations. If you think this is wasting your time, by all 
> means feel free
> to ignore this thread. I have found it pretty interesting so far.

I haven't been ignoring this thread, although I probably should have rather 
than feeding the trolls.

> "there are lots of very knowledgeable people"

When it comes to Ada, there are very few knowledgeable people (sadly), so 
any statement starting with "lots of knowledgeable people" is junk on its 
face. The only real issue that I've heard from a knowledgeable person is the 
parameter mode issue (which is always an issue with OOP and Ada, it's not 
unique here), and there is a very standard approach to mitigate the problem 
(the Rosen technique).

Everything else seems to come from people who want to do C++ or some other 
language-de-jure in Ada, and that sort of thing has almost always led to 
making Ada more complex without adding anything of value (anonymous access 
types, interfaces, etc.)

>> And the Reference function in the
>> existing containers (and in any container I can imagine) takes a 
>> container
>> parameter. That parameter has to come from somewhere, and it can't come 
>> from
>> the iterator interface (it doesn't include a container in the 
>> description).
>> So where does it come from??
>
> I was talking of the Reference_Type (which doesn't need a container in the 
> public
> spec, although it is convenient sometimes to have one to ensure the 
> lifetime of
> the container is greater than that of the reference -- with all the 
> additional
> performance costs).

I'm still confused. Where does the value of the Reference_Type come from? It 
has to come from the call of some function. (More below.)

> The Iterator interface is an interface, so of course it doesn't contain 
> anything. An
> actual Iterator implementation is free to store a reference to the 
> container if it needs
> it to implement complex algorithms. An iterator could return a reference 
> by building
> it directly, it doesn't need to go through the Reference function for 
> this.

Building it directly from what? An iterator (in Ada today) is an interface 
of functions that are called to implement the iteration syntax. Are you 
proposing to scrap that model? If so, then you have to explain how an 
iterator type maps to iteration syntax. If not, then you have to describe 
the functions called and where in that syntax.

One way to do that latter would be to create additional iterator interfaces. 
*That* would work, rather than additional aspects that don't connect to 
anything. In that case, the function that created the reference type would 
take a value of the iterator object.

That could look something like (names would of course be TBD, "EB" is in 
honor of you, of course):

generic
   type Cursor;
   with function Has_Element (Position : Cursor) return Boolean;
   type Reference_Type is private;
package Ada.EB_Iterator_Interfaces is
   pragma Pure (Iterator_Interfaces);

   package II is new Ada.Iterator_Interfaces (Cursor, Has_Element);

   type EB_Forward_Iterator is limited new II.Forward_Iterator with null 
record;
   function First (Object : Forward_Iterator) return Cursor is abstract;
   function Next (Object : Forward_Iterator; Position : Cursor)
      return Cursor is abstract;
   function Reference (Object : Forward_Iterator; Position : Cursor)
      return Reference_Type is abstract;

   -- Similarly for Reverse_Iterator.

end Ada.EB_Iterator_Interfaces;

Then one could explain the mapping of iterators to references via calls to 
Reference, and the relationship with the other iterators.

As previously noted, I'm unconvinced this is a good idea, but at least the 
above would work. Your proposals are leaving out steps that have to be 
defined in order for it to be a language feature.


>> You're speaking nonsense. The element is part of the container, and the 
>> only
>> way to access it is from the container. You can't create a reference to 
>> an
>> element of a container without having the container. But your proposed
>> interface does not have the container anywhere. How does the reference 
>> get
>> created???
>
> I'll forward you to the discussion you are having with Dmitry. Your notion 
> of
> Index vs Cursor vs Iterators seems to be wrong.

No, his notion of index vs. cursor vs. iterators is nonsense. That's typical 
for him, he uses his own definitions for things, whether or not they have 
anything to do with the subject at hand. It's something one learns to ignore 
here (it's pointless to argue with him about it).

The only definitions I use are the ones in the Ada Reference Manual. All 
else is irrelevant to me.

>> I'm mapping iteration onto the existing containers. That is 
>> straightforward
>> with the existing description,
>
> No it is not. Anyone who has already tried to implement their own 
> iterators
> has failed the first time (at AdaCore, but also Simon Wright in the 
> initial
> message here, at courses we have given in various places,....)

That's the effect of the lack of good examples more than any problem with 
the interface. Brad's ACATS tests provide some good examples for users to 
study, hopefully examples like that will get more play.

>> The limitations aren't that severe, and seem mostly to be related to 
>> having
>> the iterator object be an "in" parameter. (That's probably happened 
>> because
>> "in out" parameters on functions seem weird, but they clearly make more
>> sense in this case.)
>
> I'll stop this discussion which indeed is leading nowhere. You started by 
> saying
> that for-of is useless, so all the rest is moot from your point of view. I 
> can
> understand where you are coming from. You can't understand where we want
> to go.

I think I do understand where you want to go, and I really don't think Ada 
should be going there. Certainly not for sequential programs (I'm more open 
to change on the parallel side because what we have is way too hard to use).

                                Randy.


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

* Re: A few questions
  2015-11-17 21:33                         ` Randy Brukardt
@ 2015-11-17 23:14                           ` Simon Wright
  0 siblings, 0 replies; 73+ messages in thread
From: Simon Wright @ 2015-11-17 23:14 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Simon Wright" <simon@pushface.org> wrote in message 
> news:ly1tbpipgd.fsf@pushface.org...

>> I can't of course speak for AdaCore, but I think that the problem is
>> to do with obtaining a writable view of an in parameter; for example, in
>> the Bounded Hashed Map (GCC 5) there is
>>
>>   function Iterate
>>     (Container : Map) return 
>> Map_Iterator_Interfaces.Forward_Iterator'Class
>>   is
>>      B  : Natural renames Container'Unrestricted_Access.all.Busy;

> As Brad noted, you have to use the Rosen technique here. Not hacks
> like 'Unrestricted_Access. (The Rosen technique is not a "trick", it's
> an intended part of the language in Ada 2012. I admit it originally
> was accidental, but it's too widely used to eliminate.)

Does that now work for non-limited types? The anti-tampering bits have
to be in the container ... how have other vendors managed this?

Brad was talking about using this technique in the iterator.


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

* Re: A few questions
  2015-11-17 21:30                         ` Randy Brukardt
@ 2015-11-18  9:53                           ` Dmitry A. Kazakov
  2015-11-18 22:27                             ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-18  9:53 UTC (permalink / raw)


On Tue, 17 Nov 2015 15:30:28 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:8hw612c7lfik.1cy0uanjjnpzv$.dlg@40tude.net...
>> On Mon, 16 Nov 2015 13:13:05 -0600, Randy Brukardt wrote:
>>
>>> You're speaking nonsense. The element is part of the container, and the 
>>> only way to access it is from the container.
>>
>> I think you are confusing indices with iterators. The very concept of the
>> iterator is accessing elements without the container as opposed to the
>> index.
> 
> That's surely not my idea of an iterator. And it doesn't work for Ada in any 
> case, as that would allow altering elements of constant containers (we 
> prevent that in the containers library by requiring an "in out" container 
> parameter in all cases where modifications are allowed).

Access /= Update. Compare it with "access constant T"

The difference between index and iterator is that accessing through the
index requires the container. An index is always relative to some
container. The iterator does not need the container, the container is
implicit.

>> Both concepts of
>> iterator and index have fundamental operations to create a new instance
>> referencing some other element (next, previous, sibling, parent, neighbour
>> etc)
> 
> The C++ containers mix up the ideas of iterators and cursors (they're 
> essentially the same thing there). By your description, you want them to be 
> the same -- but in that case, just use the cursors and be done with it. You 
> will sacrifice safety and ease-of-use to do so, but whatever.

That is not my point. It is that Index + 1 is another index and that
Iterator.Next is another iterator. From the interface point of view you
don't need the container to get another instance of either.

And regarding safety, it is very important that you don't need the
container when accessing elements or advancing the iterator. Well-designed
iterators meant to keep the iteration state *inside* the iterator object
rather than in the container, for evident reasons.

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


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

* Re: A few questions
  2015-11-18  9:53                           ` Dmitry A. Kazakov
@ 2015-11-18 22:27                             ` Randy Brukardt
  2015-11-19  8:52                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2015-11-18 22:27 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:ojkj222dh308.y5p6iz7kqgjc.dlg@40tude.net...
> On Tue, 17 Nov 2015 15:30:28 -0600, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:8hw612c7lfik.1cy0uanjjnpzv$.dlg@40tude.net...
>>> On Mon, 16 Nov 2015 13:13:05 -0600, Randy Brukardt wrote:
>>>
>>>> You're speaking nonsense. The element is part of the container, and the
>>>> only way to access it is from the container.
>>>
>>> I think you are confusing indices with iterators. The very concept of 
>>> the
>>> iterator is accessing elements without the container as opposed to the
>>> index.
>>
>> That's surely not my idea of an iterator. And it doesn't work for Ada in 
>> any
>> case, as that would allow altering elements of constant containers (we
>> prevent that in the containers library by requiring an "in out" container
>> parameter in all cases where modifications are allowed).
>
> Access /= Update. Compare it with "access constant T"

True, but irrelevant. Iterators without update compatibilities are way to 
limiting to be of any value.

> The difference between index and iterator is that accessing through the
> index requires the container. An index is always relative to some
> container. The iterator does not need the container, the container is
> implicit.

This is the confusion between "iterators" and "cursors" that the C++ 
libraries have. What you are describing as an "iterator" is exactly the 
definition of a cursor in Ada. To me, iterators are active objects, not just 
indexes.

>>> Both concepts of
>>> iterator and index have fundamental operations to create a new instance
>>> referencing some other element (next, previous, sibling, parent, 
>>> neighbour
>>> etc)
>>
>> The C++ containers mix up the ideas of iterators and cursors (they're
>> essentially the same thing there). By your description, you want them to 
>> be
>> the same -- but in that case, just use the cursors and be done with it. 
>> You
>> will sacrifice safety and ease-of-use to do so, but whatever.
>
> That is not my point. It is that Index + 1 is another index and that
> Iterator.Next is another iterator. From the interface point of view you
> don't need the container to get another instance of either.

Next(Cursor) gets you another Cursor. (You can't use the prefix notation 
because Cursors aren't tagged, and that's because we can't have primitive 
operations of two tagged types, else they would have been tagged. But 
otherwise this is identical.) You don't need the container to call Next. But 
you do need the container to update the element.

> And regarding safety, it is very important that you don't need the
> container when accessing elements or advancing the iterator. Well-designed
> iterators meant to keep the iteration state *inside* the iterator object
> rather than in the container, for evident reasons.

???

If the container (not counting the contents of the elements) is modified 
while the iterator is executing, it doesn't matter where the iteration is 
happening -- you're not going to be able to maintain the invariants of the 
execution.

That happens with explicit iteration in the Ada.Containers (that is, 
directly using Next and Cursors) -- where the effect is for the user to 
figure out (and it's often erroneous) -- and that happens with any possible 
iterator mechanism (using call-backs, or interfaces, or whatever) -- where 
Ada uses a tampering check to avoid problems (the container does not allow 
element insertions or deletions while an iteration is running).

If you think allowing erroneous execution is somehow safe, you're in the 
wrong language forum.

                            Randy.


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

* Re: A few questions
  2015-11-18 22:27                             ` Randy Brukardt
@ 2015-11-19  8:52                               ` Dmitry A. Kazakov
  2015-11-19 21:15                                 ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-19  8:52 UTC (permalink / raw)


On Wed, 18 Nov 2015 16:27:31 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:ojkj222dh308.y5p6iz7kqgjc.dlg@40tude.net...
>> On Tue, 17 Nov 2015 15:30:28 -0600, Randy Brukardt wrote:
>>
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:8hw612c7lfik.1cy0uanjjnpzv$.dlg@40tude.net...
>>>> On Mon, 16 Nov 2015 13:13:05 -0600, Randy Brukardt wrote:
>>>>
>>>>> You're speaking nonsense. The element is part of the container, and the
>>>>> only way to access it is from the container.
>>>>
>>>> I think you are confusing indices with iterators. The very concept of the
>>>> iterator is accessing elements without the container as opposed to the
>>>> index.
>>>
>>> That's surely not my idea of an iterator. And it doesn't work for Ada in any
>>> case, as that would allow altering elements of constant containers (we
>>> prevent that in the containers library by requiring an "in out" container
>>> parameter in all cases where modifications are allowed).
>>
>> Access /= Update. Compare it with "access constant T"
> 
> True, but irrelevant. Iterators without update compatibilities are way to 
> limiting to be of any value.

I was answering your point. Clearly iterators, as pointers are, can be
immutable themselves and/or refer to the immutable target. If container is
immutable you should not be able to obtain a mutable-target iterator from
it. Where is a problem?

>> The difference between index and iterator is that accessing through the
>> index requires the container. An index is always relative to some
>> container. The iterator does not need the container, the container is
>> implicit.
> 
> This is the confusion between "iterators" and "cursors" that the C++ 
> libraries have. What you are describing as an "iterator" is exactly the 
> definition of a cursor in Ada. To me, iterators are active objects, not just 
> indexes.

Iterator is not an index, I explained the difference. Index needs explicit
container in the indexing operation. Iterator/cursor is nothing but a fat
pointer. Pointers do not need explicit container (=memory pool) for
dereferencing. This has nothing to do with specifically C++. E.g. DB
interfaces have "cursors", GUI frameworks have "iterators" etc. The
semantics of such object is same:

   Cursor = Iterator = Pointer

>>>> Both concepts of
>>>> iterator and index have fundamental operations to create a new instance
>>>> referencing some other element (next, previous, sibling, parent, 
>>>> neighbour etc)
>>>
>>> The C++ containers mix up the ideas of iterators and cursors (they're
>>> essentially the same thing there). By your description, you want them to 
>>> be the same -- but in that case, just use the cursors and be done with it. 
>>> You will sacrifice safety and ease-of-use to do so, but whatever.
>>
>> That is not my point. It is that Index + 1 is another index and that
>> Iterator.Next is another iterator. From the interface point of view you
>> don't need the container to get another instance of either.
> 
> Next(Cursor) gets you another Cursor. (You can't use the prefix notation 
> because Cursors aren't tagged, and that's because we can't have primitive 
> operations of two tagged types, else they would have been tagged. But 
> otherwise this is identical.) You don't need the container to call Next. But 
> you do need the container to update the element.

Both are just design bugs resulted due to language deficiencies. Clearly,
there is no reason why postfix notation should not be allowed for the
iterator objects, why the iterator type cannot be inherited from, why
container is needed to update its element.

As I said many times, fix the language type system first, then design
standard containers. In that order.

>> And regarding safety, it is very important that you don't need the
>> container when accessing elements or advancing the iterator. Well-designed
>> iterators meant to keep the iteration state *inside* the iterator object
>> rather than in the container, for evident reasons.
> 
> ???
> 
> If the container (not counting the contents of the elements) is modified 
> while the iterator is executing, it doesn't matter where the iteration is 
> happening -- you're not going to be able to maintain the invariants of the 
> execution.

This is an aliasing problem, not a problem of iterator objects, though all
iterators always have aliasing issues because of their referential
semantics.

BTW, speaking of inventing definitions, "iterator" is an object. It is not
a process, the latter is called "iteration", "traversing", "search",
"walkthrough", "enumeration" etc.

> That happens with explicit iteration in the Ada.Containers (that is, 
> directly using Next and Cursors) -- where the effect is for the user to 
> figure out (and it's often erroneous) -- and that happens with any possible 
> iterator mechanism (using call-backs, or interfaces, or whatever) -- where 
> Ada uses a tampering check to avoid problems (the container does not allow 
> element insertions or deletions while an iteration is running).

Yes, this is one of the worst form of enumeration because it is recursive,
hello FP. Should be avoided where possible.

> If you think allowing erroneous execution is somehow safe, you're in the 
> wrong language forum.

The point was that keeping the iteration state in the container is more
erroneous that keeping it outside in the iterator object. E.g. some
implementations store last found element, deploy caching and book-keeping
things in the container. That far less safe than keeping that stuff outside
the container, e.g. in the iterator object.

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

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

* Re: A few questions
  2015-11-19  8:52                               ` Dmitry A. Kazakov
@ 2015-11-19 21:15                                 ` Randy Brukardt
  0 siblings, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2015-11-19 21:15 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1wew1bio4hygc.xotxd22aq47g.dlg@40tude.net...
> On Wed, 18 Nov 2015 16:27:31 -0600, Randy Brukardt wrote:
...
>> If you think allowing erroneous execution is somehow safe, you're in the
>> wrong language forum.
>
> The point was that keeping the iteration state in the container is more
> erroneous that keeping it outside in the iterator object. E.g. some
> implementations store last found element, deploy caching and book-keeping
> things in the container. That far less safe than keeping that stuff 
> outside
> the container, e.g. in the iterator object.

Sorry, missed your point originally. I don't think it's possible (in 
general) to keep the iteration information within the container, as that 
would mean that you could only do one iteration at a time. Which would be a 
nasty abstraction break (inner iterations on the same container would have 
to fail in that case, but for no good reason).

That is, if the iterator info is part of the container, then
        for E of C loop
            for F of C loop
               ...
            end loop;
       end loop;

cannot work. (The inner loop often occurs in some routine called from the 
body of the loop, it wouldn't be obvious like this is.)

                               Randy.



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

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

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-31 20:29 A few questions Laurent
2015-10-31 20:49 ` Dmitry A. Kazakov
2015-11-01 13:16   ` Laurent
2015-11-01  0:25 ` Jeffrey R. Carter
2015-11-01 13:30   ` Laurent
2015-11-03  6:25   ` Randy Brukardt
2015-11-01  9:05 ` Jacob Sparre Andersen
2015-11-01 13:40   ` Laurent
2015-11-01 18:14     ` Jacob Sparre Andersen
2015-11-01 18:40       ` Laurent
2015-11-01 13:42 ` brbarkstrom
2015-11-01 13:52   ` Laurent
2015-11-01 17:59     ` Jeffrey R. Carter
2015-11-01 18:35       ` Laurent
2015-11-02 13:25     ` brbarkstrom
2015-11-01 15:15   ` Dennis Lee Bieber
2015-11-01 16:33 ` gautier_niouzes
2015-11-01 16:36   ` gautier_niouzes
2015-11-01 18:17 ` Stephen Leake
2015-11-01 18:53   ` Laurent
2015-11-02  0:41     ` Dennis Lee Bieber
2015-11-02 16:42     ` Stephen Leake
2015-11-02 17:45 ` Simon Wright
2015-11-02 18:48   ` Simon Wright
2015-11-03  6:33     ` Randy Brukardt
2015-11-03  8:26       ` Simon Wright
2015-11-03  6:40   ` Randy Brukardt
2015-11-03  8:34     ` Simon Wright
2015-11-04 16:19       ` Simon Wright
2015-11-05  1:20         ` Randy Brukardt
2015-11-05  8:34           ` briot.emmanuel
2015-11-12 18:28             ` Randy Brukardt
2015-11-12 20:19               ` Simon Wright
2015-11-12 20:56               ` Dmitry A. Kazakov
2015-11-12 21:15                 ` Randy Brukardt
2015-11-13  8:40                   ` Dmitry A. Kazakov
2015-11-13 17:52                     ` Randy Brukardt
2015-11-13 20:37                       ` Dmitry A. Kazakov
2015-11-13 22:15                         ` Randy Brukardt
2015-11-14 11:42                           ` Dmitry A. Kazakov
2015-11-14 12:37                           ` Simon Wright
2015-11-14 17:24                             ` Shark8
2015-11-14 20:09                               ` Simon Wright
2015-11-15 18:54                             ` Brad Moore
2015-11-13  8:45               ` briot.emmanuel
2015-11-13 17:41                 ` Randy Brukardt
2015-11-14 19:57                   ` briot.emmanuel
2015-11-16 19:13                     ` Randy Brukardt
2015-11-16 20:47                       ` Dmitry A. Kazakov
2015-11-17 21:30                         ` Randy Brukardt
2015-11-18  9:53                           ` Dmitry A. Kazakov
2015-11-18 22:27                             ` Randy Brukardt
2015-11-19  8:52                               ` Dmitry A. Kazakov
2015-11-19 21:15                                 ` Randy Brukardt
2015-11-16 21:50                       ` Simon Wright
2015-11-17 21:33                         ` Randy Brukardt
2015-11-17 23:14                           ` Simon Wright
2015-11-17  8:49                       ` briot.emmanuel
2015-11-17 22:09                         ` Randy Brukardt
2015-11-05  8:45           ` Simon Wright
2015-11-05  8:52             ` Simon Wright
2015-11-12 18:29               ` Randy Brukardt
2015-11-12 18:32               ` Randy Brukardt
2015-11-12 20:02                 ` Simon Wright
2015-11-12 21:08                   ` Randy Brukardt
2015-11-15 17:56                     ` Brad Moore
2015-11-15 21:42                       ` Simon Wright
2015-11-16 19:16                       ` Randy Brukardt
  -- strict thread matches above, loose matches on Subject: below --
2015-02-07 17:43 Laurent
2015-02-07 22:15 ` Brad Moore
2015-02-08 22:37   ` Laurent
2015-02-09 13:56     ` Brad Moore
2015-02-09 18:36       ` Laurent

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