Expressions, contracts and patterns
Look up evaluation, scoped results, successful-exit checks and branch-local values. The linked specification rules are authoritative; the guide teaches these constructs through programs.
Operators, conditionals and assignment
| Form | Behavior | Rules |
|---|---|---|
a / b |
Fractional division; integer operands promote to Double before calculation | CS-ARITH-001 |
a div b |
Quotient truncated toward zero; fractional/compatible mixed inputs produce Long via CLR quotient conversion | CS-ARITH-002/006 |
a mod b |
.NET-like remainder, not Euclidean modulo | CS-ARITH-002 |
not age >= 18 |
Negates the comparison | CS-EXPR-004 |
age >= 18 and <= 65 |
Reuses the once-evaluated subject with short-circuiting | CS-EXPR-005 |
if(c, a, b) |
Evaluates only the selected result | CS-EXPR-006 |
if(c, a) / ifnot(c, b) |
Returns nothing when its branch is unselected |
CS-EXPR-006–CS-EXPR-007 |
value ?? fallback |
Lazy fallback only on actual absence | CS-EXPR-008 |
value ?? throw |
Check at expression execution only; no persistent assignment policy. Direct parameter uses ArgumentNullException, other expressions NullReferenceException | CS-EXPR-009 |
target ??= expression |
Lazy null fill; once-only target evaluation; writable target required | CS-ASSIGN-001–CS-ASSIGN-002 |
a = b = Load() |
One final RHS evaluation; rightmost local assigned first | CS-ASSIGN-003 |
checked(...) / unchecked(...) |
Ordinary C# overflow context for applicable expressions | CS-OVERFLOW-001–CS-OVERFLOW-003 |
Block overflow forms use matching end checked / end unchecked. A context does not suppress unrelated exceptions or change arithmetic inside imported methods. mod= is supported; div= is not inferred from the existence of div.
Operands execute once in source order; grouping is a separate concern. Unselected conditional/fallback operands do not execute. Default substitution applies locally to supported authored arithmetic, preserving stored absence and imported operator contracts. The old persistent ?? nothing policy is superseded.
See chapter 6 for diagnostics and reference lowerings, and appendix B for confirmed grouping relationships. Use parentheses when combining unfamiliar operators. Imported operators retain their declared CLR behavior.
Expression select and take
let fee = select customer.Type
case .Vip
take 0
else
take 20
end select
First matching case wins, without fall-through. Every normally completing selected path has a final take; an exceptional path needs no manufactured value. An else is required unless selection is provably complete. Results need a common/contextual type. return still exits the action. Missing cases do not synthesize nothing or default.
CS-SELECT-001–CS-SELECT-006, invalid paths and reference switch lowering: chapter 7. take is limited to approved supporting scopes; it does not make arbitrary blocks expressions.
require, ensure and old_value_of
| Construct | Evaluation | Failure/constraint |
|---|---|---|
require condition |
Immediately when executed | Fail-fast, ordinary .NET exception |
ensure condition |
On normal completion, after required finally blocks | Failure prevents successful return |
result |
Captured return value | No repeated return-expression evaluation |
old_value_of(source) |
Capture before body/require; constructors first complete generated initialization | Once per eligible source in first-written-occurrence order; captured outer locals allowed, body locals/calls/arithmetic excluded |
Default failures: absent required action parameter → ArgumentNullException with parameter name; attributable parameter constraint → ArgumentException/appropriate subclass; state or unclear attribution → InvalidOperationException; every ensure failure → InvalidOperationException.
Exceptional exits skip postconditions. Do not lower ensure into finally. Conditions must not be reevaluated for error messages, which identify source expressions without including runtime values.
CS-CONTRACT-001–CS-CONTRACT-010 and the synchronous C# example: chapter 12. Use otherwise to supply a message or exception expression. It does not introduce a control-flow branch.
Pattern and regex captures
is like uses wildcards: * means zero or more, ? exactly one. Sequence patterns require suitable ordered, indexable targets and permit at most one variable-length wildcard per nesting level. Exact = does not interpret wildcard syntax.
if fileName is like "report-{{let name = *}}.csv" then
Print(name)
end if
Regex uses ordinary .NET named groups, not wildcard capture syntax:
| Known regex group | Promoted local / value |
|---|---|
| Non-repeat-capable, participating | String; may be empty |
| Non-repeat-capable, nonparticipating | nothing |
| Repeat-capable | List of all captured strings, in capture order |
| Repeat-capable with zero captures | Empty list |
| Name outside DirectSharp ASCII identifier grammar | No promoted local; regex remains valid |
| Dynamic pattern | No invented locals |
Captures exist in the successful branch. Keyword names use @; case-colliding promotable names are compile-time errors. Repeatability depends on regex structure, not a particular match. Ordinary matching is case-insensitive; is match_case_sensitive is explicit.
CS-PATTERN-001–CS-PATTERN-005 and CS-REGEX-001–CS-REGEX-006: chapter 16, including capture typing and diagnostics.
Lazy values
let customer = lazy LoadCustomer(id)
The entire initializer waits for first ordinary value use; captured mutable values are read then. One initializer executes even under concurrent first reads. Successful values, including nothing, and exceptions are cached. There is no retry. The source binding is assign-once and transparently has the computed value's type.
| Predicate | True when | Forces initialization? |
|---|---|---|
is initialized |
Successfully completed, including nothing |
No |
is not initialized |
Not started, working or faulted | No |
is working |
Initializer executing | No |
is faulted |
Cached initialization failure | No |
The optional report index shows a complete ordinary class example, force-time captures, resource lifetime and a C# state/publication pattern.
Recursive forcing fails clearly. Safe publication does not make the computed object's mutation thread-safe. CS-LAZY-001–CS-LAZY-008 and the limits of System.Lazy lowering: chapter 18.