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

Vector of Vectors.

220 views
Skip to first unread message

Peter C. Chapin

unread,
Jan 14, 2009, 7:32:25 PM1/14/09
to
I'm having a bit of trouble manipulating an element of a vector of
vectors. I'm using GNAT GPL 2008. Here is a small program to illustrate
the issue:

with Ada.Containers.Vectors;

procedure Check is
package Integer_Vectors is
new Ada.Containers.Vectors
(Index_Type => Natural,
Element_Type => Integer);

package Nested_Vectors is
new Ada.Containers.Vectors
(Index_Type => Natural,
Element_Type => Integer_Vectors.Vector,
"=" => Integer_Vectors."=");

IV : Integer_Vectors.Vector;
NV : Nested_Vectors.Vector;
begin
IV.Append(42);
NV.Append(IV);
NV.Element(0).Append(43); -- Compile error here.
end Check;

The error message is, "Actual for Container must be a variable." I
understand what this means. The problem is that I'm trying to use an
expression as an argument for an 'in out' parameter. What I'm having
trouble figuring out is how to work around this. I tried using 'renames'
to give a simple name to NV.Element(0) but that didn't fool the compiler
(no surprise). I also tried playing around with anonymous access types
but I couldn't figure out how to declare the Element_Type of package
Nested_Vectors to be aliased. I'm not sure if it would have worked in
any case.

Surely there must be a straight forward way to do this!

Peter

Jeffrey R. Carter

unread,
Jan 14, 2009, 9:44:22 PM1/14/09
to
Peter C. Chapin wrote:
>
> Surely there must be a straight forward way to do this!

I'd probably use Update_Element.

--
Jeff Carter
"I've got to stay here, but there's no reason
why you folks shouldn't go out into the lobby
until this thing blows over."
Horse Feathers
50

Alex R. Mosteo

unread,
Jan 15, 2009, 5:10:07 AM1/15/09
to
Jeffrey R. Carter wrote:

> Peter C. Chapin wrote:
>>
>> Surely there must be a straight forward way to do this!
>
> I'd probably use Update_Element.

Which one could argue is straightforward from a conceptual point of view,
but requires a lot of typing.

I think there was an old discussion about why it was not a good idea to have
functions returning accesses to the elements for this[*], which would enable
what Peter was attempting (since without something like C++ references
there's no way to do this with similar code). I have done so for my use
sometimes, but is ugly nonetheless. Exposing accesses to client code is not
nice, to put it mildly.

[*] Dangling pointers IIRC was the reason. In GNAT case I suspect that
dangling cursors is not any better since they don't do reference counting
anyway.

Georg Bauhaus

unread,
Jan 15, 2009, 5:56:22 AM1/15/09
to
Alex R. Mosteo schrieb:

> Jeffrey R. Carter wrote:
>
>> Peter C. Chapin wrote:
>>> Surely there must be a straight forward way to do this!
>> I'd probably use Update_Element.
>
> Which one could argue is straightforward from a conceptual point of view,
> but requires a lot of typing.

There is a fair bit of template code for
Update_Element. No need, I should think,
to not have a computer help you with this
sort of typing :-)

Peter C. Chapin

unread,
Jan 15, 2009, 7:08:36 AM1/15/09
to
Jeffrey R. Carter wrote:


>> Surely there must be a straight forward way to do this!
>
> I'd probably use Update_Element.

Okay, thanks. That sounds like a reasonably approach.

I don't mind the extra typing, honestly, and some extra "complexity" is
also acceptable since this isn't something I need to do often (in
general). Being straight forward conceptually is more important and
Update_Element seems to satisfy that criteria.

Thanks!

Peter

Jeffrey R. Carter

unread,
Jan 15, 2009, 3:44:23 PM1/15/09
to
Alex R. Mosteo wrote:
>
> Which one could argue is straightforward from a conceptual point of view,
> but requires a lot of typing.

Ada explicitly emphasizes ease of reading over ease of writing (ARM Introduction).

--
Jeff Carter
"Your mother was a hamster and your father smelt of elderberries."
Monty Python & the Holy Grail
06

Robert A Duff

unread,
Jan 15, 2009, 4:26:05 PM1/15/09
to
"Jeffrey R. Carter" <spam.jrc...@spam.acm.org> writes:

> Alex R. Mosteo wrote:
>> Which one could argue is straightforward from a conceptual point of
>> view, but requires a lot of typing.
>
> Ada explicitly emphasizes ease of reading over ease of writing (ARM Introduction).

Not in this case.

I agree that the "extra typing" is not the problem. The problem is that
you have to read all that junk you typed, and it's mostly content free.

- Bob

Alex R. Mosteo

unread,
Jan 16, 2009, 5:15:26 AM1/16/09
to
Peter C. Chapin wrote:

