Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A few questions

498 views
Skip to first unread message

Laurent

unread,
Oct 31, 2015, 4:29:53 PM10/31/15
to
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.

Dmitry A. Kazakov

unread,
Oct 31, 2015, 4:49:24 PM10/31/15
to
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

Jeffrey R. Carter

unread,
Oct 31, 2015, 8:25:22 PM10/31/15
to
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

Jacob Sparre Andersen

unread,
Nov 1, 2015, 4:05:17 AM11/1/15
to
Laurent <lut...@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

Laurent

unread,
Nov 1, 2015, 8:16:02 AM11/1/15
to
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

Laurent

unread,
Nov 1, 2015, 8:30:44 AM11/1/15
to
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


Laurent

unread,
Nov 1, 2015, 8:40:06 AM11/1/15
to
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

brbar...@gmail.com

unread,
Nov 1, 2015, 8:42:17 AM11/1/15
to
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.

Laurent

unread,
Nov 1, 2015, 8:52:10 AM11/1/15
to
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.

gautier...@hotmail.com

unread,
Nov 1, 2015, 11:33:40 AM11/1/15
to
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;

gautier...@hotmail.com

unread,
Nov 1, 2015, 11:36:43 AM11/1/15
to
> 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

Jeffrey R. Carter

unread,
Nov 1, 2015, 12:59:47 PM11/1/15
to
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

Jacob Sparre Andersen

unread,
Nov 1, 2015, 1:14:09 PM11/1/15
to
Laurent <lut...@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

Stephen Leake

unread,
Nov 1, 2015, 1:17:44 PM11/1/15
to
Laurent <lut...@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

Laurent

unread,
Nov 1, 2015, 1:35:20 PM11/1/15
to
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

Laurent

unread,
Nov 1, 2015, 1:40:38 PM11/1/15
to
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

Laurent

unread,
Nov 1, 2015, 1:53:32 PM11/1/15
to
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 :)

brbar...@gmail.com

unread,
Nov 2, 2015, 8:25:56 AM11/2/15
to

> 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.

Stephen Leake

unread,
Nov 2, 2015, 11:42:43 AM11/2/15
to
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

Simon Wright

unread,
Nov 2, 2015, 12:45:32 PM11/2/15
to
Laurent <lut...@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;

Simon Wright

unread,
Nov 2, 2015, 1:48:17 PM11/2/15
to
Simon Wright <si...@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 ...

Randy Brukardt

unread,
Nov 3, 2015, 1:25:08 AM11/3/15
to
"Jeffrey R. Carter" <spam.jrc...@spam.not.acm.org> wrote in message
news:n13m1a$p3c$1...@dont-email.me...
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.


Randy Brukardt

unread,
Nov 3, 2015, 1:33:49 AM11/3/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:ly1tc8m...@pushface.org...
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.



Randy Brukardt

unread,
Nov 3, 2015, 1:40:39 AM11/3/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:ly611km...@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.


Simon Wright

unread,
Nov 3, 2015, 3:26:46 AM11/3/15
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> "Simon Wright" <si...@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.

Simon Wright

unread,
Nov 3, 2015, 3:34:10 AM11/3/15
to
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.

Simon Wright

unread,
Nov 4, 2015, 11:19:42 AM11/4/15
to
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"

Randy Brukardt

unread,
Nov 4, 2015, 8:20:45 PM11/4/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:lybnb9l...@pushface.org...
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.



briot.e...@gmail.com

unread,
Nov 5, 2015, 3:34:35 AM11/5/15
to
> 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

Simon Wright

unread,
Nov 5, 2015, 3:45:14 AM11/5/15
to
"Randy Brukardt" <ra...@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)

Simon Wright

unread,
Nov 5, 2015, 3:52:55 AM11/5/15
to
Oh, it should have been

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

Randy Brukardt

unread,
Nov 12, 2015, 1:28:49 PM11/12/15
to
<briot.e...@gmail.com> wrote in message
news:aa0cf839-651e-494d...@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.


Randy Brukardt

unread,
Nov 12, 2015, 1:29:53 PM11/12/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:lyziysk...@pushface.org...
Right. You got two head slaps for the price of one. :-)

Randy.


Randy Brukardt

unread,
Nov 12, 2015, 1:32:11 PM11/12/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:lyziysk...@pushface.org...
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.


Simon Wright

unread,
Nov 12, 2015, 3:02:22 PM11/12/15
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> "Simon Wright" <si...@pushface.org> wrote in message
> news:lyziysk...@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?

Simon Wright

unread,
Nov 12, 2015, 3:19:48 PM11/12/15
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> <briot.e...@gmail.com> wrote in message
> news:aa0cf839-651e-494d...@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.

Dmitry A. Kazakov

unread,
Nov 12, 2015, 3:56:38 PM11/12/15
to
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

Randy Brukardt

unread,
Nov 12, 2015, 4:08:54 PM11/12/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:ly4mgrj...@pushface.org...
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.


Randy Brukardt

unread,
Nov 12, 2015, 4:15:48 PM11/12/15
to
"Dmitry A. Kazakov" <mai...@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.


