Control flow is the order function calls, instructions, and statements are executed or evaluated when a program is running. Like many programming languages, CM have what are called control flow statements, which determine what section of code is run in a program at any time.
Conditional Statements
Repetition
Exceptions
Other
Conditional Statements
if
Use if statements to select a statement or block of code to execute based on a condition.
General Form
If-statements have the following general forms:
if (condition) consequence
if (condition) consequence else alternative
if (condition0) consequence0
else if (condition1) consequence1
..
else if (conditionN) consequenceN
else alternative
where condition is a boolean expression and consequence and alternative are statements. The consequence is executed if condition is true. When several conditions exist with else if, the conditions are evaluated in order. When a condition is true and the corresponding consequence has been executed, processing stops. If no conditions are true, the alternative will be executed instead.
Type conversions and assignments
The condition can also contain type conversions and assignments like this:
id = expr
type id = expr
The consequence statement will only be executed if expr is not null, or has type bool and value true. The identifier id is only visible inside the consequence block, if it was declared inside the condition using the second form.
Casting
The condition can also contain type casting, using the keyword as, like this:
id as type
The consequence statement will only be executed if the casting of the identifier id into type was successful. Inside the consequence block, id is of type.
Example
{ AShape2D shape = APolyline2D(); // fillColor() is final in AShape2D and can be called directly. pln(shape.fillColor()); if (shape as APolyline2D) { // count() extend APolyline2D and type casting is necessary. pln(#shape.count()); } }
Type checking
The condition can also contain type checking (without casting), using the keyword in, like this:
id in type
The consequence statement will only be executed if id is of type. The initial typing of id will be maintained, even inside the consequence block.
Example
{ AShape2D shape = APolyline2D(); if (shape in APolyline2D) { pln("shape is a polyline!"); //pln(#shape.count()); // Would give compile error } }
See also: Type Tests and Conversions.
switch
General Form
switch(expr) { caseClause1 caseClause2 .. caseClausen }
where caseClause can have the forms
case literal: stmt case literal1, literal2, .., literaln: stmt
default: stmt
and literal is a literal of a supported type. No case may be repeated. The supported types are:
- all integer types except nat and int64
- all enum types
- integer ranges
- str
- symbol
The default case is chosen when the expression does not match any of the other cases. Failure to match an alternative will throw an exception if the default case was omitted.
Examples
{ int x = 1; switch(x) { case 1: pln("one"); case 2: pln("two"); default: pln("other"); } }
{ switch(x) { case 1, 3, 5: { pln("odd"); } case 2, 4, 6: { pln("even"); } default: pln("other"); } }
{ switch(x) { case 0..9: pln("one digit"); case 10..99: pln("two digits"); } }
{ str s = getStr(); switch(s) { case "SE": lang = "swedish"; case "FR": lang = "french"; default: ; } }
{ symbol sym; switch(sym) { case #"cm.core": pkg = "core"; case #"cm.win": pkg = "win"; default: pkg = "fail"; } }
Repetition
for
Use for statements to loop over a statement for a specified number of values.
General Form
for (controlVariable in values) { stmt; }
where ''values'' can be:
a simple integer range defined like:
first..last
or an iterable data collection like:
- sequence
- set
- enum
- map
Examples
{ for (i in 1..10) { pln(#i); } }
{ Object[] seq(); seq << "Hello" << "World" << Int(8) << Double(2.3) << "Dude"; for (o in seq) { pln(#o); } }
{ str->int nameToAge(); nameToAge.put("Joan", 41); nameToAge.put("Mike", 32); nameToAge.put("John", 55); for (n, a in nameToAge) { pln(n, " is ", a, " years old"); } }
Keywords
index
The value of the current index of the loop.
{ for (n in 1..5, index=i) { pln(#i; #n); } }
Output: i=0, n=1 i=1, n=2 i=2, n=3 i=3, n=4 i=4, n=5
{ int[] values(); values << 3 << 8 << 10 << 31 << 100; for (n in values, index=i) { pln(#i; #n); } }
Output: i=0, n=3 i=1, n=8 i=2, n=10 i=3, n=31 i=4, n=100
step
Iterate in steps. Applicable for numerics.
{ for (n in 1..5, index=i, step=2) { pln(#i; #n); } }
Output: i=0, n=1 i=1, n=3 i=2, n=5
{ for (d in 1..1.74, step=.2) { pln(#d); } }
Output: d=1 d=1.2 d=1.4 d=1.6
reverse
Iterate backwards. Applicable for sequences, sorted maps and strings.
{ int[] values(); values << 3 << 8 << 10 << 31 << 100; for (n in values, index=i, reverse) { pln(#i; #n); } }
Output: i=4, n=100 i=3, n=31 i=2, n=10 i=1, n=8 i=0, n=3
start and end
Start and end iteration at the given index. Applicable for sequences and strings.
private str txt = "A simple text";
{ for (s in txt, start=9) { pln(s); } } Output: t e x t
{ for (s in txt, end=7) { pln(s); } } Output: A s i m p l e
{ for (s in txt, start=2, end=7) { pln(s); } } Output: s i m p l e
{ for (s in txt, start=7, end=2, reverse) { pln(s); } } Output: e l p m i s
Keywords inside loop
Some boolean keywords exist for convenience during iteration.
more
Is true if there are more values, i.e. if the loop will iterate at least one more time.
{ str[] lines(); lines << "First line" << "Second line" << "Third line"; StrBuf buf(); for (l in lines) { buf << l; if (more) buf << "\n"; } pln(buf); } Output: First line Second line Third line cm>
first
Is true if this is the first iteration.
{ point ref(1, 1, 1); point{} allPositions(); allPositions << (0, 0, 0) << (1, 0, 1) << (0, 2, 1); point closest; for (p in allPositions) { if (first) { closest = p; } else { if (ref.distance(p) < ref.distance(closest)) { closest = p; } } } }
last
Is true if this is the last iteration.
{ str[] linesWLF(); linesWLF << "First line\n" << "Second line\n" << "Third line\n"; StrBuf buf(); for (l in linesWLF) { buf << l; if (last) buf.dropLast(); } pln(buf); } Output: First line Second line Third line cm>
while
Use while statements to loop over a statement as long as a specified condition is fulfilled.
General Form
while (condition) { stmt; }
Another possibility is to include initialization and/or increment in the while statement.
while (initialization; condition; increment) { stmt; }
Examples
{ int i = 0; while (i < 100) { pln(#i); i++; } }
{ while (int i = 0; i <= 10; i++) { pln(#i); } }
{ int maxLength = 1024; int count; StrBuf txt(); Url url("c:\\temp\\testFile.txt"); if (url.isReadable) { if (File input = openForRead(url)) { pln("Opened file"); while (input.more) { count++; if (count > maxLength) { pln("Stopped reading"); break; } char next = input.get().char; txt << next; } input.close(); pln("Read ", txt.count, " characters from ", url); } } else { pln("Not readable: ", url); } }
do..while
A do while-loop executes a block of code at least once, and then repeatedly executes the block, or not, depending on a given condition at the end of the block.
General Form
do { stmt; } while condition
Example
{ int i = 0; do { pln(#i); } while (i++ < 10); }
Exceptions
try..catch..finally
The combination of try, catch and finally is used to execute code in a try block, deal with exceptional circumstances in a catch block, and perform cleanup or final actions in a finally block. catch and finally are optional. Note that the finally block will always be performed if it exists.
General Form
try { stmt } catch (Exception e) { exception handling } finally { cleanup }
Example
{ try { int dividend = randI(11); int divisor = randI(3); pln(dividend, "/", divisor, " = ", dividend/divisor); } catch (Exception e) { pln(eRed, e.description, ePop); } finally { pln("Division attempt was successful"); } }
do..finally
The combination of do and finally is used to execute code in a do block and perform cleanup or final actions in a finally block. Note that the finally block will always be performed unless an exception is raised in the do block.
General Form
do { stmt } finally { cleanup }
Example
{ int steps = 200; ProgressDialog dialog = beginProgress(anyFrameWindow, steps, modal=true); do { for (j in 1..steps) { if (dialog.aborted) break; sleep(20); incrProgress(); } } finally { endProgress(); } }
throw
If a problem occurs it may be useful to throw an exception for this rather than just avoiding the problem. Subroutines can throw exceptions that are then handled in try..catch..finally clauses by methods calling the subroutines. You can throw exceptions that are subclasses of the class Exception.
Examples
public class APolyline2D extends AShape2D { .. /** * Close the polyline. */ public void close() { if (!_closed) { if (points.count > 0) { points << points[0]; _closed = true; } else { throw CantHappen("Cannot close polyline : no points added."); } } } .. }
{ try { int dividend = randI(11); int divisor = randI(3); pln(dividend, "/", divisor, " = ", dividend/divisor); } catch (Exception e) { if (developMode) throw e; else pln(eRed, e.description, ePop); } finally { pln("Division attempt was successful"); } }
Other
break
When a break statement is encountered inside a loop, the loop is immediately terminated and the program control resumes at the next statement following the loop. The break statement breaks the loop one by one, i.e., in the case of nested loops, it breaks the inner loop first and then proceeds to outer loops.
Examples
{ Object[] objs(); objs << 2.4 << 1 << "C" << 5; double sum; for (obj in objs) { if (obj as Number) { sum += obj.double; pln(#obj; #sum); } else { pln(eRed, "Break "; #obj, ePop); break; } } pln(#sum); }
Output:
obj=2.4, sum=2.4
obj=1, sum=3.4
Break , obj=C
sum=3.4
{ Object[] objs(); objs << 2.4 << 1 << 2.6 << "C" << 5; double res; for (obj in objs) { if (obj as Number) { double factor1 = obj.double; for (factor2 in 1..10) { double product = factor1 * factor2; if (product > 10) { pln(eRed, "Break inner"; #product, ePop); break; } else { res += product; pln(#product; #res); } } } else { pln(eRed, "Break outer"; #obj, ePop); break; } } pln(eGreen, #res, ePop); }
Output: product=2.4, res=2.4 product=4.8, res=7.2 product=7.2, res=14.4 product=9.6, res=24 Break inner, product=12 product=1, res=25 product=2, res=27 product=3, res=30 product=4, res=34 product=5, res=39 product=6, res=45 product=7, res=52 product=8, res=60 product=9, res=69 product=10, res=79 product=2.6, res=81.6 product=5.2, res=86.8 product=7.8, res=94.6 Break inner, product=10.4 Break outer, obj=C res=94.6
continue
When a continue statement is encountered inside a loop, the flow of control is interrupted, however, iteration of the loop will be continued.
Example
{ int start; int stop = 10; int sum; while (int i = 0; i < 10; i++) { if (i%2 == 0) continue; sum += i; pln(#i; #sum); } pln("The sum of odd numbers between ", start, " and ", stop, " is ", sum); }
Output: i=1, sum=1 i=3, sum=4 i=5, sum=9 i=7, sum=16 i=9, sum=25 The sum of odd numbers between 0 and 10 is 25
goto
To transfer the control from one statement to another statement, goto can be used. The transfer can be done within the same block and there must a label, where you want to transfer the control.
The use of goto may lead to code that is hard to follow, so use it with caution!
Example
{ Object[] objs(); objs << 2.4 << 1 << "C" << 2.6 << "Alpha" << 5; double sum; int c; if (objs.any) { TryNext: c++; pnn("Trying index ", c-1, ": "); Object obj = objs[c-1]; if (obj as Number) { pln("Adding ", obj); sum += obj.double; } else { pln("Skipping ", obj); goto TryNext; } if (c < objs.count) { goto TryNext; } } pln(c, " elements was checked. The sum of all numeric elements is ", sum); }
Output: Trying index 0: Adding 2.4 Trying index 1: Adding 1 Trying index 2: Skipping C Trying index 3: Adding 2.6 Trying index 4: Skipping Alpha Trying index 5: Adding 5 6 elements was checked. The sum of all numeric elements is 11
Comments
0 comments
Please sign in to leave a comment.