Difference between revisions of "For"
m |
(review; add more information) |
||
Line 1: | Line 1: | ||
{{for}} | {{for}} | ||
− | |||
− | |||
− | + | <syntaxhighlight lang="pascal" enclose="none">for</syntaxhighlight> is a [[Keyword|keyword]] used in conjunction with other keywords to create loops. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | <syntaxhighlight> | + | == loop with iterator variable == |
− | for | + | <syntaxhighlight lang="pascal" enclose="none">for</syntaxhighlight> used along with [[To|<syntaxhighlight lang="pascal" enclose="none">to</syntaxhighlight>]]/[[Downto|<syntaxhighlight lang="pascal" enclose="none">downto</syntaxhighlight>]] and [[Do|<syntaxhighlight lang="pascal" enclose="none">do</syntaxhighlight>]] constructs a loop in which the value of a control variable is incremented or decremented by <syntaxhighlight lang="pascal" enclose="none">1</syntaxhighlight> passing every iteration. |
+ | |||
+ | === behavior === | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | for controlVariable := start to finalValue do | ||
+ | begin | ||
+ | statement; | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | In this example <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> is first initialized with the value of <syntaxhighlight lang="pascal" enclose="none">start</syntaxhighlight> (but cmp. [[#legacy|§ “legacy”]] below). | ||
+ | If and as long as <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> is not greater than <syntaxhighlight lang="pascal" enclose="none">finalValue</syntaxhighlight>, the [[Begin|<syntaxhighlight lang="pascal" enclose="none">begin</syntaxhighlight>]] … [[End|<syntaxhighlight lang="pascal" enclose="none">end</syntaxhighlight>]] block with all its statements is executed. | ||
+ | By reaching <syntaxhighlight lang="pascal" enclose="none">end</syntaxhighlight> <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> is [[Inc|incremented]] by <syntaxhighlight lang="pascal" enclose="none">1</syntaxhighlight> and the comparison is made, whether another iteration, whether the statement-[[Block|block]] is executed again. | ||
+ | |||
+ | === reverse direction === | ||
+ | By exchanging <syntaxhighlight lang="pascal" enclose="none">to</syntaxhighlight> with <syntaxhighlight lang="pascal" enclose="none">downto</syntaxhighlight>, the variable – in the example <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> – is [[Dec|decremented]] by <syntaxhighlight lang="pascal" enclose="none">1</syntaxhighlight> and the condition becomes “as long as the control variable is not less than the final value.” | ||
+ | |||
+ | === constraints === | ||
+ | ==== immutable requirement ==== | ||
+ | While inside in a loop, it is imperative not to mess with the loop variable. | ||
+ | Plain assignments – e.g. <syntaxhighlight lang="pascal" enclose="none">controlVariable := 2</syntaxhighlight> – are caught by the compiler reporting “Illegal assignment to for-loop variable "controlVariable"”. | ||
+ | However, ''indirect'' manipulations are not prevented: | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | program iteratorManipulation(input, output, stderr); | ||
+ | |||
+ | var | ||
+ | i: longint; | ||
+ | |||
+ | procedure foo; | ||
+ | begin | ||
+ | i := 1; | ||
+ | end; | ||
+ | |||
+ | begin | ||
+ | for i := 0 to 2 do | ||
+ | begin | ||
+ | writeLn(i); | ||
+ | foo; | ||
+ | end; | ||
+ | end. | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | The global variable <syntaxhighlight lang="pascal" enclose="none">i</syntaxhighlight> is modified by calling <syntaxhighlight lang="pascal" enclose="none">foo</syntaxhighlight>. | |
+ | The program runs an [[Infinite loop|infinite loop]]. | ||
− | <syntaxhighlight> | + | ==== type restrictions ==== |
− | for | + | The [[Data type|type]] of <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> has to be enumerable. |
+ | Assuming your system operates on [[ASCII]] you can do | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | var | ||
+ | c: char; | ||
+ | begin | ||
+ | for c := 'a' to 'z' do | ||
+ | begin | ||
+ | writeLn(c); | ||
+ | end; | ||
+ | end. | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | or generally use any type that is enumerable. | |
+ | |||
+ | ==== other step widths ==== | ||
+ | Other step widths than <syntaxhighlight lang="pascal" enclose="none">1</syntaxhighlight> or <syntaxhighlight lang="pascal" enclose="none">-1</syntaxhighlight> are not possible by utilizing this syntax. | ||
+ | You have to use other loop constructs such as [[While|<syntaxhighlight lang="pascal" enclose="none">while</syntaxhighlight>]] … <syntaxhighlight lang="pascal" enclose="none">do</syntaxhighlight> and manually initialize, compare and change the <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight>. | ||
− | + | The matter, whether [[FPC|FreePascal]] could provide a syntax specifying other step widths, came up several times. | |
− | + | In general it was regarded as “syntactic sugar”, though, and in order to stay compatible Pascal's core, or Delphi's extensions, in order to avoid any impetuous decisions, the developers remained rather conservative and rejected any changes in that direction. | |
− | |||
− | + | === limits === | |
+ | Note, as it is common mathematics when writing sums <math>\sum_{n=0}^{k}</math> or products <math>\prod_{n=1}^{k}</math> the limits are ''inclusive''. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | for i := 5 to 5 do | ||
+ | begin | ||
+ | writeLn(z); | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | This excerpt will print one line with <code>5</code>, though you might be fooled by such thoughts as “5 to 5 – that's zero. The body must never be executed.” | ||
− | + | === legacy === | |
+ | Assuming no other manipulations were made, after the loop the value of <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> will be <syntaxhighlight lang="pascal" enclose="none">final</syntaxhighlight>, unless the the proper condition was not met from the start, then it is ''undefined'' (remains unchanged). | ||
+ | In case of empty loops (where the body is never executed), even the <syntaxhighlight lang="pascal" enclose="none">start</syntaxhighlight> value is not loaded. | ||
+ | Rationale: | ||
+ | The <syntaxhighlight lang="pascal" enclose="none">controlVariable</syntaxhighlight> exists for usage ''inside'' the loop's body. | ||
+ | If the loop's body is not entered, then value might remain unused. | ||
+ | We generally avoid unused values, i.e. any unnecessary assignment without successive reads. | ||
− | == | + | === short syntax === |
− | + | For ''single'' statements writing a surrounding <syntaxhighlight lang="pascal" enclose="none">begin</syntaxhighlight> … <syntaxhighlight lang="pascal" enclose="none">end</syntaxhighlight> block can be skipped resulting in: | |
+ | <syntaxhighlight lang="pascal"> | ||
+ | for controlVariable := start to final do | ||
+ | statement; | ||
+ | </syntaxhighlight> | ||
+ | It is advised though, to make use of that only in justified cases, where the readability is improved and it is very unlikely the loop is expanded by any additional statement. | ||
+ | Too many programmers inadvertently fell for the pitfall before and added a properly indented line forgetting it requires a surrounding <syntaxhighlight lang="pascal" enclose="none">begin</syntaxhighlight> … <syntaxhighlight lang="pascal" enclose="none">end</syntaxhighlight> then, too. | ||
+ | Make it a habit and always accompany <syntaxhighlight lang="pascal" enclose="none">for</syntaxhighlight>-loops with <syntaxhighlight lang="pascal" enclose="none">begin</syntaxhighlight> … <syntaxhighlight lang="pascal" enclose="none">end</syntaxhighlight>, leaving the option to possibly eliminate those at a ''later'' stage (but ''not'' during development). | ||
+ | |||
+ | == loop with elements == | ||
+ | With [[for-in loop|<syntaxhighlight lang="pascal" enclose="none">for</syntaxhighlight> … <syntaxhighlight lang="pascal" enclose="none">in</syntaxhighlight> loops]] the variable that is changed every iteration represents an element out of a collection. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | type | ||
+ | furniture = (chair, desk, bed, wardrobe); | ||
+ | arrangement = set of furniture; | ||
+ | var | ||
+ | thing: furniture; | ||
+ | begin | ||
+ | writeLn('all available pieces of furniture:'); | ||
+ | for thing in arrangement do | ||
+ | begin | ||
+ | writeLn(thing); | ||
+ | end; | ||
+ | end. | ||
+ | </syntaxhighlight> | ||
+ | In contrast to other loops, an index variable is not provided. | ||
+ | In the above example <syntaxhighlight lang="pascal" enclose="none">ord(thing)</syntaxhighlight> will return an index, but it has to be ''additionally'' retrieved while it inherently exists though inaccessible. | ||
+ | [[for-in loop#Proposed extensions|Proposals]] were made, whether and how to extend the syntax allowing to specify an index variable that is adjusted with every iteration. | ||
+ | |||
+ | == see also == | ||
+ | * [[Example: Why the loop variable should be of signed type]] | ||
+ | * [[sRangechecks|<syntaxhighlight lang="pascal" enclose="none">{$rangechecks}</syntaxhighlight>]] | ||
{{Keywords}} | {{Keywords}} | ||
− | |||
[[Category:Pascal]] | [[Category:Pascal]] | ||
[[Category:Control Structures]] | [[Category:Control Structures]] |
Revision as of 01:31, 27 March 2018
│
Deutsch (de) │
English (en) │
français (fr) │
русский (ru) │
for
is a keyword used in conjunction with other keywords to create loops.
loop with iterator variable
for
used along with to
/downto
and do
constructs a loop in which the value of a control variable is incremented or decremented by 1
passing every iteration.
behavior
for controlVariable := start to finalValue do
begin
statement;
end;
In this example controlVariable
is first initialized with the value of start
(but cmp. § “legacy” below).
If and as long as controlVariable
is not greater than finalValue
, the begin
… end
block with all its statements is executed.
By reaching end
controlVariable
is incremented by 1
and the comparison is made, whether another iteration, whether the statement-block is executed again.
reverse direction
By exchanging to
with downto
, the variable – in the example controlVariable
– is decremented by 1
and the condition becomes “as long as the control variable is not less than the final value.”
constraints
immutable requirement
While inside in a loop, it is imperative not to mess with the loop variable.
Plain assignments – e.g. controlVariable := 2
– are caught by the compiler reporting “Illegal assignment to for-loop variable "controlVariable"”.
However, indirect manipulations are not prevented:
program iteratorManipulation(input, output, stderr);
var
i: longint;
procedure foo;
begin
i := 1;
end;
begin
for i := 0 to 2 do
begin
writeLn(i);
foo;
end;
end.
The global variable i
is modified by calling foo
.
The program runs an infinite loop.
type restrictions
The type of controlVariable
has to be enumerable.
Assuming your system operates on ASCII you can do
var
c: char;
begin
for c := 'a' to 'z' do
begin
writeLn(c);
end;
end.
or generally use any type that is enumerable.
other step widths
Other step widths than 1
or -1
are not possible by utilizing this syntax.
You have to use other loop constructs such as while
… do
and manually initialize, compare and change the controlVariable
.
The matter, whether FreePascal could provide a syntax specifying other step widths, came up several times. In general it was regarded as “syntactic sugar”, though, and in order to stay compatible Pascal's core, or Delphi's extensions, in order to avoid any impetuous decisions, the developers remained rather conservative and rejected any changes in that direction.
limits
Note, as it is common mathematics when writing sums [math]\displaystyle{ \sum_{n=0}^{k} }[/math] or products [math]\displaystyle{ \prod_{n=1}^{k} }[/math] the limits are inclusive.
for i := 5 to 5 do
begin
writeLn(z);
end;
This excerpt will print one line with 5
, though you might be fooled by such thoughts as “5 to 5 – that's zero. The body must never be executed.”
legacy
Assuming no other manipulations were made, after the loop the value of controlVariable
will be final
, unless the the proper condition was not met from the start, then it is undefined (remains unchanged).
In case of empty loops (where the body is never executed), even the start
value is not loaded.
Rationale:
The controlVariable
exists for usage inside the loop's body.
If the loop's body is not entered, then value might remain unused.
We generally avoid unused values, i.e. any unnecessary assignment without successive reads.
short syntax
For single statements writing a surrounding begin
… end
block can be skipped resulting in:
for controlVariable := start to final do
statement;
It is advised though, to make use of that only in justified cases, where the readability is improved and it is very unlikely the loop is expanded by any additional statement.
Too many programmers inadvertently fell for the pitfall before and added a properly indented line forgetting it requires a surrounding begin
… end
then, too.
Make it a habit and always accompany for
-loops with begin
… end
, leaving the option to possibly eliminate those at a later stage (but not during development).
loop with elements
With for
… in
loops the variable that is changed every iteration represents an element out of a collection.
type
furniture = (chair, desk, bed, wardrobe);
arrangement = set of furniture;
var
thing: furniture;
begin
writeLn('all available pieces of furniture:');
for thing in arrangement do
begin
writeLn(thing);
end;
end.
In contrast to other loops, an index variable is not provided.
In the above example ord(thing)
will return an index, but it has to be additionally retrieved while it inherently exists though inaccessible.
Proposals were made, whether and how to extend the syntax allowing to specify an index variable that is adjusted with every iteration.
see also
Keywords: begin — do — else — end — for — if — repeat — then — until — while