Dmitry A. Kazakov

unread,
Nov 13, 2015, 3:40:57 AM11/13/15
to
On Thu, 12 Nov 2015 15:15:45 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@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.

briot.e...@gmail.com

unread,
Nov 13, 2015, 3:45:48 AM11/13/15
to
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" ?


Randy Brukardt

unread,
Nov 13, 2015, 12:41:05 PM11/13/15
to

<briot.e...@gmail.com> wrote in message
news:db3ea03a-07cc-4f1a...@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.



Randy Brukardt

unread,
Nov 13, 2015, 12:52:31 PM11/13/15
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1dolqizyi8gxi.t...@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.


Dmitry A. Kazakov

unread,
Nov 13, 2015, 3:38:01 PM11/13/15
to
On Fri, 13 Nov 2015 11:52:29 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
> news:1dolqizyi8gxi.t...@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.

Randy Brukardt

unread,
Nov 13, 2015, 5:15:04 PM11/13/15
to
"Dmitry A. Kazakov" <mai...@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.


Dmitry A. Kazakov

unread,
Nov 14, 2015, 6:42:38 AM11/14/15
to
On Fri, 13 Nov 2015 16:15:01 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@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.

Simon Wright

unread,
Nov 14, 2015, 7:37:32 AM11/14/15
to
"Randy Brukardt" <ra...@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!

Shark8

unread,
Nov 14, 2015, 12:24:05 PM11/14/15
to
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.)

briot.e...@gmail.com

unread,
Nov 14, 2015, 2:57:08 PM11/14/15
to
> 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.

Simon Wright

unread,
Nov 14, 2015, 3:09:58 PM11/14/15
to
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;

Brad Moore

unread,
Nov 15, 2015, 12:56:47 PM11/15/15
to
On Thursday, November 12, 2015 at 2:08:54 PM UTC-7, Randy Brukardt wrote:
> "Simon Wright" <si...@pushface.org> wrote in message
> news:ly4mgrj...@pushface.org...
> > "Randy Brukardt" <ra...@rrsoftware.com> writes:
> >
> >> "Simon Wright" <si...@pushface.org> wrote in message
> >> news:lyziysk...@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

Brad Moore

unread,
Nov 15, 2015, 1:54:22 PM11/15/15
to
On Saturday, November 14, 2015 at 5:37:32 AM UTC-7, Simon Wright wrote:
> "Randy Brukardt" <ra...@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

Simon Wright

unread,
Nov 15, 2015, 4:42:17 PM11/15/15
to
Brad Moore <bmoor...@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.

Randy Brukardt

unread,
Nov 16, 2015, 2:13:08 PM11/16/15
to
<briot.e...@gmail.com> wrote in message
news:5007b311-5d2e-448c...@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.


Randy Brukardt

unread,
Nov 16, 2015, 2:16:47 PM11/16/15
to
"Brad Moore" <bmoor...@gmail.com> wrote in message
news:68087ee3-fc89-4c13...@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.


Dmitry A. Kazakov

unread,
Nov 16, 2015, 3:47:50 PM11/16/15
to
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.

Simon Wright

unread,
Nov 16, 2015, 4:50:28 PM11/16/15
to
"Randy Brukardt" <ra...@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.

briot.e...@gmail.com

unread,
Nov 17, 2015, 3:49:51 AM11/17/15
to
> 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.


Randy Brukardt

unread,
Nov 17, 2015, 4:30:34 PM11/17/15
to
"Dmitry A. Kazakov" <mai...@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.


Randy Brukardt

unread,
Nov 17, 2015, 4:33:43 PM11/17/15
to
"Simon Wright" <si...@pushface.org> wrote in message
news:ly1tbpi...@pushface.org...
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.


Randy Brukardt

unread,
Nov 17, 2015, 5:09:34 PM11/17/15
to
<briot.e...@gmail.com> wrote in message
news:64a2a1bd-7519-4d66...@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.


Simon Wright

unread,
Nov 17, 2015, 6:14:19 PM11/17/15
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> "Simon Wright" <si...@pushface.org> wrote in message
> news:ly1tbpi...@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.

Dmitry A. Kazakov

unread,
Nov 18, 2015, 4:54:20 AM11/18/15
to
On Tue, 17 Nov 2015 15:30:28 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@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.

Randy Brukardt

unread,
Nov 18, 2015, 5:27:34 PM11/18/15
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:ojkj222dh308.y...@40tude.net...
> On Tue, 17 Nov 2015 15:30:28 -0600, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mai...@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.


Dmitry A. Kazakov

unread,
Nov 19, 2015, 3:53:23 AM11/19/15
to
On Wed, 18 Nov 2015 16:27:31 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
> news:ojkj222dh308.y...@40tude.net...
>> On Tue, 17 Nov 2015 15:30:28 -0600, Randy Brukardt wrote:
>>
>>> "Dmitry A. Kazakov" <mai...@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.

Randy Brukardt

unread,
Nov 19, 2015, 4:15:18 PM11/19/15
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1wew1bio4hygc.x...@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.


0 new messages