user4599386
user4599386

Reputation:

Starting the next iteration of a loop immediately in Ada

I want to have an endless loop where the loop runs through nearly the entire program and at any point, based on a condition statement, I want it to exit that particular iteration of the loop and go back to the top and execute.

Is there a way this can be done?

It doesn't have to be an endless loop; it can be a for loop. I just want it to go to the next iteration of that loop.

Upvotes: 7

Views: 5564

Answers (4)

Artium
Artium

Reputation: 5329

To answer your question, the easiest way (syntax-wise) I am aware of is to use another loop, nested in the first one. Exiting the inner loop imitates a continue statement.

loop
    loop
        ...
        exit when Some_Condition;
        ...
    end loop;
end loop;

That said, If you need to do something like that, something smells bad. I woulkd personally use what ajb demonstrated in the begining of his answer, which is to use if statements. If the nesting level of the if statements gets too deep, you probably doing too much in the main and need to use functions/procedures anyway.

Upvotes: 3

ajb
ajb

Reputation: 31699

Ada doesn't have the equivalent of a continue. The simplest way to accomplish the same thing is probably just to put the rest of the loop in an if statement. So instead of something like this (here's an example where we're processing input lines and skipping those that begin with #):

while not End_Of_File (Input_File) loop
    ...
    Read_A_Line (Input_File, Line);
    if Line(Line'First) = "#" then
        continue;  -- ERROR--Ada doesn't have a continue statement
    end if;
    ... process the input line
end loop;

you could say

while not End_Of_File (Input_File) loop
    ...
    Read_A_Line (Input_File, Line);
    if Line(Line'First) /= "#" then
        ... process the input line
    end if;
end loop;

If it gets complicated, you may want to define a Boolean Need_To_Keep_Processing_Line or something. If you have several points where you need the equivalent of continue, you might end up with a multiply-nested if; if this gets too ugly, then one thing I sometimes do is multiple non-nested if's on the same Boolean:

if Need_To_Keep_Processing_Line then
    ...
    if something then
        if something-else then
            Need_To_Keep_Processing_Line := false;
        end if;
    end if;
end if;
if Need_To_Keep_Processing_Line then  -- again
    ...
end if;

Other alternatives have been mentioned: (1) goto; (2) use a procedure and return from various points; (3) exceptions. There are two problems with exceptions: first, this isn't really an exception, so you're using a construct for a purpose for which it wasn't intended, probably making your code less readable; and exceptions are inefficient (some compilers add extra code any time a block with an exception handler is entered; other compilers avoid this by setting up a table at compile time, but then a table search is required when an exception is raised). Using a procedure might be viable, depending on whether the loop body represents a concept that is easily named and identified. If it isn't, then extracting the loop body can hamper readability, because you're adding a procedure that doesn't really have a "procedure" purpose. The reason to avoid goto is that back in the 70's we used to use it indiscriminately, leading to a lot of tangled code that went every which way. Despite what you may have heard about it, it doesn't have to make code unreadable if used in a disciplined fashion. I generally don't use it. But I also avoid continue if programming in C-style languages, since to me it's just a glorified "goto" without the benefit of having a visible label at the end of your function to alert you to the fact that somebody is "going to" there.

But my real feeling about this is that if using if leads to ugly code, your loop body is probably too big and needs to be broken down anyway. The solution wouldn't be to revert to one of the other solutions (exceptions or goto), but rather to figure out the best way to make your loop body smaller and more readable.

Upvotes: 6

Keith Thompson
Keith Thompson

Reputation: 263497

Raise an exception that you handle in the body of the loop:

procedure Main is
    Try_Again: exception;
begin
    while Keep_Going loop
        begin
            -- lots of stuff
            if Give_Up_On_This_Iteration then
                raise Try_Again;
            end if;
            -- lots more stuff
        exception
            when Try_Again =>
                null;
        end;
    end loop;
end Main;

Upvotes: 4

Joe
Joe

Reputation: 357

You could use a goto statement

Upvotes: 5

Related Questions