Statements
Statements execute actions, introduce declarations, or control which code runs. Unlike expressions, they do not pass a value to a surrounding expression.
let message = "ready" // declaration statement
Console.WriteLine(message) // expression statement
count = count + 1 // assignment statement
Newlines normally separate statements. Semicolons are optional, but can separate several statements on one line. See Control flow for the complete termination and line-continuation rules.
Assignment statements
An assignment replaces or updates the value stored in a writable location:
count = 1
count += 2
person.Name = "Ada"
values[index] = 42
In statement position, assignment syntax produces an assignment statement. The left side may be an assignable expression—such as a mutable local, property, field, or element access—or a supported assignment pattern.
Use _ = expression to evaluate an expression and discard its result
explicitly:
_ = trySave()
Nullable conditional member assignment is also valid:
receiver?.Member = value
receiver?.Member += delta
Raven evaluates the receiver once and skips the write when it is null.
Pattern assignments can update several existing locations at once. Their forms and extraction rules are described under Matching and deconstruction.
Expression statements
Most expressions can be used as statements when their value is not needed:
Console.WriteLine("saved")
service.Refresh()
The expression is evaluated for its effects and the statement has type unit.
Its value does not become an implicit return value merely because the statement
appears at the end of a function.
A type name such as Console or System.Console does not produce a value.
Using it alone as an expression statement is a compiler error (RAV0120).
It does not trigger the unused-result warning.
Type names remain valid as receivers for static members, as in
Console.WriteLine("saved").
A final non-unit expression in a unit-returning function is still discarded,
but diagnostic RAV9034 warns because it can resemble an accidental implicit
result. Use _ = expression to make an intentional discard clear, change the
return type when the value should be returned, or configure the analyzer when
that convention is not wanted.
Control-flow statements
if, loop, while, for, match, and try have dedicated statement forms.
They run branches or bodies for their effects instead of contributing a value
to a surrounding expression.
Statement-form match, and statement-form if with an else, can provide an
implicit tail result when they are the final statement of a value-returning
body. Outside that position, Raven warns when statement-form control flow
appears to compute branch values that are discarded:
RAV2107formatchRAV2108forifRAV2109fortry
Add explicit return statements when using statement form, or use the
corresponding expression in a value context.
Pattern-binding statements such as if let, while let, for let, and
let ... else combine a pattern test with local declarations:
if let Some(name) = maybeName {
Console.WriteLine(name)
}
let Some(requiredName) = maybeName else {
return
}
See Pattern matching for their binding behavior and Control-flow expressions and statements for branching and loops.
Lock statements
A lock statement prevents multiple threads from executing a protected block
through the same gate at the same time. Use it to synchronize access to shared
mutable state:
lock gate {
updateSharedState()
}
The gate expression must have a reference type. Raven evaluates it exactly once
and acquires its monitor before entering the body. The monitor is always
released when control leaves the body, including through return or an
exception.
Choose a dedicated, privately held reference as the gate so unrelated code cannot acquire the same monitor accidentally.
On .NET, the statement has the same effect as storing the gate in a hidden
local, calling System.Threading.Monitor.Enter, executing the body in a try,
and calling System.Threading.Monitor.Exit from finally.