8. Statements¶
Statements are designed to control the execution:
statement:
expressionStatement
| block
| localDeclaration
| ifStatement
| loopStatement
| breakStatement
| continueStatement
| returnStatement
| switchStatement
| throwStatement
| tryStatement
| assertStatement
;
8.1. Normal and Abrupt Statement Execution¶
The actions that every statement performs in a normal mode of execution are specific for the particular kind of that statement. The normal modes of evaluation for each kind of statement are described in the following sections.
A statement execution is considered to complete normally if the desired action is performed without an exception or an error being thrown.
On the contrary, a statement execution is considered to complete abruptly if it causes an exception or an error to be thrown.
8.2. Expression Statements¶
Any expression can be used as a statement:
expressionStatement:
expression
;
The execution of a statement leads to the execution of the expression. The result of such execution is discarded.
8.3. Block¶
A sequence of statements enclosed in balanced braces forms a block:
block:
'{' statement* '}'
;
The execution of a block means that all block statements, except type declarations, are executed one by one in the textual order of their appearance within the block if no exception, error, or return occurs.
If a block is the body of a functionDeclaration or a classMethodDeclaration, which was declared implicitly or explicitly with return type void, then the block can contain no return statement at all. Such a block is equivalent to a block ending in the return statement, and is executed accordingly.
8.4. Local Declarations¶
Local declarations define new mutable or immutable variables or types within the enclosing context.
Let and const declarations have the initialization part that presumes execution, and actually act as statements:
localDeclaration:
variableDeclaration
| constantDeclaration
| typeDeclaration
;
The visibility of a local declaration name is determined by the function (method) and block scope rules (see Scopes).
8.5. if Statements¶
An if statement allows executing alternative statements (if provided) under
certain conditions:
ifStatement:
'if' '(' expression ')' statement1
('else' statement2)?
;
If an expression represents a condition and is successfully evaluated as true, then statement1 is executed. Otherwise, statement2 is executed (if provided). A compile-time error occurs if the expression type is not boolean.
Any else matches the first if of an if statement:
1 if (Cond1)
2 if (Cond2) statement1
3 else statement2 // Executes only if: Cond1 && !Cond2
A list of statements in braces (see Block) is used to combine the
else part with the first if:
1 if (Cond1) {
2 if (Cond2) statement1
3 }
4 else statement2 // Executes if: !Cond1
8.6. loop Statements¶
ArkTS has four kinds of loops. A loop of each kind can have an optional loop
label that can be used only by break and continue statements contained
in the body of the loop. The label is characterized by an identifier as shown
below:
loopStatement:
(identifier ':')?
whileStatement
| doStatement
| forStatement
| forOfStatement
;
8.7. while Statements and do Statements¶
A while statement and a do statement evaluate an expression and
execute a statement repeatedly till the expression value is true.
The key difference is that whileStatement first evaluates and checks the
expression value, and doStatement first executes the statement:
whileStatement:
'while' '(' expression ')' statement
;
doStatement
: 'do' statement 'while' '(' expression ')'
;
8.8. for Statements¶
forStatement:
'for' '(' forInit? ';' expression? ';' forUpdate? ')' statement
;
forInit:
expressionSequence
| variableDeclarations
;
forUpdate:
expressionSequence
;
1 // existing variable
2 let i: number
3 for (i = 1; i < 10; i++) {
4 console.log(i)
5 }
6
7 // new variable, explicit type:
8 for (let i: number = 1; i < 10; i++) {
9 console.log(i)
10 }
11
12 // new variable, implicit type
13 // inferred from variable declaration
14 for (let i = 1; i < 10; i++) {
15 console.log(i)
16 }
8.9. for-of Statements¶
A for-of loop iterates elements of array or string, or an instance
of iterable class or interface (see Iterable Types):
forOfStatement:
'for' '(' forVariable 'of' expression ')' statement
;
forVariable:
identifier | ('let' | 'const') identifier (':' type)?
;
A compile-time error occurs if the type of an expression is not array, string, or iterable type.
The execution of a for-of loop starts with the evaluation of expression.
If the evaluation is successful, then the resultant expression is used for
loop iterations (execution of the statement). On each iteration,
forVariable is set to successive elements of the array, string, or
result of class iterator advancing.
If forVariable has the modifiers let or const, then a new variable
is used inside the loop. Otherwise, the variable is as declared above.
The modifier const prohibits assignments into forVariable,
while let allows modifications.
Explicit type annotation of forVariable is allowed as an experimental feature (see For-of Type Annotation).
1 // existing variable 'ch'
2 let ch : char
3 for (ch of "a string object") {
4 console.log(ch)
5 }
6
7 // new variable 'ch', its type is
8 // inferred from expression
9 for (let ch of "a string object") {
10 console.log(ch)
11 }
12
13 // new variable 'element', its type is
14 // inferred from expression, and it
15 // cannot be assigned with a new value
16 // in the loop body
17 for (const element of [1, 2, 3]) {
18 console.log(element)
19 }
8.10. break Statements¶
A break statement transfers control out of the enclosing loopStatement
or switchStatement:
breakStatement:
'break' identifier?
;
A break statement with the label identifier transfers control out of the
enclosing statement with the same label identifier. A compile-time error
occurs if such a statement is not found within the body of the surrounding
function or method.
A statement without a label transfers control out of the innermost enclosing
switch, while, do, for, or for-of statement.
A compile-time error occurs if the breakStatement is not found within loopStatment or switchStatement.
8.11. continue Statements¶
A continue statement stops the execution of the current loop iteration,
and transfers control to the next iteration. Appropriate checks of loop
exit conditions depend on the kind of the loop.
continueStatement:
'continue' identifier?
;
A continue statement with the label identifier transfers control out
of the enclosing loop statement with the same label identifier.
A compile-time error occurs if such a statement is not found within the body
of the surrounding function or method.
A compile-time error occurs if no continueStatement is found within loopStatment.
8.12. return Statements¶
A return statement can have or not have an expression.
returnStatement:
'return' expression?
;
A ‘return expression’ statement can only occur inside a function or a method body.
A return statement (with no expression) can occur in one of the following
situations:
Inside a class initializer;
Inside a constructor body; or
Inside a function or a method body with return type
void.
A compile-time error occurs if a return statement is found in:
Top-level statements (see Top-Level Statements);
Class initializers (see Class Initializer) and constructors (see Constructor Declaration), where it has an expression;
A function or a method with return type
void, where it has an expression;A function or a method with a non-
voidreturn type, where it has no expression.
The execution of returnStatement leads to the termination of the surrounding function or method. If an expression is provided, the resultant value is the evaluated expression.
In case of constructors, class initializers, and top-level statements, the control is transferred out of the scope of the construction in question, but no result is required. Other statements of the surrounding function, method body, class initializer, or top-level statement are not executed.
8.13. switch Statements¶
A switch statement transfers control to a statement or a block by using the
result of successful evaluation of the value of a switch expression.
switchStatement:
(identifier ':')? 'switch' '(' expression ')' switchBlock
;
switchBlock
: '{' caseClause* defaultClause? caseClause* '}'
;
caseClause
: 'case' expression ':' (statement+ | block)?
;
defaultClause
: 'default' ':' (statement+ | block)?
;
The switch expression type must be of type char, byte, short, int, long, Char, Byte, Short, Int, Long, string, or enum.
A compile-time error occurs if not all of the following is true:
Every case expression type associated with a
switchstatement is compatible (see Type Compatibility) with the type of theswitchstatement’s expression.In a
switchstatement expression of type enum, every case expression associated with theswitchstatement is of type enum.No two case expressions associated with the
switchstatement have identical values.No case expression associated with the
switchstatement is null.
1 let arg = prompt("Enter a value?");
2 switch (arg) {
3 case '0':
4 case '1':
5 alert('One or zero')
6 break
7 case '2':
8 alert('Two')
9 break
10 default:
11 alert('An unknown value')
12 }
The execution of a switch statement starts from the evaluation of the
switch expression. If the evaluation result is of type Char, Byte,
Short, or Int, then the unboxing conversion follows.
Otherwise, the value of the switch expression is compared repeatedly to the
value of each case expression.
If a case expression value equals the value of the switch expression in
terms of the operator ‘\(==\)’, then the case label matches.
However, if the expression value is a string, then the equality for strings determines the equality.
8.14. throw Statements¶
A throw statement causes exception or error to be thrown (see
Error Handling). It immediately transfers control, and can exit multiple
statements, constructors, functions, and method calls until a try statement
(see try Statements) is found that catches the thrown value. If no
try statement is found, then UncatchedExceptionError is thrown.
throwStatement:
'throw' expression
;
The expression’s type must be assignable (see Assignment) to type Exception or Error. Otherwise, a compile-time error occurs.
This implies that the thrown object is never null.
It is necessary to check at compile time that a throw statement, which
throws an exception, is placed in the try block of a try statement,
or in a throwing function (see Throwing Functions). Errors can
be thrown at any place in the code.
8.15. try Statements¶
A try statement runs blocks of code, and provides sets of catch clauses
to handle different exceptions and errors (see Error Handling).
tryStatement:
'try' block catchClauses finallyClause?
;
catchClauses:
typedCatchClause* catchClause?
;
catchClause:
'catch' '(' identifier ')' block
;
typedCatchClause:
'catch' '(' identifier ':' typeReference ')' block
;
finallyClause:
'finally' block
;
The ArkTS programming language supports multiple typed catch clauses as an experimental feature (see try Statements).
A try statement must contain either a finally clause, or at least one
catch clause. Otherwise, a compile-time error occurs.
If the try block completes normally, then no action is taken, and no
catch clause block is executed.
If an error is thrown in the try block directly or indirectly, then the
control is transferred to the catch clause.
8.15.1. catch Clause¶
A catch clause consists of two parts:
Catch identifier that provides access to the object associated with the error thrown; and
Block of code that handles the situation.
The type of catch identifier is Object.
See Multiple Catch Clauses in Try Statements for the details of typed catch clause.
1 class ZeroDivisor extends Error {}
2
3 function divide(a: number, b: number): number {
4 if (b == 0)
5 throw new ZeroDivisor()
6 return a / b
7 }
8
9 function process(a: number, b: number): number {
10 try {
11 let res = divide(a, b)
12
13 // further processing ...
14 }
15 catch (e) {
16 return e instanceof ZeroDivisor? -1 : 0
17 }
18 }
A catch clause handles all errors at runtime. It returns ‘-1’ for
the ZeroDivisor, and ‘0’ for all other errors.
8.15.2. finally Clause¶
A finally clause defines the set of actions in the form of a block to be
executed without regard to whether a try-catch completes normally or
abruptly.
finallyClause:
'finally' block
;
A finally block is executed without regard to how (by reaching
exception, error, return, or try-catch end) the program control
is transferred out. The finally block is particularly useful to ensure
proper resource management.
Any required actions (e.g., flush buffers and close file descriptors)
can be performed while leaving the try-catch:
class SomeResource {
// some API
// ...
close() : void {}
}
function ProcessFile(name: string) {
let r = new SomeResource()
try {
// some processing
}
finally {
// finally clause will be executed after try-catch is
executed normally or abruptly
r.close()
}
}
8.15.3. try Statement Execution¶
A
tryblock and the entiretrystatement complete normally if nocatchblock is executed. The execution of atryblock completes abruptly if an exception or an error is thrown inside thetryblock.Catchclauses are checked in the textual order of their position in the source code.The execution of a
tryblock completes abruptly if exception or error x is thrown inside thetryblock. If the runtime type of x is compatible (see Type Compatibility) with the exception class of the exception parameter (i.e., thecatchclause matches x), and the execution of the body of thecatchclause completes normally, then the entiretrystatement completes normally. Otherwise, thetrystatement completes abruptly.If no
catchclause can handle an exception or an error, then those propagate to the surrounding scope. If the surrounding scope is a function, method, or constructor, then the execution depends on whether the surrounding scope is a throwing function (see Throwing Functions). If so, then the exception propagates to the caller context. Otherwise, UncatchedExceptionError is thrown.
8.16. Assert Statements¶
The assert statements are described in the chapter Experimental Features
(see Assert Statements).