To be fair, since I was the one throwing the typing bit, this kind of
"heavyweight" constructs are sparingly needed (in my use cases) when using
the standard containers. And in any case you can write a wrapper once and
hide it for good.

Ivan Levashew

unread,
Jan 17, 2009, 5:20:28 AM1/17/09
to
> >
> > Ada explicitly emphasizes ease of reading over ease of writing (ARM Introduction).
>
> Not in this case.
>
> I agree that the "extra typing" is not the problem. The problem is that
> you have to read all that junk you typed, and it's mostly content free.

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?

Top-posting is what actually happens when one uses downwards closures.
In my case, I had to iterate map of vectors. "Iterate" procedure
passes my
closure just Cursor. I need to invoke Update_Element on Cursor, then
Iterate the Vector, then Update_Element on Vector.
4 levels so far.

Downwards closures is rather easy way to write write-only Ada code.

I've specified the order in which I wrote every line. There are just 2
levels here.

1 declare
5 procedure ...(...) is
9 procedure ...(...) is
...
10 begin
12 Iterate (..., ...'Acess);
11 end ...;
6 begin
8 Update_Element (..., ...'Access);
7 end ...;
2 begin
4 Iterate (...., ...'Access);
3 end;

Do you read in the same order?

I'd like to have a syntax like this:

Iterate (..., ..., new procedure (...) is
begin
...
end;);

Procedure name should be optional, I think.

Dmitry A. Kazakov

unread,
Jan 17, 2009, 5:51:45 AM1/17/09
to
On Sat, 17 Jan 2009 02:20:28 -0800 (PST), Ivan Levashew wrote:

> Downwards closures is rather easy way to write write-only Ada code.
>
> I've specified the order in which I wrote every line. There are just 2
> levels here.
>
> 1 declare
> 5 procedure ...(...) is
> 9 procedure ...(...) is
> ...
> 10 begin
> 12 Iterate (..., ...'Acess);
> 11 end ...;
> 6 begin
> 8 Update_Element (..., ...'Access);
> 7 end ...;
> 2 begin
> 4 Iterate (...., ...'Access);
> 3 end;
>
> Do you read in the same order?
>
> I'd like to have a syntax like this:
>
> Iterate (..., ..., new procedure (...) is
> begin
> ...
> end;);
>
> Procedure name should be optional, I think.

And the next step is

for Element in Vector loop
-- place "new procedure" here!
end loop;

There is nothing better for iteration than loops. Downward closures are
meant for different stuff.

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

Robert A Duff

unread,
Jan 17, 2009, 11:41:57 AM1/17/09
to
Ivan Levashew <octa...@bluebottle.com> writes:

> A: Because it messes up the order in which people normally read text.
> Q: Why is top-posting such a bad thing?
> A: Top-posting.
> Q: What is the most annoying thing in e-mail?
>
> Top-posting is what actually happens when one uses downwards closures.

Nice analogy. I agree 100%

> Procedure name should be optional, I think.

Yes. Like a lambda expression in Lisp, but preferably with less verbose
syntax.

Requiring the body of a loop to have a name is an annoyance.
What are you going to call it? The_Loop_Body. Or something
equally meaningless.

- Bob

Robert A Duff

unread,
Jan 17, 2009, 11:45:25 AM1/17/09
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> And the next step is
>
> for Element in Vector loop
> -- place "new procedure" here!
> end loop;

Sather has an elegant iterator feature, which is along these lines.

> There is nothing better for iteration than loops.

Maybe things like "map" found in functional languages?

>...Downward closures are
> meant for different stuff.

I'd say your above "for..." syntax should be thought of as syntactic
sugar defined in terms of downward closures. Or perhaps in terms
of some coroutine-like concept.

- Bob

Dmitry A. Kazakov

unread,
Jan 17, 2009, 12:18:24 PM1/17/09
to
On Sat, 17 Jan 2009 11:45:25 -0500, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:
>
>> And the next step is
>>
>> for Element in Vector loop
>> -- place "new procedure" here!
>> end loop;
>
> Sather has an elegant iterator feature, which is along these lines.
>
>> There is nothing better for iteration than loops.
>
> Maybe things like "map" found in functional languages?

Iteration is meant to be stateful. Map, convolution, product etc are
different in my view.

>>...Downward closures are
>> meant for different stuff.
>
> I'd say your above "for..." syntax should be thought of as syntactic
> sugar defined in terms of downward closures. Or perhaps in terms
> of some coroutine-like concept.

I would say that downward closure is an argument of a map or some other
operation taking subprogram as an argument etc.

Concerning syntax, I think we should have introduced proper procedural
types with literals/aggregates of. Quite simple to do, IMO.

Georg Bauhaus

unread,
Jan 17, 2009, 1:56:24 PM1/17/09
to
Robert A Duff wrote:

> Requiring the body of a loop to have a name is an annoyance.
> What are you going to call it? The_Loop_Body. Or something
> equally meaningless.

Is the loop body meaningless, too? If not, there is a name :-)

Robert A Duff

unread,
Jan 17, 2009, 5:59:48 PM1/17/09
to
Georg Bauhaus <see.re...@maps.futureapps.de> writes:

The loop body is usually self explanatory. E.g:

for Index in S'Range loop
S(Index) := To_Upper_Case(S(Index));
end loop;

Do you want me to call it "Convert_Current_Character_To_Upper_Case",
and wrap it in a procedure by that name?

- Bob

Robert A Duff

unread,
Jan 17, 2009, 6:06:37 PM1/17/09
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> Concerning syntax, I think we should have introduced proper procedural
> types with literals/aggregates of. Quite simple to do, IMO.

I mostly agree. What syntax would you propose for anonymous procedures?

- Bob

Dmitry A. Kazakov

unread,
Jan 18, 2009, 4:44:46 AM1/18/09
to

That is the most difficult part! It should allow both one-line coding style
when a mere [lazy] expression and a full-blown body with exception handlers
etc.

Georg Bauhaus

unread,
Jan 18, 2009, 1:34:21 PM1/18/09
to
Robert A Duff wrote:

> The loop body is usually self explanatory. E.g:

I wish it were, yes. A loop body _should_ be
elf explanatory. FWIW, I have not seen a loop
with just single statement in quite a while.
Hope things are in different shape elsewhere.

> for Index in S'Range loop
> S(Index) := To_Upper_Case(S(Index));
> end loop;
>
> Do you want me to call it "Convert_Current_Character_To_Upper_Case",
> and wrap it in a procedure by that name?

No, but I think I'd prefer something like

Iterate(S, Process => To_Upper_Case);

That is, To_Upper_Case is a good name, already.
The loop above is a "for-all" loop, Index is used
for nothing but a concrete, clumsy, and---if you
will---redundant handle of the abstraction "for-all".
So why a detailed loop?

Robert A Duff

unread,
Jan 18, 2009, 4:29:39 PM1/18/09
to
Georg Bauhaus <see.re...@maps.futureapps.de> writes:

> Robert A Duff wrote:
>
>> The loop body is usually self explanatory. E.g:
>
> I wish it were, yes. A loop body _should_ be
> elf explanatory. FWIW, I have not seen a loop
> with just single statement in quite a while.
> Hope things are in different shape elsewhere.

Not sure what you mean. I'm saying that Ada's current support for
iterators requires you to wrap the loop body in a named procedure.
The fact that people don't normally wrap loop bodies in procedures
(when using 'for' and 'while' loops) proves that doing so is a burden.

I want to create procedures for exactly the code that represents
a coherent abstraction -- and that's not necessarily the body of a loop.

>> for Index in S'Range loop
>> S(Index) := To_Upper_Case(S(Index));
>> end loop;
>>
>> Do you want me to call it "Convert_Current_Character_To_Upper_Case",
>> and wrap it in a procedure by that name?
>
> No, but I think I'd prefer something like
>
> Iterate(S, Process => To_Upper_Case);

Without the 'Access. ;-)

Normally, the loop body needs access to some local variable (or
parameter). Here's another example: Suppose we have a procedure
to send a character to an output stream:

procedure Put(Stream: in out ...; C: Character);

And we want to write a procedure to send a String. So we write:

procedure Put(Stream: in out ...; S : String) is
begin
for I in S'Range loop
Put(Stream, S(I));
end loop;
end Put;

It would be silly to write:

procedure Put(Stream: in out ...; S : String) is
procedure Put(C: Character) is
begin
Put(Stream, C);
end Put;
begin
for I in S'Range loop
Put(S(I));
end loop;
end Put;

No matter what you call that inner Put, it doesn't deserve to be a
named procedure at all. Note that it has to be nested, because
it needs to refer to Stream -- we can't create a reusable one
and put it in a library.

But if we have a Vector of Characters, or Linked_List of Characters,
instead of an array of Characters, we would be forced to write that
silly nested procedure.

Not sure whether we are agreeing or disagreeing, here... ;-)

> That is, To_Upper_Case is a good name, already.
> The loop above is a "for-all" loop, Index is used
> for nothing but a concrete, clumsy, and---if you
> will---redundant handle of the abstraction "for-all".
> So why a detailed loop?

I definitely agree with this part. The Index is conceptually
unnecessary. Furthermore, the fact that arrays and Vectors use
totally different syntax for iteration and element selection
and so forth is a Bad Thing.

Ideally, we want to say something like:

for C: Character in S loop -- Whether S is an array, or some other sequence data structure
<do something with C> -- not a named procedure
end loop;

- Bob

Georg Bauhaus

unread,
Jan 19, 2009, 6:52:33 AM1/19/09
to
Robert A Duff schrieb:

> Georg Bauhaus <see.re...@maps.futureapps.de> writes:
>
>> Robert A Duff wrote:
>>
>>> The loop body is usually self explanatory. E.g:
>> I wish it were, yes. A loop body _should_ be
>> elf explanatory. FWIW, I have not seen a loop
>> with just single statement in quite a while.
>> Hope things are in different shape elsewhere.
>
> Not sure what you mean. I'm saying that Ada's current support for
> iterators requires you to wrap the loop body in a named procedure.
> The fact that people don't normally wrap loop bodies in procedures
> (when using 'for' and 'while' loops) proves that doing so is a burden.

But the fact that people don't normally bother to wrap loop bodies in
procedures is not a prove that to do must be wrong, or that giving
a loop name might not in fact be preferrable. Yes, it is work to
find a good name but OTOH, it is considered good style, in particular
in Ada culture, to Say What You Mean. AFAIK.

I agree that the example you have given might show
some silly formalism. But again, is this a typical
scenario warranting more anonymity in Ada?

Eiffel's new anonymous agents (access sub parameters with
partially bound arguments) have met some criticism, too, BTW.

Here is another example, one active and one passive
iteration. Does the loop body deserve a captivating
title? Then, maybe in the form of a named local procedure.


function Active (Data: Vector; Threshold: Amount) return Amount is

N: Positive; -- nth item
Result: Amount;
Item: Amount;

begin
Result := 0.0;
N := 1;
for Index in First_Index(Data) .. Last_Index(Data) loop
Item := Element(Data, Index);
if Item < Threshold then
Result := ((N - 1) * Result + Item) / N;
N := N + 1;
else
Skipped := Skipped + 1;
end if;
end loop;
return Result;
end Active;

function Passive (Data: Vector; Threshold: Amount) return Amount is

N: Positive; -- nth item
Result: Amount;

procedure Incremental_Average(Position: in Cursor) is
Item: constant Amount := Element(Position);
begin
if Item < Threshold then
Result := ((N - 1) * Result + Item) / N;
N := N + 1;
else
Skipped := Skipped + 1;
end if;
end Incremental_Average;

begin
Result := 0.0;
N := 1;
Iterate(Data, Process => Incremental_Average'Access);
return Result;
end Passive;

In Active, the new syntax you have suggested will shorten
the loop body a bit, making Item's declaration in Active's
declarative part unneccesary. But still, there will be a
few lines left, worth a comment, at least? If so,
then why not write a named body?


Writing quick, anonymous, non-recursive lamdas is fun,
but there is inherent danger in making them a language
feature, I think. The danger is that they are going to
be used like they are being used in Python, or
Perl: spanning multiple lines, trying to be clever,
avoid finding a name, write them once, never understand
them again.

See also the proliferation of anonymous access ;-)
(I recall Vdim Gunko (I think) saying that adding named 'class
pointers to the Qt4 (C++) binding is too much of a burdon...

Georg Bauhaus

unread,
Jan 19, 2009, 7:39:36 AM1/19/09
to
Georg Bauhaus schrieb:

> See also the proliferation of anonymous access ;-)
> (I recall Vdim Gunko (I think)

That was Vadim Godunko. I'm sorry.

Randy Brukardt

unread,
Jan 19, 2009, 9:11:25 PM1/19/09
to
"Robert A Duff" <bob...@shell01.TheWorld.com> wrote in message
news:wccfxjg...@shell01.TheWorld.com...
...

>> I wish it were, yes. A loop body _should_ be
>> elf explanatory. FWIW, I have not seen a loop
>> with just single statement in quite a while.
>> Hope things are in different shape elsewhere.
>
> Not sure what you mean. I'm saying that Ada's current support for
> iterators requires you to wrap the loop body in a named procedure.
> The fact that people don't normally wrap loop bodies in procedures
> (when using 'for' and 'while' loops) proves that doing so is a burden.

I've lost the thread of this discussion, but the issue of iterators in Ada
with proper syntax is trivial IFF the language has the correct features. And
the feature that the language doesn't have that prevents a relatively easy
iterator is the one alluded to by the OP. I've spent a good portion of the
last two months thinking about these issues, and there is no getting around
the missing way to modify an element in place in a container. (I've several
times thought that I'd gotten around the problem, but it isn't practical to
do so.)

Watch Ada-Comment for my take on these problems, some coming very soon
(tonight, I hope).

Randy Brukardt.


0 new messages