Recent from talks
Nothing was collected or created yet.
For loop
View on Wikipedia
| Loop constructs |
|---|
In computer programming, a for loop is a structured control flow statement that repeatedly runs a section of code until a condition is satisfied.
A for loop has two parts: a header and a body. The header defines how the loop iterates, and the body is the code executed once per iteration. The header often declares a loop variable which can be used in the body to know which iteration of the loop is being executed. A relatively simple for loop iterates for a fixed number of times. For example, the following C for loop declares a loop variable i and prints its value as it increments from 0, 1, and 2:
for (int i = 0; i < 3; ++i) {
printf("%d", i);
}
Depending on programming language, various keywords are used to denote a for loop. For example, descendants of ALGOL use for,[1] while descendants of Fortran use do and COBOL uses PERFORM VARYING.
Variations
[edit]
Generally, a for loop falls into one of the following categories:
Numeric
[edit]A numeric for loop increments a control variable from a start value to and end value. In languages such as ALGOL, Simula, BASIC, Pascal, Modula, Oberon, Ada, MATLAB, OCaml, and F# it looks like:
for i = first to last do statement
Some languages support an optional step value (increment or decrement). Some languages require a separate declaration of the control variable.
3 part
[edit]A 3-part for loop, popularized by C, has the following parts separated by semi-colons: initialization (loop variant), condition, and advancement to the next value. Each part is optional and can be blank. This syntax came from B programming language and was originally invented by Stephen C. Johnson.[2] In the initialization part, any variables needed are declared and assigned values. The condition part checks a condition and exits the loop if false, even if the loop is never executed. If the condition is true, then the loop's block of is executed. The advancement to the next iteration part is performed each time the block is executed.
The following Java code is a C-style numeric loop that prints the numbers from 0 to 99.
for (int i = 0; i < 100; ++i) {
System.out.printf("%d", i );
}
This form is often used like the numeric for loop, but is more flexible and can be used for other patterns. For example, for (start(); done(); next()) calls functions instead of using a control variable. The pattern of an infinite loop is implemented as for (;;).
Iterator-based
[edit]A foreach loop enumerates the items of a sequence. It is usually uses an implicit or explicit iterator, in which the loop variable represents each value of the sequence. The following Python code shows a foreach loop. items is either a data collection that supports implicit iteration, or may be an iterator itself.
for item in items:
do_something(item)
Vectorized
[edit]Some languages offer a for loop that acts as if processing all iterations in parallel, such as the for all keyword in Fortran 95 which has the interpretation that all right-hand-side expressions are evaluated before any assignments are made, as distinct from the explicit iteration form. For example, in the for statement in the following pseudocode fragment, when calculating the new value for A(i), except for the first (with i = 2) the reference to A(i - 1) will obtain the new value that had been placed there in the previous step. In the for all version, however, each calculation refers only to the original, unaltered A.
for i := 2 : N - 1 do A(i) := [A(i - 1) + A(i) + A(i + 1)] / 3; next i; for all i := 2 : N - 1 do A(i) := [A(i - 1) + A(i) + A(i + 1)] / 3;
The difference may be significant.
Some languages (such as PL/I, Fortran 95) also offer array assignment statements, that enable many for loops to be omitted. Thus pseudocode such as A:= 0; would set all elements of array A to zero, no matter its size or dimensionality. The example loop could be rendered as
A(2 : N - 1) := [A(1 : N - 2) + A(2 : N - 1) + A(3 : N)] / 3;
But whether that would be rendered in the style of the for loop or the for-all-loop or something else may not be clearly described in the compiler manual.
Numeric & while
[edit]Introduced with ALGOL 68 and followed by PL/I, the compound numeric and while for loop iterates while the control value increments (as a numeric for loop) and while a condition is true. If the condition evaluates to false, then the loop exits before the loop variable reaches the last value. In the following code, i starts at 1 and the loops iterates until either i is N or Done is true.
for i := 1 : N while not Done do Something()
Loop counters
[edit]In computer programming, a loop counter is a control variable that controls the iterations of a loop (a computer programming language construct). It is so named because most uses of this construct result in the variable taking on a range of integer values in some orderly sequences (for example., starting at 0 and ending at 10 in increments of 1)
Loop counters change with each iteration of a loop, providing a unique value for each iteration. The loop counter is used to decide when the loop should terminate and for the program flow to continue to the next instruction after the loop.
A common identifier naming convention is for the loop counter to use the variable names i, j, and k (and so on if needed), where i would be the most outer loop, j the next inner loop, etc. The reverse order is also used by some programmers. This style is generally agreed to have originated from the early programming of Fortran[citation needed], where these variable names beginning with these letters were implicitly declared as having an integer type, and so were obvious choices for loop counters that were only temporarily required. The practice dates back further to mathematical notation where indices for sums and multiplications are often i, j, etc. A variant convention is the use of duplicated letters for the index, ii, jj, and kk, as this allows easier searching and search-replacing than using a single letter.[3]
Example
[edit]An example of C code involving nested for loops, where the loop counter variables are i and j:
for (int i = 0; i < 100; i++) {
for (int j = i; j < 10; j++) {
someFunction(i, j);
}
}
Loops in C can also be used to print the reverse of a word. As:
for (int i = 0; i < 6; i++) {
scanf("%c", &a[i]);
}
for (int i = 4; i >= 0; i--) {
printf("%c", a[i]);
}
Here, if the input is apple, the output will be elppa.
Additional semantics and constructs
[edit]Use as infinite loops
[edit]This C-style for loop is commonly the source of an infinite loop since the fundamental steps of iteration are completely in the control of the programmer. When infinite loops are intended, this type of for loop can be used (with empty expressions), such as:
for (;;) {
// loop body
}
This style is used instead of infinite while (true) loops to avoid a type conversion warning in some C/C++ compilers.[4] Some programmers prefer the more succinct for (;;) form over the semantically equivalent but more verbose while (true) form.
Early exit and continuation
[edit]Some languages may also provide other supporting statements, which when present can alter how the for loop iteration proceeds. Common among these are the break and continue statements found in C and its derivatives. The break statement causes the innermost loop to be terminated immediately when executed. The continue statement will move at once to the next iteration without further progress through the loop body for the current iteration. A for statement also terminates when a break, goto, or return statement within the statement body is executed.[Wells] Other languages may have similar statements or otherwise provide means to alter the for loop progress; for example in Fortran 90:
DO I = 1, N
statements!Executed for all values of "I", up to a disaster if any.
IF (no good) CYCLE! Skip this value of "I", and continue with the next.
Statements!Executed only where goodness prevails.
IF (disaster) EXIT! Abandon the loop.
Statements!While good and, no disaster.
END DO! Should align with the "DO".
Some languages offer further facilities such as naming the various loop constructs so that with multiple nested loops there is no doubt as to which loop is involved. Fortran 90, for example:
X1:DO I = 1, N
statements
X2:DO J = 1, M
statements
IF (trouble) CYCLE X1
statements
END DO X2
statements
END DO X1
Thus, when "trouble" is detected in the inner loop, the CYCLE X1 (not X2) means that the skip will be to the next iteration for I, not J. The compiler will also be checking that each END DO has the appropriate label for its position: this is not just a documentation aid. The programmer must still code the problem correctly, but some possible blunders will be blocked.
Loop variable scope and semantics
[edit]Different languages specify different rules for what value the loop variable will hold on termination of its loop, and indeed some hold that it "becomes undefined". This permits a compiler to generate code that leaves any value in the loop variable, or perhaps even leaves it unchanged because the loop value was held in a register and never stored in memory. Actual behavior may even vary according to the compiler's optimization settings, as with the Honeywell Fortran66 compiler.
In some languages (not C or C++) the loop variable is immutable within the scope of the loop body, with any attempt to modify its value being regarded as a semantic error. Such modifications are sometimes a consequence of a programmer error, which can be very difficult to identify once made. However, only overt changes are likely to be detected by the compiler. Situations, where the address of the loop variable is passed as an argument to a subroutine, make it very difficult to check because the routine's behavior is in general unknowable to the compiler unless the language supports procedure signatures and argument intents. Some examples in the style of pre-Fortran-90:
DO I = 1, N
I = 7 !Overt adjustment of the loop variable. Compiler should complain
Z = ADJUST(I) !Function "ADJUST" might alter "I", to uncertain effect.
PRINT *, (A(I), B(I), I = 1, N, 2) !Implicit for loop to print odd elements of arrays A and B, reusing "I"... Compiler should complain.
PRINT *, I ! What value will be presented?
END DO! How many times will the loop be executed?
A common approach is to calculate the iteration count at the start of a loop (with careful attention to overflow as in for i:= 0: 65535 do ... ; in sixteen-bit integer arithmetic) and with each iteration decrement this count while also adjusting the value of I: double counting results. However, adjustments to the value of I within the loop will not change the number of iterations executed.
Still, another possibility is that the code generated may employ an auxiliary variable as the loop variable, possibly held in a machine register, whose value may or may not be copied to I on each iteration. Again, modifications of I would not affect the control of the loop, but now a disjunction is possible: within the loop, references to the value of I might be to the (possibly altered) current value of I or to the auxiliary variable (held safe from improper modification) and confusing results are guaranteed. For instance, within the loop a reference to element I of an array would likely employ the auxiliary variable (especially if it were held in a machine register), but if I is a parameter to some routine (for instance, a print-statement to reveal its value), it would likely be a reference to the proper variable I instead. It is best to avoid such possibilities.
Adjustment of bounds
[edit]Just as the index variable might be modified within a for loop, so also may its bounds and direction. But to uncertain effect. A compiler may prevent such attempts, they may have no effect, or they might even work properly - though many would declare that to do so would be wrong. Consider a statement such as
for i := first : last : step do A(i) := A(i) / A(last);
If the approach to compiling such a loop was to be the evaluation of first, last and step and the calculation of an iteration count via something like (last - first)/step once only at the start, then if those items were simple variables and their values were somehow adjusted during the iterations, this would have no effect on the iteration count even if the element selected for division by A(last) changed.
List of value ranges
[edit]ALGOL 60, PL/I, and ALGOL 68, allow loops in which the loop variable is iterated over a list of ranges of values instead of a single range. The following PL/I example will execute the loop with six values of i: 1, 7, 12, 13, 14, 15:
do i = 1, 7, 12 to 15;
/*statements*/
end;
Equivalence with while-loops
[edit]A for loop is generally equivalent to a while-loop:
factorial := 1
for counter from 2 to 5
factorial := factorial * counter
counter:= counter - 1
print counter + "! equals " + factorial
Is equivalent to:
factorial := 1
counter := 1
while counter < 5
counter := counter + 1
factorial := factorial * counter
print counter + "! equals " + factorial
As demonstrated by the output of the variables.
Timeline of the for loop syntax in various programming languages
[edit]Given an action that must be repeated, for instance, five times, different languages' for loops will be written differently. The syntax for a three-expression for loop is nearly identical in all languages that have it, after accounting for different styles of block termination and so on.
1957: FORTRAN
[edit]Fortran's equivalent of the for loop is the DO loop, using the keyword do instead of for, The syntax of Fortran's DO loop is:
DO label counter = first, last, step
statements
label statement
The following two examples behave equivalently to the three argument for loop in other languages, initializing the counter variable to 1, incrementing by 1 each iteration of the loop, and stopping at five (inclusive).
DO 9, ICOUNT = 1, 5, 1
WRITE (6,8) ICOUNT
8 FORMAT( I2 )
9 CONTINUE
As of Fortran 90, block structured END DO was added to the language. With this, the end of loop label became optional:
do icounter = 1, 5
write(*, '(i2)') icounter
end do
The step part may be omitted if the step is one. Example:
* DO loop example.
PROGRAM MAIN
INTEGER SUMSQ
SUMSQ = 0
DO 199 I = 1, 9999999
IF (SUMSQ.GT.1000) GO TO 200
199 SUMSQ = SUMSQ + I**2
200 PRINT 206, SUMSQ
206 FORMAT( I2 )
END
In Fortran 90, the GO TO may be avoided by using an EXIT statement.
* DO loop example.
program main
implicit none
integer:: sumsq
integer:: i
sumsq = 0
do i = 1, 9999999
if (sumsq > 1000) exit
sumsq = sumsq + i**2
end do
print *, sumsq
end program
Alternatively, a DO - WHILE construct could be used:
program main
implicit none
integer:: sumsq
integer:: i
sumsq = 0
i = 0
do while (sumsq <= 1000)
i = i+1
sumsq = sumsq + i**2
end do
print *, sumsq
end program
1958: ALGOL
[edit]ALGOL 58 introduced the for statement, using the form as Superplan:
FOR Identifier = Base (Difference) Limit
For example to print 0 to 10 incremented by 1:
FOR x = 0 (1) 10 BEGIN
PRINT (FL) = x END
In ALGOL 60 the looping construct was changed. A series of 'for list elements', separated by commas, can be specified. An element can either be an arithmetic expression element, a 'step-until' element, or a 'while' element.
To print from 0 to 10, then the number 42:
for x := 0 step 1 until 10, 42 do
begin
outinteger (1, x);
outstring (1, "\n")
end;
A mostly equivalent loop using a 'while' element could be written:
x := 0;
for x := x while x <= 10, 42 do
begin
outinteger (1, x);
outstring (1, "\n");
x := x + 1
end;
Note the value of x after the first loop has completed will be 42, whereas in the second loop it will be 43.
1960: COBOL
[edit]COBOL was formalized in late 1959 and has had many elaborations. It uses the PERFORM verb which has many options. Originally all loops had to be out-of-line with the iterated code occupying a separate paragraph. Ignoring the need for declaring and initializing variables, the COBOL equivalent of a for loop would be.
PERFORM SQ-ROUTINE VARYING I FROM 1 BY 1 UNTIL I > 1000
SQ-ROUTINE
ADD I**2 TO SUM-SQ.
In the 1980s, the addition of in-line loops and structured programming statements such as END-PERFORM resulted in a for loop with a more familiar structure.
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 1000
ADD I**2 TO SUM-SQ.
END-PERFORM
If the PERFORM verb has the optional clause TEST AFTER, the resulting loop is slightly different: the loop body is executed at least once, before any test.
1964: BASIC
[edit]In BASIC, a loop is sometimes named a for-next loop.
10 REM THIS FOR LOOP PRINTS ODD NUMBERS FROM 1 TO 15
20 FOR I = 1 TO 15 STEP 2
30 PRINT I
40 NEXT I
The end-loop marker specifies the name of the index variable, which must correspond to the name of the index variable at the start of the for loop. Some languages (PL/I, Fortran 95, and later) allow a statement label at the start of a for loop that can be matched by the compiler against the same text on the corresponding end-loop statement. Fortran also allows the EXIT and CYCLE statements to name this text; in a nest of loops, this makes clear which loop is intended. However, in these languages, the labels must be unique, so successive loops involving the same index variable cannot use the same text nor can a label be the same as the name of a variable, such as the index variable for the loop.
1964: PL/I
[edit]The PL/I DO statement can act as either a for loop, a while loop, or a do until loop.
do counter = 1 to 5 by 1; /* "by 1" is the default if not specified */
/*statements*/;
end;
The LEAVE statement may be used to exit the loop. Loops can be labeled, and leave may leave a specific labeled loop in a group of nested loops. Some PL/I dialects include the ITERATE statement to terminate the current loop iteration and begin the next.
1968: ALGOL 68
[edit]ALGOL 68 has what was considered the universal loop, the full syntax is:
FOR i FROM 1 BY 2 TO 3 WHILE i≠4 DO ~ OD
Further, the single iteration range could be replaced by a list of such ranges. There are several unusual aspects of the construct
- only the
do ~ odportion was compulsory, in which case the loop will iterate indefinitely. - thus the clause
to 100 do ~ od, will iterate exactly 100 times. - The
whilesyntactic element allowed a programmer to break from aforloop early, as in:
INT sum sq := 0;
FOR i
WHILE
print(("So far:", i, new line)); # Interposed for tracing purposes. #
sum sq ≠ 70↑2 # This is the test for the WHILE #
DO
sum sq +:= i↑2
ODSubsequent extensions to the standard ALGOL 68 allowed the to syntactic element to be replaced with upto and downto to achieve a small optimization. The same compilers also incorporated:
until- for late loop termination.
foreach- for working on arrays in parallel.
1970: Pascal
[edit]for Counter:= 1 to 5 do
(*statement*);
Decrementing (counting backwards) is using downto keyword instead of to, as in:
for Counter:= 5 downto 1 do
(*statement*);
The numeric range for loop varies somewhat more.
1972: C, C++
[edit]for (initialization; condition; increment/decrement)
statement
The statement is often a block statement; an example of this would be:
//Using for loops to add numbers 1 - 5
int sum = 0;
for (int i = 1; i <= 5; ++i) {
sum += i;
}
The ISO/IEC 9899:1999 publication (commonly known as C99) also allows initial declarations in for loops. All three sections in the for loop are optional, with an empty condition equivalent to true.
1972: Smalltalk
[edit]1 to: 5 do: [ :counter | "statements" ]
Contrary to other languages, in Smalltalk a for loop is not a language construct but is defined in the class Number as a method with two parameters, the end value and a closure, using self as start value.
1980: Ada
[edit]for Counter in 1 .. 5 loop
-- statements
end loop;
The exit statement may be used to exit the loop. Loops can be labeled, and exit may leave a specifically labeled loop in a group of nested loops:
Counting:
For Counter in 1 .. 5 loop
Triangle:
for Secondary_Index in 2 .. Counter loop
-- statements
exit Counting;
-- statements
end loop Triangle;
end loop Counting;
1980: Maple
[edit]Maple has two forms of for loop, one for iterating over a range of values, and the other for iterating over the contents of a container. The value range form is as follows:
for i from f by b to t while w do
# loop body
od;
All parts except do and od are optional. The for I part, if present, must come first. The remaining parts (from f, by b, to t, while w) can appear in any order.
Iterating over a container is done using this form of loop:
for e in c while w do
# loop body
od;
The in c clause specifies the container, which may be a list, set, sum, product, unevaluated function, array, or object implementing an iterator.
A for loop may be terminated by od, end, or end do.
1982: Maxima CAS
[edit]In Maxima CAS, one can use also integer values:
for x:0.5 step 0.1 thru 0.9 do
/* "Do something with x" */
1982: PostScript
[edit]The for loop, written as [initial] [increment] [limit] { ... } for initializes an internal variable, and executes the body as long as the internal variable is not more than the limit (or not less, if the increment is negative) and, at the end of each iteration, increments the internal variable. Before each iteration, the value of the internal variable is pushed onto the stack.[5]
1 1 6 {STATEMENTS} for
There is also a simple repeat loop.
The repeat-loop, written as X { ... } repeat, repeats the body exactly X times.[6]
5 { STATEMENTS } repeat
1983: Ada 83 and above
[edit]procedure Main is
Sum_Sq : Integer := 0;
begin
for I in 1 .. 9999999 loop
if Sum_Sq <= 1000 then
Sum_Sq := Sum_Sq + I**2
end if;
end loop;
end;
1984: MATLAB
[edit]for n = 1:5
-- statements
end
After the loop, n would be 5 in this example.
As i is used for the Imaginary unit, its use as a loop variable is discouraged.
1987: Perl
[edit]for ($counter = 1; $counter <= 5; $counter++) { # implicitly or predefined variable
# statements;
}
for (my $counter = 1; $counter <= 5; $counter++) { # variable private to the loop
# statements;
}
for (1..5) { # variable implicitly called $_; 1..5 creates a list of these 5 elements
# statements;
}
statement for 1..5; # almost same (only 1 statement) with natural language order
for my $counter (1..5) { # variable private to the loop
# statements;
}
"There's more than one way to do it" is a Perl programming motto.
1988: Mathematica
[edit]The construct corresponding to most other languages' for loop is named Do in Mathematica.
Do[f[x], {x, 0, 1, 0.1}]
Mathematica also has a For construct that mimics the for loop of C-like languages.
For[x= 0 , x <= 1, x += 0.1,
f[x]
]
1989: Bash
[edit]# first form
for i in 1 2 3 4 5
do
# must have at least one command in a loop
echo $i # just print the value of i
done
# second form
for (( i = 1; i <= 5; i++ ))
do
# must have at least one command in a loop
echo $i # just print the value of i
done
An empty loop (i.e., one with no commands between do and done) is a syntax error. If the above loops contained only comments, execution would result in the message "syntax error near unexpected token 'done'".
1990: Haskell
[edit]In Haskell98, the function mapM_ maps a monadic function over a list, as
mapM_ print [4, 3 .. 1]
-- prints
-- 4
-- 3
-- 2
-- 1
The function mapM collects each iteration result in a list:
result_list <- mapM (\ indx -> do{ print indx; return (indx - 1) }) [1..4]
-- prints
-- 1
-- 2
-- 3
-- 4
-- result_list is [0,1,2,3,4]
Haskell2010 adds functions forM_ and forM, which are equivalent to mapM_ and mapM, but with their arguments flipped:
forM_ [0..3] $ \ indx -> do
print indx
-- prints
-- 0
-- 1
-- 2
-- 3
result_list <- forM ['a'..'d'] $ \ indx -> do
print indx
return indx
-- prints
-- 'a'
-- 'b'
-- 'c'
-- 'd'
-- result_list is ['a','b','c','d']
When compiled with optimization, none of the expressions above will create lists. But, to save the space of the [1..5] list if optimization is turned off, a forLoop_ function could be defined as
import Control.Monad as M
forLoop_ :: Monad m => a -> (a -> Bool) -> (a -> a) -> (a -> m ()) -> m ()
forLoop_ startIndx test next f = theLoop startIndx
where
theLoop indx = M.when (test indx) $ do
f indx
theLoop (next indx)
and used as
forLoopM_ (0::Int) (< len) (+1) $ \indx -> do
-- statements
1991: Oberon-2, Oberon-07, Component Pascal
[edit]FOR Counter:= 1 TO 5 DO
(* statement sequence *)
END
In the original Oberon language, the for loop was omitted in favor of the more general Oberon loop construct. The for loop was reintroduced in Oberon-2.
1991: Python
[edit]
Python does not contain the classical for loop, rather a foreach loop is used to iterate over the output of the built-in range() function which returns an iterable sequence of integers.
for i in range(1, 6): # gives i values from 1 to 5 inclusive (but not 6)
# statements
print(i)
# if we want 6 we must do the following
for i in range(1, 6 + 1): # gives i values from 1 to 6
# statements
print(i)
Using range(6) would run the loop from 0 to 5.
When the loop variable is not needed, it is common practice to use an underscore (_) as a placeholder. This convention signals to other developers that the variable will not be used inside the loop. For example:
for _ in range(5):
print("Hello")
This will print “Hello” five times without using the loop variable.
1993: AppleScript
[edit]repeat with i from 1 to 5
-- statements
log i
end repeat
It can also iterate through a list of items, similar to what can be done with arrays in other languages:
set x to {1, "waffles", "bacon", 5.1, false}
repeat with i in x
log i
end repeat
A exit repeat may also be used to exit a loop at any time. Unlike other languages, AppleScript currently has no command to continue to the next iteration of a loop.
1993: Crystal
[edit]for i = start, stop, interval do
-- statements
end
So, this code
for i = 1, 5, 2 do
print(i)
end
will print:
1 3 5
A for loop can also loop through a table using
ipairs()
to iterate numerically through arrays and
pairs()
to iterate randomly through dictionaries.
Generic for loop making use of closures:
for name, phone, and address in contacts() do
-- contacts() must be an iterator function
end
1995: ColdFusion Markup Language (CFML)
[edit]Script syntax
[edit]Simple index loop:
for (i = 1; i <= 5; i++) {
// statements
}
Using an array:
for (i in [1,2,3,4,5]) {
// statements
}
Using a list of string values:
loop index="i" list="1;2,3;4,5" delimiters=",;" {
// statements
}
The above list example is only available in the dialect of CFML used by Lucee and Railo.
Tag syntax
[edit]Simple index loop:
<cfloop index="i" from="1" to="5">
<!--- statements --->
</cfloop>
Using an array:
<cfloop index="i" array="#[1,2,3,4,5]#">
<!--- statements --->
</cfloop>
Using a "list" of string values:
<cfloop index="i" list="1;2,3;4,5" delimiters=",;">
<!--- statements --->
</cfloop>
1995: Java
[edit]for (int i = 0; i < 5; i++) {
//perform functions within the loop;
//can use the statement 'break;' to exit early;
//can use the statement 'continue;' to skip the current iteration
}
For the extended for loop, see Foreach loop § Java.
1995: JavaScript
[edit]JavaScript supports C-style "three-expression" loops. The break and continue statements are supported inside loops.
for (var i = 0; i < 5; i++) {
// ...
}
Alternatively, it is possible to iterate over all keys of an array.
for (var key in array) { // also works for assoc. arrays
// use array[key]
...
}
1995: PHP
[edit]This prints out a triangle of *
for ($i = 0; $i <= 5; $i++) {
for ($j = 0; $j <= $i; $j++) {
echo "*";
}
echo "<br />\n";
}
1995: Ruby
[edit]for the counter in 1..5
# statements
end
5.times do |counter| # counter iterates from 0 to 4
# statements
end
1.upto(5) do |counter|
# statements
end
Ruby has several possible syntaxes, including the above samples.
1996: OCaml
[edit]See expression syntax.[7]
(* for_statement:= "for" ident '=' expr ( "to" ∣ "down to" ) expr "do" expr "done" *)
for i = 1 to 5 do
(* statements *)
done ;;
for j = 5 down to 0 do
(* statements *)
done ;;
1998: ActionScript 3
[edit]for (var counter:uint = 1; counter <= 5; counter++){
//statement;
}
2008: Small Basic
[edit]For i = 1 To 10
' Statements
EndFor
2008: Nim
[edit]Nim has a foreach-type loop and various operations for creating iterators.[8]
for i in 5 .. 10:
# statements
2009: Go
[edit]for i := 0; i <= 10; i++ {
// statements
}
2010: Rust
[edit]for i in 0..10 {
// statements
}
2011: Kotlin
[edit]for (i in 1..10) {
// statements
}
2012: Julia
[edit]for j = 1:10
# statements
end
See also
[edit]References
[edit]- ^ Wirth, Niklaus (1973). "Preface". Systematic Programming: An Introduction. Prentice-Hall. pp. xiii. ISBN 0138803692.
- ^ Thompson, Ken. VCF East 2019 – Brian Kernighan interviews Ken Thompson. YouTube. Archived from the original on 2021-12-12. Retrieved 2020-11-16.
I saw Johnson's semicolon version of the for loop and I put that in [B], I stole it.
- ^ http://www.knosof.co.uk/vulnerabilities/loopcntrl.pdf Analysis of loop control variables in C
- ^ "Compiler Warning (level 4) C4127". Microsoft. Retrieved 29 June 2011.
- ^ PostScript Language Reference. Addison-Wesley Publishing Company. 1999. p. 596. ISBN 0-201-37922-8.
- ^ "PostScript Tutorial - Loops".
- ^ "OCaml expression syntax". Archived from the original on 2013-04-12. Retrieved 2013-03-19.
- ^ https://nim-lang.org/docs/system.html#...i%2CT%2CT ".. iterator"
For loop
View on Grokipediafor (initialization; condition; update) {
// body executed repeatedly
}
for (initialization; condition; update) {
// body executed repeatedly
}
for item in iterable:
# body executed for each item
for item in iterable:
# body executed for each item
Definition and Fundamentals
Core Concept and Syntax
A for loop is a repetition control structure in programming that executes a block of code a predetermined number of times, typically managed by a counter variable to iterate through a known range or sequence.[2] This structure provides a concise way to handle repetitive tasks, distinguishing it from indefinite loops like while statements by its emphasis on a fixed iteration count.[8] The basic pseudocode syntax for a traditional for loop follows the form:for (initialization; condition; increment) {
body
}
for (initialization; condition; increment) {
body
}
Initialization, Condition, and Iteration
In the traditional for loop construct, the initialization clause is executed exactly once before the loop body begins, typically to declare and set an initial value for a loop control variable, such as a counter starting at zero. This step ensures the loop begins from a defined state, often involving simple assignment likei = 0 in languages like C.[14]
The condition clause, a boolean expression, is evaluated prior to each iteration of the loop body; if it evaluates to true (or non-zero in languages without explicit booleans), the body executes, but if false, the loop terminates immediately without entering or continuing the body. For instance, a condition such as i < n checks whether the counter remains within the desired bounds, controlling the number of iterations based on the problem's requirements.[14]
Following the execution of the loop body, the iteration clause—also known as the update or increment—is performed to modify the loop control variable, preparing it for the next condition check. This often involves incrementing the counter, as in i++, but can include more complex updates like i += 2 for stepping through values at intervals.[14] The full execution flow proceeds as: initialization (once), condition evaluation, body (if true), iteration, then repeat from condition until false.
These clauses collectively manage the loop's lifecycle, with the counter variable's role in initialization, testing, and updating detailed further in discussions of loop counters. Omitting the initialization clause assumes prior setup of the control variable, while an always-true condition can lead to unbounded execution, though such cases are handled through other control mechanisms. In the C programming language, for example, the syntax for (i = 0; i < 10; i++) { /* body */ } illustrates this flow, where all clauses are optional but the structure enforces the specified order per ISO/IEC 9899 standards.
Variations of For Loops
Traditional Indexed For Loops
Traditional indexed for loops represent the classic form of the for loop construct, featuring explicit initialization of a counter variable, a condition that checks against predefined bounds, and an increment or update expression to advance the counter after each iteration. This structure is prevalent in imperative programming languages such as C, C++, Java, and JavaScript, where the syntax typically follows the pattern offor (initialization; condition; increment) { body }. The initialization sets the starting value of the index (often 0 for zero-based arrays), the condition evaluates to true for continuation (e.g., index less than array length), and the increment updates the index (e.g., i++).[15][16][17]
These loops are commonly applied in scenarios requiring direct access to array elements via numerical indices or performing repetitive numerical operations, such as summing values in an array or processing fixed-size datasets. For instance, in array traversal, the loop iterates over each element by referencing array[i], enabling operations like accumulation or transformation. In mathematical summations, a typical implementation might initialize a sum to zero and add array[i] within the loop body until the bounds are reached. This form is particularly suited to scientific computing tasks where precise iteration over known ranges is essential.[16][17][18]
The primary advantages of traditional indexed for loops include precise control over the iteration process, allowing developers to customize step sizes, reverse direction, or skip elements as needed, which supports flexible traversal patterns beyond simple sequential access. They offer conceptual simplicity, making them straightforward for expressing definite iterations in parallel contexts, such as distributed computing where static analysis of affine indices can optimize communication overhead. Additionally, their efficiency shines with fixed-size collections, as the explicit bounds and increments facilitate compiler optimizations without runtime overhead from iterators.[19][18]
However, these loops can be verbose, necessitating manual management of initialization, conditions, and increments, which increases code length compared to higher-level abstractions. They are prone to errors, particularly off-by-one mistakes where the index exceeds array bounds or misses elements at the endpoints, a common pitfall in array-based operations. This sequential indexing also inherently suggests ordered execution, potentially complicating parallelization without additional transformations.[20][21]
A representative pseudocode example for processing an array via indexing is:
for (int i = 0; i < length; i++) {
process(element[i]);
}
for (int i = 0; i < length; i++) {
process(element[i]);
}
Iterator-Based For Loops
Iterator-based for loops, also known as enhanced for loops or foreach loops, provide a syntax for traversing collections or iterables without explicitly managing indices or counters. The general form isfor (element : collection), where each element of the collection is sequentially assigned to the loop variable for processing within the loop body. This construct abstracts away the traditional initialization, condition, and increment steps of indexed loops, focusing instead on the elements themselves.[17]
The mechanism relies on iterator objects or enumerator methods provided by the collection. In languages like Java, the enhanced for loop implicitly calls the iterator() method on collections implementing the Iterable interface, advancing through elements via hasNext() and next() until exhausted. Similarly, in C#, the foreach statement invokes GetEnumerator() on types implementing IEnumerable or IEnumerable<T>, using the enumerator's MoveNext() method and Current property to yield elements sequentially. Python's for loop operates on any iterable by calling its __iter__() method to obtain an iterator, which supplies elements one by one through __next__(). In C++, the range-based for loop (introduced in C++11) uses the range's begin() and end() functions to establish iterators, dereferencing them to access elements in order. This iterator-driven approach ensures sequential access while hiding the underlying traversal logic.[17][22][23][24]
These loops find primary applications in object-oriented and functional programming languages for iterating over data structures such as lists, sets, arrays, and maps. For instance, in Java, they are used to process elements in ArrayList or HashSet without needing explicit iteration code. Python employs them for traversing sequences like lists or dictionaries (via .items() for key-value pairs). C# applies foreach to collections like List<T> or arrays, and C++ uses range-based loops for standard containers such as std::vector or std::string. This makes them ideal for tasks like summing values, filtering elements, or performing operations on each item in a collection, promoting code that works polymorphically across compatible types.[17][23][22][24]
Key benefits include reduced boilerplate code by eliminating manual index management, which minimizes errors like off-by-one bounds issues common in traditional loops. They enhance readability and maintainability, allowing developers to focus on element processing rather than traversal mechanics, and support polymorphism by operating uniformly on any iterable or enumerable type. For example, in Python:
words = ['cat', 'window', 'defenestrate']
for w in words:
print(w, len(w))
words = ['cat', 'window', 'defenestrate']
for w in words:
print(w, len(w))
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int item : numbers) {
[System](/page/System).out.println("Count is: " + item);
}
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int item : numbers) {
[System](/page/System).out.println("Count is: " + item);
}
Vectorized and Implicit For Loops
Vectorized and implicit for loops represent an optimization paradigm in programming, particularly in numerical and scientific computing, where iteration over collections of data—such as arrays or vectors—is performed without explicit loop constructs or visible counters. Instead, these loops rely on language or library features that apply operations element-wise across entire data structures in a single statement, implicitly handling the repetition. This approach contrasts with traditional explicit loops by shifting the iteration logic to optimized, low-level implementations, often executed in compiled code rather than interpreted loops.[25][26] The mechanism underlying vectorized and implicit loops typically involves array broadcasting and universal functions (ufuncs) in libraries like NumPy, where operations on arrays of compatible shapes are automatically expanded to match dimensions without copying data or using explicit indices. For instance, in NumPy, adding a scalar to an array implicitly applies the addition to each element, leveraging C-level loops for efficiency. Similarly, MATLAB's vectorization revises scalar-oriented code into matrix and vector operations, such asA + B for element-wise addition of matrices, which the interpreter processes without user-defined loops. These implementations often harness SIMD (Single Instruction, Multiple Data) instructions available in modern CPUs, allowing simultaneous processing of multiple data elements in a single operation, as supported by compilers like Intel's oneAPI DPC++/C++.[25][26]
In applications such as scientific computing and data processing, vectorized loops enable concise expressions for bulk operations, like computing the sum of an array with np.sum(A) in NumPy, which replaces a manual loop accumulating values element by element. This is prevalent in fields requiring high-throughput numerical analysis, where functions like element-wise multiplication or statistical aggregations process large datasets efficiently without per-element iteration in user code. In R, vector arithmetic supports implicit iteration, as in x + y for two vectors, avoiding explicit loops like for(i in 1:length(x)) { result[i] <- x[i] + y[i] }, and functions like sapply extend this to more complex transformations over sequences.[25][27]
The primary advantages of vectorized and implicit for loops include substantial performance gains—often orders of magnitude faster than interpreted loops due to reduced overhead and SIMD utilization—and improved code readability through succinct syntax for mathematical operations on aggregates. For example, MATLAB documentation highlights that vectorized code often runs much faster than equivalent looped versions for large arrays by minimizing interpretive steps. However, drawbacks include restrictions to operations compatible with array data types, potential memory inefficiencies from temporary arrays in broadcasting, and obscured performance bottlenecks, as the implicit nature may prevent fine-tuned optimizations for irregular data patterns.[26][25]
Loop Counters and Variables
Role and Management of Counters
In a for loop, the counter plays a central role in tracking iteration progress and enforcing finite execution by maintaining state across loop cycles. It is typically initialized to a starting value, such as zero for ascending sequences, and incremented or updated after each body execution, while being tested against a boundary condition before each iteration to determine continuation. This mechanism ensures controlled repetition, as seen in standard definitions where the counter advances from a low bound to a high bound, preventing unbounded runs.[28][29] Management of the counter begins with its declaration, commonly as an integer type to support exact arithmetic, followed by initialization in the loop's opening clause to set the initial state. The update occurs via the iteration clause, often using increment operators like++ for sequential progression or custom logic for non-linear steps, ensuring the counter reflects cumulative advancement. These operations are executed in a fixed sequence—initialization once, then repeated condition checks and updates— to synchronize iteration with the program's intent.[28]
Best practices emphasize selecting appropriate types for reliability: unsigned integers, such as size_t in C for non-negative counts, align with container sizes and array lengths, reducing comparison mismatches and supporting large ranges without sign-related artifacts. Floating-point types should be avoided as counters due to precision limitations that can cause erratic iteration counts from rounding errors. Explicit bounds and pre-computed limits further safeguard against excessive iterations.[30][31]
Common pitfalls arise from integer overflow, where prolonged loops push the counter beyond its type's maximum, triggering wrap-around that may yield undefined behavior, skipped iterations, or infinite execution in signed types. Mismatches between signed and unsigned counters exacerbate this, as implicit promotions can invert comparisons and fail to terminate loops correctly when interfacing with unsigned sizes like array lengths. For instance, in C, declaring for (size_t i = 0; i < n; ++i) mitigates overflow for large n by leveraging the unsigned nature of size_t, which wraps predictably without invoking undefined behavior on overflow.[32][30]
for (size_t i = 0; i < n; ++i) {
// Loop body
}
for (size_t i = 0; i < n; ++i) {
// Loop body
}
Scope, Lifetime, and Modification
In modern programming languages such as C++ and JavaScript, the scope of a for loop's control variable is typically limited to the block of the loop itself when declared within the loop's initialization clause, ensuring it is not accessible outside the loop to prevent unintended reuse or shadowing issues.[33] For instance, in C++ (since C++98), a variable declared in the for loop's init-statement has its scope confined to the entire for statement, including the condition, increment, and body, but it is destroyed upon loop completion. Similarly, in JavaScript, usinglet for the loop variable enforces block scoping, making it inaccessible after the loop, whereas the older var keyword results in function scoping, allowing post-loop access to the variable's final value.[33]
In contrast, older languages like BASIC treat for loop control variables with program-wide scope, where the variable persists throughout the entire program and retains its final value after the loop ends, reflecting the absence of block scoping in early implementations.[34] The lifetime of a for loop's control variable generally begins at its initialization (either explicitly before or within the loop header) and extends until the end of its scope or explicit reassignment/destruction, with post-loop accessibility depending on the scoping rules: inaccessible in block-scoped modern languages but available in broader-scoped older ones like BASIC.[34]
Modification of the loop control variable within the body is permitted in imperative languages, allowing manual adjustments such as incrementing or decrementing beyond the loop's update expression (e.g., i -= 1 inside a loop incrementing i++), but this can lead to unintended behavior like infinite loops if the change violates the loop condition prematurely.[33] In functional languages like Haskell, traditional mutable for loops do not exist; instead, iteration is achieved through recursion or higher-order functions with immutable bindings, avoiding mutable counters altogether to maintain referential transparency.
// JavaScript example: block scoping with let
for (let i = 0; i < 5; i++) {
console.log(i); // i is accessible here
}
// console.log(i); // ReferenceError: i is not defined (block-scoped)
// JavaScript example: block scoping with let
for (let i = 0; i < 5; i++) {
console.log(i); // i is accessible here
}
// console.log(i); // ReferenceError: i is not defined (block-scoped)
Control and Semantics
Infinite and Unbounded Loops
Infinite and unbounded for loops are configured by omitting the loop condition or explicitly setting it to a value that always evaluates to true, resulting in continuous execution without automatic termination. In the C programming language, the syntaxfor(;;) omits the condition expression, which is treated as a non-zero constant equivalent to true, creating an endless loop unless interrupted by other control statements.[35] This form is a standard idiom for indefinite iteration, as documented in the seminal reference on C.
Such loops are commonly employed in patterns requiring persistent execution, such as event-driven waits in server applications where the loop monitors for incoming connections or events, or in simulations like game loops that continuously update states until an external signal halts them.[36][37] For instance, a server might use for (initialization; ; update) to repeatedly check for network activity, processing requests in each iteration while incrementing a counter for logging purposes.[36]
However, infinite for loops pose significant risks, including resource exhaustion where repeated iterations consume CPU cycles, memory, or other system resources, potentially leading to program crashes, denial-of-service conditions, or system-wide performance degradation.[38] Termination typically requires manual intervention, such as a break statement triggered by a specific condition, signal handling, or external process termination, emphasizing the need for careful design to avoid unintended endless execution.[38]
While equivalent to a while(true) construct in functionality, for loops are often preferred for infinite scenarios when counter-based progress tracking is desired, as the initialization and update clauses allow seamless integration of iteration variables without separate declarations. This preference stems from the structured nature of for loops, which encapsulate all loop control elements in one statement, as exemplified by the common macro #define forever for(;;) for readability.
A typical guarded infinite for loop incorporates a conditional break to ensure safe termination, such as:
for(;;) {
if (some_condition) break;
process_data();
}
for(;;) {
if (some_condition) break;
process_data();
}
Early Exit and Continuation Mechanisms
In programming languages that support for loops, early exit and continuation mechanisms provide fine-grained control over loop execution, allowing developers to terminate or skip iterations based on conditions without relying solely on the loop's inherent structure. These mechanisms, primarily the break and continue statements, originated in early imperative languages and are now standard in many modern ones, enabling more efficient and readable code for tasks requiring conditional interruption. While they can be applied to potentially infinite loops to impose bounds, their primary role is in bounded iterations where premature adjustment is needed.[39][40] The break statement immediately terminates the execution of the innermost enclosing loop, transferring control to the statement following the loop body. In a for loop, this exits after the current iteration's body, bypassing any remaining iterations, the update expression, and the condition check. For instance, in C, as described by Kernighan and Ritchie, break is used to exit when a negative value is encountered in an array traversal.[39] Similarly, in Java, an unlabeled break ends the innermost for loop, such as when searching an array for a specific value like 12 at index 4.[40] In Python, break exits the innermost for loop, for example, when a factor is found during a primality check.[23] The continue statement skips the remainder of the current iteration in the innermost enclosing loop, advancing directly to the update expression (in a for loop) or the condition check, and then proceeding to the next iteration if applicable. This avoids executing subsequent code in the body for that iteration. In C, continue is employed to ignore negative elements when summing an array, jumping past the addition for those cases.[39] Java's unlabeled continue, for example, skips non-matching characters when counting occurrences of 'p' in a string, ensuring only relevant iterations contribute to the count.[40] Python uses continue to bypass odd numbers in a loop printing even ones, streamlining output without nested conditionals.[23] In nested for loops, both break and continue typically affect only the innermost loop unless the language supports labeled statements. In C and Python, an unlabeled break or continue impacts solely the immediate enclosing loop, requiring alternative structures like functions or flags for outer control.[39][23] Java, however, allows labeled break and continue to target outer loops explicitly; for instance, a labeled break "search" in nested for loops exits the outer loop upon finding a target at position (1, 0), while a labeled continue "test" skips to the next outer iteration if inner matches fail.[40] These mechanisms are particularly valuable for optimization in search operations and error handling in batch processing. Break enables early termination in linear searches, halting iteration once a target is found to avoid unnecessary computations—for example:for (int i = 0; i < n; i++) {
if (arr[i] == target) {
break; // Exit upon finding the first match
}
}
for (int i = 0; i < n; i++) {
if (arr[i] == target) {
break; // Exit upon finding the first match
}
}
Bounds Adjustment and Range Handling
In programming languages, bounds adjustment refers to the dynamic modification of the loop's upper or lower limits during execution, typically by altering the condition variable or bound expressions within the loop body. For instance, in C++, a for loop likefor (int i = 0; i < n; ++i) allows modification of n inside the body, such as decrementing n to reduce iterations, but this can lead to unpredictable behavior if the change affects the condition evaluation inconsistently across iterations.[15] Similarly, in Java, the for loop's condition can be influenced by updating bound variables mid-execution, enabling adaptive iteration spaces like shrinking arrays during processing.[17] However, such adjustments are generally discouraged due to their potential to complicate code readability and introduce errors.
Modifying loop bounds carries significant risks, including infinite loops or skipped iterations, as the compiler or runtime may not anticipate changes to the termination condition. In C++, altering the loop counter or bound variable can violate the forward progress guarantee, potentially resulting in undefined behavior for non-terminating loops without observable side effects since C++26.[15] For example, if a decrement to the upper bound occurs unevenly, the loop might never satisfy the condition, causing endless execution; conversely, excessive reductions could bypass intended iterations. Languages like Pascal mitigate this by prohibiting direct assignment to the control variable in a for-to-do loop, ensuring the counter remains unaltered and the loop executes exactly as bounded, with any attempted modification raising a compile-time error.[42]
Range specification in for loops defines the iteration space through inclusive or exclusive bounds, determining whether endpoints are included in the sequence. In Python's iterator-based for loop using the range() function, the start is inclusive (defaulting to 0), while the stop is exclusive, producing sequences like range(1, 6) yielding 1 through 5; this half-open interval convention avoids off-by-one errors in array indexing.[43] Contrastingly, Visual Basic .NET's For...Next statement uses inclusive bounds, executing while the counter is less than or equal to (or greater than or equal to, for negative steps) the end value, such as For i As Integer = 1 To 10 including both 1 and 10.[44] Mishandling these conventions, such as assuming inclusivity in an exclusive system, risks infinite loops if the step fails to reach or surpass the bound appropriately.
Step sizes extend range handling by allowing increments beyond 1, facilitating efficient traversal of sparse or patterned data. Python's range(start, stop, step) supports arbitrary integer steps, including negative values for descending sequences, as in range(0, 10, 2) producing 0, 2, 4, 6, 8; a step of zero raises a ValueError to prevent infinite loops.[43] In Visual Basic .NET, the optional Step clause defaults to 1 but permits fractions or negatives, like For i As Double = 10 To 0 Step -0.5, decrementing inclusively to include 0.[44] C++ achieves variable steps via the update expression, such as for (int i = 0; i < 100; i += 5), skipping every four values for performance in large ranges.[15]
Advanced range handling includes reverse iteration through decrementing counters, often via dedicated syntax to ensure safe traversal. Pascal's for-downto-do construct reverses inclusively with a step of -1, as in for i := 10 downto 1 do, executing from 10 to 1 without modifiable bounds to avoid skips.[42] Python emulates this with negative steps in range(), like range(10, 0, -1) yielding 10 down to 1 (exclusive of 0), while Java and C++ use for (int i = n-1; i >= 0; --i) for equivalent descending exclusive bounds.[43] Non-linear ranges, such as logarithmic or custom progressions, are typically implemented by adjusting steps dynamically in languages permitting bound modifications, though this heightens risks of incomplete coverage if the sequence does not align with the termination condition.[17]
Comparisons with Other Constructs
Equivalence to While Loops
In many programming languages, such as C and C++, the traditional for loop with initialization, condition, and update clauses is semantically equivalent to a while loop constructed by performing the initialization once before the loop, evaluating the condition at the start of each iteration, executing the loop body, and then performing the update.[15] Specifically, a for loop of the formfor (init; cond; update) { body } expands to init; while (cond) { body; update; }, where the while loop checks the condition before entering the body, ensuring identical execution flow for finite iterations when the condition eventually falsifies.
This equivalence can be demonstrated through structural expansion and operational semantics, showing that all behaviors of a for loop—whether finite termination upon condition failure or infinite looping if the condition remains true and the update does not alter it—are directly mappable to a while loop. For instance, an infinite for loop like for (;; ) { body } (with omitted condition and update) is equivalent to while (1) { body }, as the empty condition defaults to true in C semantics, and both constructs repeat indefinitely unless interrupted by other control statements. The mapping preserves termination properties: if the for loop halts after k iterations due to the condition becoming false after the k-th update, the while loop does the same by placing the update after the body but before the next condition check.[45]
For loops are typically preferred when the number of iterations is known in advance, such as traversing a fixed-size array or performing a predetermined count of operations, due to their concise syntax that groups initialization, condition, and update in one place.[46] In contrast, while loops are favored for dynamic conditions where the iteration count is uncertain, like processing input until end-of-file or waiting for a user event, as they emphasize the condition without implying a counter-based structure.[46]
A key limitation of rewriting for loops as while loops is that the while construct lacks a dedicated update clause, necessitating manual placement of the update statement within the body, which can lead to errors if forgotten or misplaced (e.g., inside conditional branches). For example, the C for loop int i = 0; for (i = 0; i < 5; i++) { x += i; } transforms to int i = 0; while (i < 5) { x += i; i++; }, where the increment i++ must be explicitly added after the body to avoid an infinite loop.[46]
Relation to Do-While and Recursive Alternatives
The for loop evaluates its condition prior to the first iteration, allowing for the possibility of zero executions if the condition is false from the outset. In contrast, the do-while loop performs the condition check after executing the body at least once, ensuring a minimum of one iteration regardless of the initial condition value. This fundamental difference in timing—pre-iteration for for loops versus post-iteration for do-while—arises from their syntactic and semantic designs in languages like C and C++, where the for loop's structure integrates initialization, condition, and update into a single construct equivalent to a while loop with prefixed initialization.[15][47] Converting between these constructs requires careful adjustment of the condition placement to preserve behavior. For instance, a do-while loop without prior initialization, such asdo { body; update; } while (cond);, can be emulated in a for loop by using an empty initialization, condition, and update, placing the update inside the body before the post-body check: for (;; ) { body; update; if (!cond) break; }. This approach inverts the test timing while maintaining the guaranteed first execution, though it introduces an explicit break for early exit, which may alter readability in imperative languages.[15][47]
In functional programming paradigms, recursive functions, particularly those employing tail recursion, provide an alternative to traditional for loops by simulating iteration without mutable state. Tail recursion occurs when the recursive call is the final operation in the function, enabling compilers or interpreters to optimize it into an iterative loop via tail call optimization (TCO), which reuses the current stack frame instead of allocating new ones. This equivalence allows tail-recursive functions to achieve the constant space complexity of loops while adhering to functional purity. A seminal formalization of proper tail recursion in Scheme, which influences many functional languages, defines it as recursion where no operations follow the recursive call, ensuring space efficiency comparable to iteration.[48]
For example, in Haskell, a tail-recursive sum function mimics a for loop over a list:
sum' :: Num a => [a] -> a
sum' xs = sumHelper xs 0
where
sumHelper [] acc = acc
sumHelper (x:xs) acc = sumHelper xs (acc + x)
sum' :: Num a => [a] -> a
sum' xs = sumHelper xs 0
where
sumHelper [] acc = acc
sumHelper (x:xs) acc = sumHelper xs (acc + x)
sumHelper is in tail position, allowing the Haskell compiler to optimize it to a loop-like iteration with O(1) space. Such patterns are common in the Haskell Prelude for operations like list folding, where recursion replaces explicit looping constructs absent in the language.[49]
Recursion, including tail variants, is particularly suited for problems with inherent hierarchical structure, such as tree traversals, where a for loop would require awkward auxiliary stacks or indices. However, without TCO, general recursion risks stack overflow from excessive depth, consuming O(n) space for n calls, whereas iterative for loops maintain constant stack usage by avoiding function calls altogether. Languages like Haskell mandate TCO for tail recursion, mitigating this trade-off and making recursion viable for large-scale iteration, though it may introduce slight overhead in non-optimized environments compared to native loops.[48]
Historical Evolution
Origins in Early Languages (1950s-1960s)
The for loop construct emerged in the late 1950s as programming languages sought to simplify repetitive operations common in scientific and business computing, moving away from the unstructured jumps prevalent in assembly languages. In 1957, FORTRAN introduced the DO loop, the earliest iteration mechanism resembling a modern for loop, designed to automate index calculations for numerical computations that previously required manual manipulation of registers in machine code. The syntax wasDO n i = m1, m2 (optionally with step m3), where n labeled the terminal statement, i was the control variable, m1 the start, m2 the end, and m3 the increment (defaulting to 1); execution proceeded from the DO to statement n, after which control passed to the next statement.[50] This innovation enabled fixed iteration counts, directly supporting mathematical processes like summations and array traversals, and was optimized by the compiler to generate efficient code comparable to hand-optimized assembly.[50]
Building on FORTRAN's foundation, ALGOL 58 formalized a more expressive for statement in 1958, emphasizing clarity and generality for algorithmic description. The syntax allowed for V := E1 (E2) E3 do S, where V was the variable, E1 the initial value, E2 the step (optional, default 1), E3 the limit, and S the body; an alternative list form assigned successive values from a comma-separated sequence.[4] For example, for I := 1 (1) 10 do P(I) iterated I from 1 to 10, executing procedure P each time, equivalent to a conditional loop but more concise.[4] This design drew inspiration from mathematical notation for sequences, promoting readable expressions for bounded repetition in scientific algorithms while replacing ad-hoc goto chains.[4]
By 1960, COBOL adapted the concept for data processing with the PERFORM VARYING statement, tailored to business applications involving table scans and report generation. The syntax was PERFORM paragraph VARYING counter FROM initial BY increment UNTIL condition, executing the named paragraph repeatedly while incrementing the counter until the condition held true. This allowed flexible bounds based on data conditions rather than fixed counts, addressing repetitive file handling that assembly required explicit indexing for, and integrated seamlessly with COBOL's English-like prose for non-scientific users.
In 1964, two influential languages further refined the for loop for accessibility and versatility. BASIC's FOR...NEXT construct, FOR I = 1 TO 10 ... NEXT I, provided a simple, line-numbered iteration for educational and interactive use, with implicit step 1 and optional STEP clause, enabling beginners to handle loops without complex syntax. Similarly, PL/I's DO statement, DO i = 1 TO 10; ... END;, combined FORTRAN-like indexing with block structure, supporting variable steps and conditions within a compound statement for robust scientific and systems programming. These developments underscored the for loop's role in abstracting away low-level repetition control, fostering structured code influenced by summation sigma notation in mathematics.[50]
Development in Structured Programming (1970s-1980s)
In the 1970s, structured programming principles, which emphasized clear control flow through constructs like bounded iteration, significantly influenced the evolution of the for loop, building on earlier procedural foundations to promote readability and maintainability in code.[51] Niklaus Wirth's Pascal, introduced in 1970, exemplified this shift with its for loop syntax designed for teaching and safe iteration. The construct used the formfor variable := initial_value to final_value do statement, where the control variable was implicitly immutable during execution, preventing unintended modifications and ensuring predictable bounds.[52] This feature aligned with structured programming's avoidance of unstructured jumps, making Pascal a cornerstone for educational and systems programming.[53]
By 1972, Dennis Ritchie's C language introduced a more flexible for loop that became a model for portability across systems. The syntax for (expression1; expression2; expression3) statement allowed optional initialization, condition, and increment steps, enabling concise expression of initialization, testing, and updating in a single line while supporting infinite loops if the condition was omitted.[54] This design, rooted in C's development for Unix at Bell Labs, prioritized efficiency and expressiveness for low-level programming, rapidly gaining adoption in operating systems and embedded applications due to its balance of control and simplicity.[39]
That same year, Alan Kay's Smalltalk pioneered object-oriented iteration with a block-based for loop, reflecting the language's emphasis on message-passing and encapsulation. The syntax 1 to: 10 do: [:i | statements] sent a do: message to a numeric range, passing each value to a closure (block) for execution, which integrated seamlessly with Smalltalk's dynamic, everything-is-an-object paradigm.[55] This approach facilitated higher-level abstractions, influencing later languages by treating loops as methods on collections rather than rigid control structures.[56]
The 1980 release of Ada, developed under U.S. Department of Defense sponsorship, advanced range-based iteration for safety-critical systems. Its for loop syntax for identifier in [reverse] discrete_range loop sequence_of_statements end loop iterated over a predefined discrete range (e.g., 1 .. 10), with the loop parameter acting as a constant to enforce bounds checking and prevent overflow errors.[57] This design supported structured programming's goals of reliability, particularly in concurrent and real-time environments, by integrating type safety and explicit scoping.[58]
Mid-1980s innovations extended for loops to specialized domains, with MATLAB's 1984 introduction providing a colon-based syntax for numerical computing: for k = 1:10 statements end. This allowed stepping through vectors or ranges efficiently, tailored for matrix operations in scientific applications.[59] Similarly, Larry Wall's Perl, released in 1987, added a foreach variant foreach variable (@array) { statements } for iterating over lists and arrays, enhancing text processing and scripting by simplifying data traversal without index management.
These developments marked a trend toward the C-style for loop's ubiquity for its versatility in imperative languages, promoting code portability across platforms, while the emergence of foreach constructs addressed iterable collections, reducing error-prone indexing.[51] Overall, for loops in this era enabled safer, more readable code in systems programming and emerging scripting contexts, underpinning the structured paradigm's dominance by minimizing bugs from unbounded control flow.[60]
Modern Implementations (1990s-2020s)
In the 1990s, Java introduced a standardized for loop syntax that became influential across object-oriented languages, featuring an initialization, condition, and update clause within parentheses. The basic form,for (int i = 0; i < n; i++) { ... }, allows precise control over iteration counters, while the enhanced for loop, added in Java 5 (2004) as for (Type t : collection) { ... }, simplifies iteration over collections by eliminating explicit indexing. This design emphasized readability and reduced common errors like off-by-one bounds, influencing subsequent languages.[17][61]
Python, first released in 1991, adopted an iterator-based for loop with the syntax for i in range(n): ..., which iterates over sequences like lists or the range generator without manual counter management. This approach promoted Pythonic expressiveness, treating loops as traversals of iterables rather than rigid counters. Complementing explicit loops, list comprehensions like [x for x in range(n)] emerged as concise, implicit alternatives for building collections, blending imperative and functional styles.[23]
JavaScript's for loop, from its 1995 origins, mirrored C-style syntax with for (let i = 0; i < n; i++) { ... }, using let for block-scoped variables introduced in ES6 (2015). The ES6 update added for...of, as in for (const value of iterable) { ... }, enabling iteration over arrays, strings, and other iterables without indices, enhancing safety by avoiding mutation during traversal.[33][62]
The 2000s saw Go (2009) unify looping under a single for keyword, with traditional form for i := 0; i < n; i++ { ... } and range-based for k, v := range slice { ... } for maps and slices, prioritizing simplicity and garbage collection for concurrency. Rust (2010) emphasized memory safety through for i in 0..n { ... }, where .. denotes exclusive ranges, and iterator chains like for item in vec.iter() { ... }, enforcing immutability by default to prevent data races. Kotlin (2011), building on JVM interoperability, used range syntax for (i in 1..10) { ... }, extended with downTo for descending iteration and step for increments, as in for (i in 10 downTo 1 step 2) { ... }, to boost expressiveness while maintaining type safety.[63][64][65]
Into the 2010s and 2020s, Swift (2014) refined range iteration with for i in 0..<n { ... }, using ..< for exclusive upper bounds, and introduced stride for custom steps: for i in stride(from: 0, to: n, by: 2) { ... }, integrating seamlessly with optionals and collections for safer iOS development. Julia (2012), focused on numerical computing, employed for i = 1:10 ... end, where : creates step ranges, alongside enhanced comprehensions like [i^2 for i=1:10] for vectorized operations. Nim (2008), a systems language, uses for i in 0..<n: ... with half-open intervals, supporting iterators for efficiency in metaprogramming contexts. These implementations addressed gaps in earlier designs by incorporating post-2012 languages like Swift and Kotlin.[66][67][68]
Modern for loops reflect broader trends toward safety via immutability (e.g., Rust's borrow checker preventing aliasing) and concurrency support, such as Go's goroutines enabling parallel fors without locks. Expressiveness has grown through functional alternatives like map and reduce, reducing reliance on mutable loops, while iterator protocols ensure bounds-checked iteration across ecosystems.[64][63]