Control flow: Difference between revisions

Content deleted Content added
Undid revision 1297416746 by 154.191.216.59 (talk)
 
(27 intermediate revisions by 9 users not shown)
Line 10:
[[Interrupt]]s and [[Signal (computing)|signals]] are low-level mechanisms that can alter the flow of control in a way similar to a [[subroutine]], but usually occur as a response to some external stimulus or event (that can occur [[Asynchronous systems|asynchronously]]), rather than execution of an ''in-line'' control flow statement.
 
At the level of [[machine language]] or [[assembly language]], control flow instructions usually work by altering the [[program counter]]. For some [[central processing unit]]s (CPUs), the only control flow instructions available are conditional or unconditional [[Branch (computer science)|branch]] instructions, also termed jumps. However there is also [[Predication_(computer_architecture)|predication]] which conditionally enables or disables instructions ''without'' branching: as an alternative technique it can have both [[Predication_(computer_architecture)#Advantages|advantages]] and disadvantages over branching.
 
== Categories ==
Line 234:
 
== Loops ==
[[File:Programmingloops.svg|thumb|basic types of program loops]]
A loop is a sequence of statements which is specified once but which may be carried out several times in succession. The code "inside" the loop (the ''body'' of the loop, shown below as ''xxx'') is obeyed a specified number of times, or once for each of a collection of items, or until some condition is met, or [[Infinite loop|indefinitely]]. When one of those items is itself also a loop, it is called a "nested loop".<ref>{{Cite web |date=2019-11-25 |title=Nested Loops in C with Examples |url=https://www.geeksforgeeks.org/nested-loops-in-c-with-examples/ |access-date=2024-03-14 |website=GeeksforGeeks |language=en-US}}</ref><ref>{{Cite web |title=Python Nested Loops |url=https://www.w3schools.com/python/gloss_python_for_nested.asp |access-date=2024-03-14 |website=www.w3schools.com |language=en-US}}</ref><ref>{{Cite web |last=Dean |first=Jenna |date=2019-11-22 |title=Nested Loops |url=https://medium.com/swlh/nested-loops-ee1dbb9fc8ab |access-date=2024-03-14 |website=The Startup |language=en}}</ref>
A loop is a sequence of statements which is specified once but which may be carried out several times in succession. The code "inside" the loop (the ''body'' of the loop, shown below as ''xxx'') is obeyed a specified number of times, or once for each of a collection of items (both cases of ''definite iteration''), or until some condition is met (''indefinite iteration''), or [[Infinite loop|infinitely]]. When one of those items is itself also a loop, it is called a "nested loop".<ref>{{Cite web |date=2019-11-25 |title=Nested Loops in C with Examples |url=https://www.geeksforgeeks.org/nested-loops-in-c-with-examples/ |access-date=2024-03-14 |website=GeeksforGeeks |language=en-US}}</ref><ref>{{Cite web |title=Python Nested Loops |url=https://www.w3schools.com/python/gloss_python_for_nested.asp |access-date=2024-03-14 |website=www.w3schools.com |language=en-US}}</ref><ref>{{Cite web |last=Dean |first=Jenna |date=2019-11-22 |title=Nested Loops |url=https://medium.com/swlh/nested-loops-ee1dbb9fc8ab |access-date=2024-03-14 |website=The Startup |language=en}}</ref>
 
Some common situations are not well-handled by these basic control structures, and are generally addressed by early exit from the loop, in the form of a ''break'' from the loop, a ''return'' from the function, or an exception being raised.<ref>{{cite journal
|last=Knuth |first=Donald E.
|author-link=Donald Knuth
|year=1974
|title=Structured Programming with <code>go to</code> Statements
|journal=[[ACM Computing Surveys|Computing Surveys]]
|volume=6
|issue=4
|pages=261–301
|doi=10.1145/356635.356640
|citeseerx=10.1.1.103.6084
|s2cid=207630080
}}</ref><ref name="roberts"/>
 
In [[functional programming]] languages, such as [[Haskell]] and [[Scheme (programming language)|Scheme]], both [[Recursion (computer science)|recursive]] and [[Fixed point combinator|iterative]] processes are expressed with [[Tail recursion|tail recursive]] procedures instead of looping constructs that are syntactic.
Line 243 ⟶ 258:
In most cases counting can go downwards instead of upwards and step sizes other than 1 can be used.
 
{|
{| class="wikitable"
| {{sxhl|2=basic|1=<nowiki/>
|
FOR I = 1 TO N
xxx
NEXT I}}
|
'''for''' I := 1 '''to''' N '''do''' '''begin'''
Line 253 ⟶ 268:
'''end''';
|-
| {{sxhl|2=fortran|1=<nowiki/>
|
DO I = 1,N
xxx
END DO}}
|
'''for''' ( I=1; I<=N; ++I ) {
Line 265 ⟶ 280:
In these examples, if N < 1 then the body of loop may execute once (with I having value 1) or not at all, depending on the programming language.
 
In many programming languages, only integers can be reliably used in a count-controlled loop. Floating-point numbers are represented imprecisely due to hardware constraints, so a loop such as<br />
 
'''for''' X := 0.1 '''step''' 0.1 '''to''' 1.0 '''do'''
 
Line 311 ⟶ 327:
Several programming languages (e.g., [[Ada (programming language)|Ada]], [[APL (programming language)|APL]], [[D (programming language)|D]], [[C++11]], [[Smalltalk]], [[PHP]], [[Perl]], [[Object Pascal]], [[Java (programming language)|Java]], [[C Sharp (programming language)|C#]], [[MATLAB]], [[Visual Basic]], [[Ruby (programming language)|Ruby]], [[Python (programming language)|Python]], [[JavaScript]], [[Fortran 95]] and later) have special constructs which allow implicit looping through all elements of an array, or all members of a set or collection.
 
someCollection '''do''': {{codett|2=smalltalk|[:eachElement |{{!}}xxx]. "Smalltalk"}}
'''for''' Item '''in''' Collection '''do''' '''begin''' xxx '''end''';
Line 319 ⟶ 335:
'''foreach''' someArray { xxx }
'''foreach''' {{codett|2=php|1=($someArray as $k => $v) { xxx } # PHP}}
Collection<String> coll; '''for''' (String s : coll) {}
Line 325 ⟶ 341:
'''foreach''' ('''string''' s '''in''' myStringCollection) { xxx }
{{codett|2=ps1|someCollection |{{!}} ForEach-Objectforeach { $_ } # Powershell: 'foreach' and '%' are the alias of 'ForEach-Object'}}
'''forall''' ( index = first:last:step... )
 
[[Scala (programming language)|Scala]] has [[Scala (programming language)#For-expressions|for-expressions]], which generalise collection-controlled loops, and also support other uses, such as [[asynchronous programming]]. [[Haskell]] has do-expressions and comprehensions, which together provide similar function to for-expressions in Scala.
 
Line 349 ⟶ 366:
=== Restart loop ===
Ruby has a <code>retry</code> statement that restarts the entire loop from the initial iteration.<ref>{{cite web|title=control_expressions - Documentation for Ruby 2.3.0|url=https://docs.ruby-lang.org/en/2.3.0/syntax/control_expressions_rdoc.html|access-date=2020-09-25|website=docs.ruby-lang.org}}</ref>
 
=== Loop-and-a-half ===
Common loop structures sometimes result in duplicated code, either repeated statements or repeated conditions. This arises for various reasons and has various proposed solutions to eliminate or minimize code duplication.<ref name="c2messy">{{cite web |url=https://wiki.c2.com/?MessyLoopConditions |title=Messy Loop Conditions |work=WikiWikiWeb |date=2014-11-03}}</ref> Other than the traditional unstructured solution of a ''goto'' statement,{{sfn|Knuth|1974|p=278|loc=Simple Iterations}} general structured solutions include having a conditional (''if'' statement) inside the loop (possibly duplicating the condition but not the statements) or wrapping repeated logic in a function (so there is a duplicated function call, but the statements are not duplicated).<ref name="c2messy" />
 
A common case is where the start of the loop is always executed, but the end may be skipped on the last iteration.{{sfn|Knuth|1974|p=278|loc=Simple Iterations}} This was dubbed by Dijkstra a loop which is performed "''n'' and a half times",<ref>[[Edsger W. Dijkstra]], personal communication to [[Donald Knuth]] on 1974-01-03, cited in {{harvtxt|Knuth|1974|p=278|loc=Simple Iterations}}</ref> and is now called the '''''loop-and-a-half''' problem''.<ref name="roberts"/> Common cases include reading data in the first part, checking for end of data, and then processing the data in the second part; or processing, checking for end, and then preparing for the next iteration.{{sfn|Knuth|1974|p=278|loc=Simple Iterations}}<ref name="roberts"/> In these cases, the first part of the loop is executed {{tmath|n}} times, but the second part is only executed {{tmath|n - 1}} times.
 
This problem has been recognized at least since 1967 by Knuth, with Wirth suggesting solving it via early loop exit.{{sfn|Knuth|1974|p=279}} Since the 1990s this has been the most commonly taught solution, using a ''break'' statement, as in:<ref name="roberts"/>
 
 
'''loop'''
''statements''
'''if''' ''condition'' '''break'''
''statements''
'''repeat'''
 
A subtlety of this solution is that the condition is the ''opposite'' of a usual ''while'' condition: rewriting '''while''' ''condition'' ... '''repeat''' with an exit in the middle requires reversing the condition: '''loop''' ... '''if not''' ''condition'' '''exit''' ... '''repeat'''. The [[#Loop with test in the middle|loop with test in the middle]] control structure explicitly supports the loop-an-a-half use case, without reversing the condition.{{sfn|Knuth|1974|p=279}}
 
=== Early exit from loops ===
When using a count-controlled loop to search through a table, it might be desirable to stop searching as soon as the required item is found. Some programming languages provide a statement such as <code>break</code> (most languages), <code>Exit</code> (Visual Basic), or <code>last</code> (Perl), which effect is to terminate the current loop immediately, and transfer control to the statement immediately after that loop. Another term for early-exit loops is [[loop-and-a-half]].
 
It is sometimes desirable to stop executing a loop before the end of the body; for example, when using a count-controlled loop to search through a table, one can stop as soon as the required item is found. Early exit is the most common way to solve the [[loop-and-a-half]] problem.<ref name="roberts"/>
The following example is done in [[Ada (programming language)|Ada]] which supports both ''early exit from loops'' and ''[[Control flow#Loop with test in the middle|loops with test in the middle]]''. Both features are very similar and comparing both code snippets will show the difference: ''early exit'' must be combined with an '''if''' statement while a ''condition in the middle'' is a self-contained construct.
 
 
Some programming languages provide a statement such as <code>break</code> (most languages), <code>Exit</code> (Visual Basic), or <code>last</code> (Perl), which effect is to terminate the current loop immediately, and transfer control to the statement immediately after that loop.
 
Other mechanisms for early exit include a <code>return</code> out of a subroutine executing the looped statements, breaking out of both the loop and the subroutine; and raising an exception. There are other [[#Proposed control structures|proposed control structures]], but they are not commonly implemented. This section treats early exit from only the loop ("break").
 
Most commonly, this is used by combining a conditional ('''if''' statement) with an unconditional break, as in Ada:
 
<syntaxhighlight lang="ada">
loop
with Ada.Text IO;
Get(X);
with Ada.Integer Text IO;
if X = 0 then
exit;
end if;
-- Do something with X.
end loop;
</syntaxhighlight>
 
In this form, the condition is interpreted as '''until'''. Some languages, such as Ada, have syntax for a conditional break, here an '''exit when''' clause (not to be confused with the '''exitwhen''' statement in {{slink||Proposed control structures}}); if available, this is more idiomatic:
procedure Print_Squares is
 
X : Integer;
<syntaxhighlight lang="ada">
begin
loop
Read_Data : loop
Ada.Integer Text IO.Get(X);
exit Read_Data when X = 0;
-- Do something with X.
Ada.Text IO.Put (X * X);
end loop;
Ada.Text IO.New_Line;
end loop Read_Data;
end Print_Squares;
</syntaxhighlight>
 
This functions similarly to a [[#Loop with test in the middle|loop with test in the middle]], but in that case the test is part of the structure of the loop, dividing the body of the loop in half (visually indented at the same level as the start/end of loop), while early exit is unstructured: simply a statement that can appear anywhere in the body of the loop, and in fact multiple break statements are possible.
 
[[Python (programming language)|Python]] supports conditional execution of code depending on whether a loop was exited early (with a <code>break</code> statement) or not by using an else-clause with the loop. For example,
Line 384 ⟶ 429:
The <code>else</code> clause in the above example is linked to the <code>for</code> statement, and not the inner <code>if</code> statement. Both Python's <code>for</code> and <code>while</code> loops support such an else clause, which is executed only if early exit of the loop has not occurred.
 
==== Multi-level breaks ====
Some languages support breaking out of nested loops; in theory circles, these are called multi-level breaks. One common use example is searching a multi-dimensional table. This can be done either via multilevel breaks (break out of ''N'' levels), as in bash<ref>Advanced Bash Scripting Guide: [http://tldp.org/LDP/abs/html/loopcontrol.html 11.3. Loop Control]</ref> and PHP,<ref>PHP Manual: "[http://php.net/manual/en/control-structures.break.php break]"</ref> or via labeled breaks (break out and continue at given label), as in Go, Java and Perl.<ref>perldoc: [http://perldoc.perl.org/functions/last.html last]</ref> Alternatives to multilevel breaks include single breaks, together with a state variable which is tested to break out another level; exceptions, which are caught at the level being broken out to; placing the nested loops in a function and using return to effect termination of the entire nested loop; or using a label and a goto statement. C does not include a multilevel break, and the usual alternative is to use a goto to implement a labeled break.<ref>comp.lang.c FAQ list · "[http://c-faq.com/misc/multibreak.html Question 20.20b]"</ref> Python does not have a multilevel break or continue – this was proposed in [https://www.python.org/dev/peps/pep-3136/ PEP 3136], and rejected on the basis that the added complexity was not worth the rare legitimate use.<ref>[http://mail.python.org/pipermail/python-3000/2007-July/008663.html <nowiki>[</nowiki>Python-3000<nowiki>]</nowiki> Announcing PEP 3136], Guido van Rossum</ref>
Some languages support breaking out of nested loops; in theory circles, these are called '''multi-level breaks'''. One common use example is searching a multi-dimensional table. This can be done either via multilevel breaks (break out of ''N'' levels), as in bash<ref>Advanced Bash Scripting Guide: [http://tldp.org/LDP/abs/html/loopcontrol.html 11.3. Loop Control]</ref> and PHP,<ref>PHP Manual: "[http://php.net/manual/en/control-structures.break.php break]"</ref> or via labeled breaks (break out and continue at given label), as in Ada. Go, Java and Perl.<ref>perldoc: [http://perldoc.perl.org/functions/last.html last]</ref> Alternatives to multilevel breaks include single breaks, together with a state variable which is tested to break out another level; exceptions, which are caught at the level being broken out to; placing the nested loops in a function and using return to effect termination of the entire nested loop; or using a label and a goto statement. C does not include a multilevel break, and the usual alternative is to use a goto to implement a labeled break.<ref>comp.lang.c FAQ list · "[http://c-faq.com/misc/multibreak.html Question 20.20b]"</ref> Python does not have a multilevel break or continue – this was proposed in [https://www.python.org/dev/peps/pep-3136/ PEP 3136], and rejected on the basis that the added complexity was not worth the rare legitimate use.<ref>[http://mail.python.org/pipermail/python-3000/2007-July/008663.html <nowiki>[</nowiki>Python-3000<nowiki>]</nowiki> Announcing PEP 3136], Guido van Rossum</ref>
 
The notion of multi-level breaks is of some interest in [[theoretical computer science]], because it gives rise to what is today called the ''Kosaraju hierarchy''.<ref name=kozen>{{cite book |first=Dexter |last=Kozen |date=2008 |chapter=The Böhm–Jacopini Theorem is False, Propositionally |title=Mathematics of Program Construction |series=Lecture Notes in Computer Science |doi=10.1007/978-3-540-70594-9_11 |volume=5133 |pages=177–192 |isbn=978-3-540-70593-2 |url=httphttps://www.cs.cornell.edu/~kozen/papers/BohmJacopini.pdf |citeseerx=10.1.1.218.9241}}</ref> In 1973 [[S. Rao Kosaraju]] refined the [[structured program theorem]] by proving that it is possible to avoid adding additional variables in structured programming, as long as arbitrary-depth, multi-level breaks from loops are allowed.<ref>Kosaraju, S. Rao. "Analysis of structured programs," Proc. Fifth Annual ACM Syrup.
Theory of Computing, (May 1973), 240-252; also in J. Computer and System Sciences, 9,
3 (December 1974), cited by {{harvtxt|Knuth|1974}}.</ref> Furthermore, Kosaraju proved that a strict hierarchy of programs exists: for every integer ''n'', there exists a program containing a multi-level break of depth ''n'' that cannot be rewritten as a program with multi-level breaks of depth less than ''n'' without introducing added variables.<ref name="kozen"/>
3 (December 1974). cited by {{cite journal
|last=Knuth |first=Donald
|author-link=Donald Knuth
|year=1974
|title=Structured Programming with go to Statements
|journal=Computing Surveys
|volume=6
|issue=4
|pages=261–301
|doi=10.1145/356635.356640
|citeseerx=10.1.1.103.6084
|s2cid=207630080
}}</ref> Furthermore, Kosaraju proved that a strict hierarchy of programs exists: for every integer ''n'', there exists a program containing a multi-level break of depth ''n'' that cannot be rewritten as a program with multi-level breaks of depth less than ''n'' without introducing added variables.<ref name="kozen"/>
 
One can also <code>return</code> out of a subroutine executing the looped statements, breaking out of both the nested loop and the subroutine. There are other [[#Proposed control structures|proposed control structures]] for multiple breaks, but these are generally implemented as exceptions instead.
 
In his 2004 textbook, [[David Watt (computer scientist)|David Watt]] uses Tennent's notion of [[S-algol|sequencer]] to explain the similarity between multi-level breaks and return statements. Watt notes that a class of sequencers known as ''escape sequencers'', defined as "sequencer that terminates execution of a textually enclosing command or procedure", encompasses both breaks from loops (including multi-level breaks) and return statements. As commonly implemented, however, return sequencers may also carry a (return) value, whereas the break sequencer as implemented in contemporary languages usually cannot.<ref name="WattFindlay2004b">{{cite book|author1=David Anthony Watt|author2=William Findlay| title=Programming language design concepts| year=2004| publisher=John Wiley & Sons|isbn=978-0-470-85320-7|pages=215–221}}</ref>
 
=== Loop with test in the middle ===
The following structure was proposed by [[Ole-Johan Dahl|Dahl]] in 1972:<ref>Dahl & Dijkstra & Hoare, "Structured Programming" Academic Press, 1972.</ref>
 
'''loop''' '''loop'''
xxx1 read(char);
'''while''' test; '''while''' '''not''' atEndOfFile;
xxx2 write(char);
'''repeat'''; '''repeat''';
 
The construction here can be thought of as a '''do''' loop with the '''while''' check in the middle, which allows clear [[#Loop-and-a-half|loop-and-a-half]] logic. Further, by omitting individual components, this single construction can replace several constructions in most programming languages. If ''xxx1'' is omitted, we get a loop with the test at the top (a traditional '''while''' loop). If ''xxx2'' is omitted, we get a loop with the test at the bottom, equivalent to a '''do while''' loop in many languages. If '''while''' is omitted, we get an infinite loop. This construction also allows keeping the same polarity of the condition even when in the middle, unlike early exit, which requires reversing the polarity (adding a '''not'''),{{sfn|Knuth|1974|p=279}} functioning as '''until''' instead of '''while'''.
 
This structure is not widely supported, with most languages instead using '''if''' ... '''break''' for conditional early exit.
 
This is supported by some languages, such as [[Forth (programming language)|Forth]], where the syntax is BEGIN ... WHILE ... REPEAT,<ref>{{Cite web|url=https://www.forth.com/starting-forth/6-forth-do-loops/|title=6. Throw It For a Loop}}</ref> and the [[shell script]] languages [[Bourne shell]] (<code>sh</code>) and [[Bash (Unix shell)|bash]], where the syntax is '''while''' ... '''do''' ... '''done''' or '''until''' ... '''do''' ... '''done''', as:<ref>{{citation |url=https://www.gnu.org/software/bash/manual/bash.html |title=The GNU Bash Reference Manual |section=3.2.5.1 Looping Constructs |section-url=https://www.gnu.org/software/bash/manual/bash.html#Looping-Constructs-1 |date=2025-05-18}}</ref><ref>{{cite web |url=https://langdev.stackexchange.com/questions/1815/how-could-a-language-make-the-loop-and-a-half-less-error-prone/1868#1868 |title=How could a language make the loop-and-a-half less error-prone? |work=Stack Exchange: Programming Language Design and Implementation}}</ref>
 
<syntaxhighlight lang="bash">
while
statement-1
statement-2
...
condition
do
statement-a
statement-b
...
done
</syntaxhighlight>
 
The shell syntax works because the '''while''' (or '''until''') loop accepts a list of commands as a condition,<ref>{{citation |url=https://www.gnu.org/software/bash/manual/bash.html |title=The GNU Bash Reference Manual |section=3.2.4 Lists of Commands |section-url=https://www.gnu.org/software/bash/manual/bash.html#Lists |date=2025-05-18}}</ref> formally:
 
'''while''' ''test-commands''; '''do''' ''consequent-commands''; '''done'''
 
The value (exit status) of the list of ''test-commands'' is the value of the ''last'' command, and these can be separated by newlines, resulting in the idiomatic form above.
 
Similar constructions are possible in C and C++ with the [[comma operator]], and [[Comma_operator#Other_languages|other languages with similar constructs]], which allow shoehorning a list of statements into the while condition:
 
<syntaxhighlight lang="c">
while (
statement_1,
statement_2,
condition
) {
statement_a;
statement_b;
}
</syntaxhighlight>
 
While legal, this is marginal, and it is primarily used, if at all, only for short modify-then-test cases, as in:<ref>{{cite web |url=https://stackoverflow.com/questions/52550/what-does-the-comma-operator-do/52615#52615 |title=What does the comma operator , do? |work=[[Stack Overflow]]}}</ref>
 
<syntaxhighlight lang="c">
while (read_string(s), strlen(s) > 0) {
// ...
}
</syntaxhighlight>
 
=== Loop variants and invariants ===
Line 837 ⟶ 924:
| {{yes}}
| {{no}}
| {{dunnoyes}}
| {{yes}}
|
Line 852 ⟶ 939:
# {{note_label|while|7|a}} There is no special construct, since the <code>while</code> function can be used for this.
# {{note_label|user|8|a}} There is no special construct, but users can define general loop functions.
# {{note_label|loop_foreach|9|a}} The [[C++11]] standard introduced the [[C++11#Range-based for loop|range-based for]]. In the [[Standard Template Library|STL]], there is a <code>std::for_each</code> [[template (programming)|template]] function which can iterate on STL [[Container (data structure)|containers]] and call a [[unary function]] for each element.<ref>[http://www.sgi.com/tech/stl/for_each.html for_each]. Sgi.com. Retrieved on 2010-11-09.</ref> The functionality also can be constructed as [[C preprocessor#Macro definition and expansion|macro]] on these containers.<ref>[httphttps://boost-sandbox.sourceforge.net/libs/foreach/doc/html/ Chapter 1. Boost.Foreach] {{Webarchive|url=https://web.archive.org/web/20100129070613/http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/ |date=2010-01-29}}. Boost-sandbox.sourceforge.net (2009-12-19). Retrieved on 2010-11-09.</ref>
# {{note_label|count_loop_eiffel|10|a}} Count-controlled looping is effected by iteration across an integer interval; early exit by including an additional condition for exit.
# {{note_label|retry_in_eiffel|11|a}} Eiffel supports a reserved word <code>retry</code>, however it is used in [[Exception handling#Exception handling based on design by contract|exception handling]], not loop control.
# {{note_label|requires_JML|12|a}} Requires [[Java Modeling Language]] (JML) behavioral interface specification language.
# {{note_label|integer_variant|13|a}} Requires loop variants to be integers; transfinite variants are not supported. [http://archive.eiffel.com/doc/faq/variant.html Eiffel: Why loop variants are integers]
# {{note_label|DInfinite|13|a}} D supports infinite collections, and the ability to iterate over those collections. This does not require any special construct.
# {{note_label|cobol_deep_exit|14|a}} Deep breaks can be achieved using <code>GO TO</code> and procedures.
Line 1,075 ⟶ 1,162:
| {{yes}}
| {{yes}}
| {{yes}}<ref>{{citeCite web |url=https://docs.python.org/3/library/asyncio.html |title=Asyncio:asyncio — Asynchronous I/O: |website=Python 3.10.2 documentation}}</ref>
|-
| [[Rebol]]
Line 1,092 ⟶ 1,179:
| {{no}}
| {{yes}}
| {{yes|experimental}} <ref>{{citeCite web|url=https://doc.rust-lang.org/beta/unstable-book/language-features/generators.html|title=Generatorsgenerators - theThe Rust Unstable Book|website=doc.rust-lang.org}}</ref><ref>{{citeCite web|url=https://docs.rs/corona/0.4.3/corona/|title=Coronacorona - Rust|website=docs.rs}}</ref>
| {{yes}}<ref>{{citeCite web|url=https://rust-lang.github.io/async-book/|title=Getting StartedIntroduction - Asynchronous Programming in Rust|website=rust-lang.github.io}}</ref>
|-
| [[Scala (programming language)|Scala]]
Line 1,121 ⟶ 1,208:
 
== Proposed control structures ==
=== COMEFROM ===
{{main|COMEFROM}}
In a spoof [[Datamation]] article<ref>[http://www.fortran.com/fortran/come_from.html We don't know where to GOTO if we don't know where we've COME FROM. This (spoof) linguistic innovation lives up to all expectations.] {{Webarchive|url=https://web.archive.org/web/20180716171336/http://www.fortran.com/fortran/come_from.html |date=2018-07-16 }} By R. Lawrence Clark* From Datamation, December, 1973</ref> in 1973, R. Lawrence Clark suggested that the GOTO statement could be replaced by the [[COMEFROM]] statement, and provides some entertaining examples. COMEFROM was implemented in one [[esoteric programming language]] named [[INTERCAL]].
 
=== Event-based early exit from nested loops ===
[[Donald Knuth]]'s 1974 article "Structured Programming with go to Statements",<ref>Knuth, Donald E. "Structured Programming with go to Statements" [[ACM Computing Surveys]] 6(4):261-301, December 1974.</ref> identifies two situations which were not covered by the control structures listed above, and gave examples of control structures which could handle these situations. Despite their utility, these constructs have not yet found their way into mainstream programming languages.
[[Zahn's construct|This construct]] was proposed by [[Zahn's construct|Zahn]] in 1974,<ref>Zahn, C. T. "A control statement for natural top-down structured programming" presented at Symposium on Programming Languages, Paris, 1974.</ref> and discussed in {{harvtxt|Knuth|1974}}. A modified version is presented here.
 
=== Loop with test in the middle ===
The following was proposed by [[Ole-Johan Dahl|Dahl]] in 1972:<ref>Dahl & Dijkstra & Hoare, "Structured Programming" Academic Press, 1972.</ref>
 
'''loop''' '''loop'''
xxx1 read(char);
'''while''' test; '''while''' '''not''' atEndOfFile;
xxx2 write(char);
'''repeat'''; '''repeat''';
 
If ''xxx1'' is omitted, we get a loop with the test at the top (a traditional '''while''' loop). If ''xxx2'' is omitted, we get a loop with the test at the bottom, equivalent to a '''do while''' loop in many languages. If '''while''' is omitted, we get an infinite loop. The construction here can be thought of as a '''do''' loop with the while check in the middle. Hence this single construction can replace several constructions in most programming languages.
 
Languages lacking this construct generally emulate it using an equivalent infinite-loop-with-break idiom:
'''while''' (true) {
xxx1
'''if''' ('''not''' test)
'''break'''
xxx2
}
 
A possible variant is to allow more than one '''while''' test; within the loop, but the use of '''exitwhen''' (see next section) appears to cover this case better.
 
In [[Ada (programming language)|Ada]], the above loop construct ('''loop'''-'''while'''-'''repeat''') can be represented using a standard infinite loop ('''loop''' - '''end loop''') that has an '''exit when''' clause in the middle (not to be confused with the '''exitwhen''' statement in the following section).
 
<syntaxhighlight lang="ada">
with Ada.Text_IO;
with Ada.Integer_Text_IO;
 
procedure Print_Squares is
X : Integer;
begin
Read_Data : loop
Ada.Integer_Text_IO.Get(X);
exit Read_Data when X = 0;
Ada.Text IO.Put (X * X);
Ada.Text IO.New_Line;
end loop Read_Data;
end Print_Squares;
</syntaxhighlight>
 
Naming a loop (like ''Read_Data'' in this example) is optional but permits leaving the outer loop of several nested loops.
 
=== Multiple early exit/exit from nested loops ===
[[Zahn's construct|This construct]] was proposed by [[Zahn's construct|Zahn]] in 1974.<ref>Zahn, C. T. "A control statement for natural top-down structured programming" presented at Symposium on Programming Languages, Paris, 1974.</ref> A modified version is presented here.
'''exitwhen''' EventA '''or''' EventB '''or''' EventC;
xxx
Line 1,210 ⟶ 1,256:
* [[Jeroo]], helps learn control structures
* [[Main loop]]
* [[Predication_(computer_architecture)|predication]]
* [[Recursion]]
* [[Scheduling (computing)]]