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-
void
return 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
switch
statement is compatible (see Type Compatibility) with the type of theswitch
statement’s expression.In a
switch
statement expression of type enum, every case expression associated with theswitch
statement is of type enum.No two case expressions associated with the
switch
statement have identical values.No case expression associated with the
switch
statement 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
try
block and the entiretry
statement complete normally if nocatch
block is executed. The execution of atry
block completes abruptly if an exception or an error is thrown inside thetry
block.Catch
clauses are checked in the textual order of their position in the source code.The execution of a
try
block completes abruptly if exception or error x is thrown inside thetry
block. If the runtime type of x is compatible (see Type Compatibility) with the exception class of the exception parameter (i.e., thecatch
clause matches x), and the execution of the body of thecatch
clause completes normally, then the entiretry
statement completes normally. Otherwise, thetry
statement completes abruptly.If no
catch
clause 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).