Errors and try
Sec uses explicit, statically typed error handling. Failure contracts appear in function types, error types and source control flow rather than through hidden exceptions.
fn Read() Result[Data, IOError] {
let data := try ReadFile()
return Ok(data)
}
try is the language's specialized short-circuit form for fallible or
alternate-state operations.
It can propagate failure, recover from selected cases locally, or forward a fallible
operation directly from a return position.
try handles declared fallible or short-circuit
behavior. It is not an exception mechanism and it never catches panic.
The error Root Type
error is a compiler-known fundamental Sec type available without import:
error
It is the common root of Sec error types.
It is not:
- a general object base class;
- ordinary inheritance;
- an exception base class;
- a mandatory heap object;
- a fixed message/code structure;
- a permission for arbitrary runtime conversion between types.
The relation is specific to error assignability.
Error Assignability
For a concrete Sec error type MyError:
MyError -> MyError valid
MyError -> error valid implicit widening
error -> MyError no implicit conversion
ErrorA -> ErrorB no implicit conversion
Widening a concrete error to error preserves:
- the concrete error type;
- the active error variant;
- payload data;
- ownership state;
- destruction behavior.
Sec 0.1 does not define a general implicit narrowing from error to a
concrete error type.
Error Types Do Not Introduce General Inheritance
Declaring an error type creates only the error-specific relation:
concrete error type -> error
It does not create inheritance between arbitrary user-defined types.
Closed Enum Errors
A fieldless closed error family may be declared as an enum:
enum IOError error {
OpenError
ReadError
WriteError
NotFound
PermissionDenied
}
The final error marker makes values of the enum assignable to the root
error type.
An explicit underlying enum type may still be used:
enum ProtocolError uint16 error {
InvalidFrame = 1
UnsupportedVersion = 2
}
The enum otherwise follows ordinary closed nominal enum rules.
Payload-Bearing Union Errors
An error family that needs per-variant data uses a tagged union error:
type DetailedError union error {
OpenError {
Path: string
Code: int
}
ReadError {
Path: string
Offset: uint64
Code: int
}
}
The concrete error type decides which payload fields exist.
The root error type does not impose universal fields such as
Message, Id, Code or
Description.
Error Values May Own Data
Error payloads are ordinary Sec values and may contain owned or move-only resources when their containing declaration permits them.
Error values follow normal:
- ownership;
- copy/move rules;
- borrowing;
- destruction;
- discardability;
- lifetime rules.
Sec never inserts a hidden clone simply because a value is an error.
Fallible Contracts Are Explicit
Ordinary fallible functions use Result[T, E]:
fn Read() Result[Data, IOError] {
...
}
A precise concrete error type is preferred when the API has a closed known failure domain.
The root type is used when heterogeneous errors intentionally cross one API boundary:
fn RunPipeline() Result[Data, error] {
...
}
Result and Option carrier details are covered in the
previous chapter.
The try Model
try is a language-level short-circuit expression.
It provides:
- an implicit success path;
- optional local handling of alternate/failure states;
- implicit propagation of unhandled compatible alternate/failure states.
Conceptually it resembles a specialized partial match, but the compiler
is not required to lower it through a source-level match expression.
match remains the general explicit and exhaustive construct.
What try Accepts
try is not restricted to expressions whose surface type is
Result[T, E].
Its operand must be a language-defined fallible or short-circuit operation for which the compiler knows:
- the success type;
- the possible alternate/failure states;
- the propagation behavior of those states.
Sec 0.1 includes at least:
let data := try Read()
let item := try Find()
let sum := try left + right
let value := try values[index]
let percent := try Percent(raw)
let connection := try new Connection(address)
These categories include:
Result[T, E]expressions;Option[T]expressions;- language-defined fallible runtime checks;
- fallible arithmetic/conversions/constrained constructions;
- fallible property assignments;
- fallible lifecycle construction through
new.
An ordinary infallible value is not a valid try operand simply because
it could theoretically be wrapped in a carrier.
try with Result[T, E]
Ok(value) -> success value T
Err(error) -> error alternate
On success, the try expression evaluates to the success payload.
On error, a matching local handler may recover; otherwise the error propagates when compatible with the enclosing error channel.
try with Option[T]
Some(value) -> success value T
None -> absence alternate
None remains ordinary absence.
It does not become an error.
Language-Defined Fallible Operations
Some Sec operations are fallible without materializing an explicit source-level
Result value.
let value := try values[index]
let total := try left + right
let percentage := try Percent(raw)
The compiler knows the success type and possible failure types from the owning language rule.
Lowering may branch directly to success/failure control flow rather than constructing a temporary carrier.
One Protected Expression May Have Several Failure Sources
A protected expression can contain more than one fallible point:
let value := try values[index] + amount
The index operation and arithmetic operation may fail with different concrete error types.
Internally the compiler may track a heterogeneous failure set such as:
BoundsError
ArithmeticError
This internal set does not create:
- an anonymous source-language union;
- an inferred public error type;
- automatic user-union wrapping;
- automatic error variant selection.
Evaluation stops at the first failure according to normal source evaluation order.
Err(_) can handle a heterogeneous failure set because it does not need a
payload binding type.
A catch-all Err(errorValue) binding is valid only when all remaining
failure paths already share one compiler-resolved concrete or explicitly declared
common error channel, including a declared error channel.
The compiler does not infer error merely to make an otherwise
heterogeneous local binding possible.
Naked try Propagation
The simplest form is:
try expression
Success continues normally. Any unhandled alternate/failure state propagates only when the enclosing return channel is compatible.
Result Error Propagation
fn ReadData() Result[Data, IOError] {
let data := try ReadFile()
return Ok(data)
}
Every unhandled propagated error must be assignable to the declared enclosing error type.
Widening to the root error is valid:
fn Run() Result[Data, error] {
let data := try ReadFile()
return Ok(data)
}
The concrete error identity and payload remain intact through widening.
No hidden wrapper error is invented.
Option Absence Propagation
Naked try on an Option[T] may propagate None
only through an enclosing compatible Option[...] return channel:
fn Resolve() Option[Device] {
let device := try FindDevice()
return Some(device)
}
None stays absence.
No Implicit Cross-Channel Conversion
None -/> Err(...)
Err(error) -/> None
The compiler never invents a mapping between absence and failure.
When a program wants such a conversion, it states the mapping explicitly.
try Protects the Complete Following Expression
Canonical:
let total := try left + right * quantity
Conceptual grouping:
let total := try (left + (right * quantity))
Parentheses can narrow the protected region:
let total := left + (try right * quantity)
Natural boundaries include:
- statement completion;
- commas separating arguments or elements;
- closing parentheses, brackets or braces;
match/selectarrows;- the local try-handler block.
try does not change ordinary evaluation order.
The first encountered failure short-circuits the protected expression.
try Is a General Expression Form
The success value may appear wherever its success type is legal:
let value := try Read()
Process(try Read())
if try IsReady() {
Proceed()
}
let item := Container {
Value: try ReadValue()
}
let result := Calculate(try ReadLeft(), try ReadRight())
Assignment remains a statement in Sec 0.1.
try does not turn assignment into a value-producing expression.
This remains invalid:
if result = try Setup() {
Proceed()
}
Local try Handlers
A try expression may handle selected alternate/failure states locally.
Result/error example:
let config := try LoadConfig() {
Err(IOError.NotFound) => DefaultConfig()
}
Option example:
let device := try FindDevice() {
None => DefaultDevice()
}
The handler list describes only alternate/failure states. The success path stays implicit.
The obsolete nested wrapper form is invalid:
try Read() {
match {
Err(errorValue) => Handle(errorValue)
}
}
Write the handlers directly:
try Read() {
Err(errorValue) => Handle(errorValue)
}
Success Handlers Are Not Allowed in try
This is invalid for a Result:
try Read() {
Ok(value) => Use(value) // invalid
}
This is invalid for an Option:
try Find() {
Some(value) => Use(value) // invalid
}
Use match when both success and alternate states should be explicit.
Local Handlers Are Intentionally Partial
let value := try Read() {
Err(IOError.NotFound) => DefaultValue()
}
If Read() can produce another error, the unmatched error continues through
normal try propagation when compatible with the enclosing error channel.
try may handle only selected failure states
and propagate the rest. match handles the complete resolved subject exhaustively.
An explicit catch-all handles every remaining Result/error failure locally:
let value := try Read() {
Err(_) => DefaultValue()
}
For Option[T], handling None covers its only alternate state.
Err(_) Explicitly Acknowledges and Ignores the Error Payload
try Read() {
Err(_) => Recover()
}
This explicitly states that an error state is being handled while its payload is not needed.
It is conceptually similar to:
try Read() {
Err(errorValue) => {
discard errorValue
Recover()
}
}
Err(_) is legal only when discarding the matched payload is itself legal
under ordinary ownership and discardability rules.
This is deliberately different from a generic _ match arm that could
otherwise hide an unhandled Result error.
Handler Order Is Semantically Significant
Handlers are tested from top to bottom. The first matching handler wins.
try Read() {
Err(IOError.NotFound) => UseDefault()
Err(IOError.PermissionDenied) => RequestAccess()
Err(_) => Fallback()
}
A later handler that is provably covered by an earlier unguarded handler is a compile error:
try Read() {
Err(_) => Fallback()
Err(IOError.NotFound) => UseDefault() // unreachable
}
Handler Guards
try handlers use the same where spelling as
match:
try Read() {
Err(errorValue) where errorValue.Code == 404 => UseDefault()
Err(errorValue) => Handle(errorValue)
}
Rules:
- the pattern is tested first;
- the guard runs only after pattern success;
- the guard must produce
bool; - pattern bindings are visible inside the guard;
- a false guard continues to the next handler;
- a guarded handler does not cover the complete underlying pattern;
- the first matching pattern with a true guard wins.
Guard and handler code are outside the protected operation set of the surrounding
try.
If they are fallible, they need their own explicit try.
Ownership Is Committed Only After Guard Success
Handler bindings follow the same copy/move/borrow model as equivalent
match patterns.
For a prospective move-only by-value binding with a guard, ownership transfer is not committed merely because the pattern matched.
Commit occurs only after:
- the pattern matches;
- the guard succeeds, if present;
- the handler is selected.
A guard may inspect or borrow the prospective payload, but it must not consume it before selection when a later handler or propagation path may still need the value.
Recovery Values Must Match the Success Type
When try expression { ... } is used in value position, a locally handled
path that continues execution must produce a value assignable to the protected
operation's success type.
let config := try LoadConfig() {
Err(IOError.NotFound) => DefaultConfig()
}
If the success type is Config, DefaultConfig() must also
produce a compatible Config.
A handler that terminates control flow does not need a recovery value:
let config := try LoadConfig() {
Err(IOError.PermissionDenied) => {
return Err(AppError.ConfigurationDenied)
}
}
Handler Blocks May Produce Their Recovery Value
In a value-producing handler, the final expression of the handler block may provide the recovery value:
let config := try LoadConfig() {
Err(IOError.NotFound) => {
Log("Using default configuration")
DefaultConfig()
}
}
This is the contextual result position of a handler block. It does not make arbitrary Sec blocks general expression values.
void Success Needs No Recovery Value
When the protected operation has void success, a handled failure may
complete normally:
try ClearCache() {
Err(CacheError.AlreadyEmpty) => {
Log("Cache was already empty")
}
}
No artificial success payload is manufactured.
Handler Failures Are Outside the Protected Set
A handler does not recursively catch failures produced by its own recovery code.
let config := try LoadConfig() {
Err(ConfigError.NotFound) => try LoadDefaultConfig()
}
The outer try protects LoadConfig().
The inner try handles or propagates failures from
LoadDefaultConfig().
The same rule applies to fallible guard expressions.
Fallible Assignment Uses try
Naked propagation:
try vehicle.TopSpeed = requestedSpeed
Local handling:
try vehicle.TopSpeed = requestedSpeed {
Err(SpeedError.TooHigh) => {
Log("Requested speed was too high")
}
}
Rules:
- the assignment target must resolve to a fallible assignment path;
- success completes the assignment and produces no value;
- failure preserves destination state according to the setter/assignment transaction rule;
- unhandled compatible failure propagates;
- local handlers use ordinary partial-handler, guard and ordering rules;
Ok(...)handlers remain invalid;- a fallible assignment without
tryis invalid.
Assignment success is ordinary control flow, not a source-level synthetic
Ok(()).
Fallible Property Setters
A fallible setter declares its error type on the setter line:
property TopSpeed: Speed {
try set value SpeedError {
if value < MinimumSpeed {
return Err(SpeedError.TooLow)
}
self._speed = value
}
}
The setter error type must be error or a concrete Sec error type.
Setter completion rules are:
normal body completion -> success
return -> early success
return Err(errorValue) -> failure
return Ok() is invalid inside a try set body.
The setter is not modeled in source as an ordinary function returning
Result[void, E].
An interface declares the same fallible setter contract:
property Position: Point {
try set value PositionError
}
Property Getters Are Infallible in Sec 0.1
Sec 0.1 does not define:
try get ErrorType
If reading a property inherently requires a typed failure channel, use an ordinary fallible function or method API instead.
Fallible Initializers
A fallible initializer places the construction error type after its parameter list:
impl Connection {
init(address: Address) ConnectError {
if invalid {
return Err(ConnectError.InvalidAddress)
}
self.address = address
}
}
The trailing ConnectError is the construction error type, not the
success return type.
Normal successful completion produces the initialized instance.
A failed initializer produces no completed instance and follows the lifecycle rules for partially initialized state.
Construction uses ordinary try:
let connection := try new Connection(address)
return try expression
Sec permits direct forwarding from a fallible expression in Result-return position:
fn Load() Result[Config, IOError] {
return try ReadConfig()
}
For an enclosing Result[T, E]:
protected success S -> return Ok(value), when S is assignable to T
protected failure F -> propagate, when F is assignable to E
This is a special return-position forwarding rule.
It does not create a general implicit conversion from T to
Result[T, E].
Outside return try, ordinary success return remains explicit:
return Ok(value)
Sec 0.1 does not add an analogous implicit Some(...) wrapping rule for
Option returns.
try and match Serve Different Purposes
Use try when success should continue implicitly:
let value := try Read() {
Err(IOError.NotFound) => DefaultValue()
}
Use match when all subject states should be explicit:
match Read() {
Ok(value) => Use(value)
Err(_) => Fallback()
}
try may be partial and propagate unmatched failure.
match is exhaustive over the resolved subject.
Matching Result[T, error]
Widening to error preserves concrete error identity, so error-specific
patterns may narrow inside an explicit Err(...) branch:
match result {
Ok(value) => Use(value)
Err(IOError.NotFound) => UseDefault()
Err(errorValue) => Handle(errorValue)
}
This is an error-specific narrowing rule. It does not enable arbitrary runtime type patterns for unrelated Sec values.
Because error is an open domain, a match over
Result[T, error] needs a remaining error fallback such as:
Err(errorValue)
Err(_)
unless control-flow facts prove a narrower closed state.
A generic match catch-all _ must not silently hide an otherwise
unhandled Result error.
Use explicit Err(_) when the error state is intentionally acknowledged.
One-Branch Tests for Option
Canonical presence/absence tests include:
if Clear().Err() is not None {
HandleFailure()
}
The narrow positive binding convenience is:
if Clear().Err() is Some(errorValue) {
Handle(errorValue)
}
The binding exists only inside the true branch.
This is invalid:
if option is not Some(value) {
Use(value) // invalid
}
No value exists on the true path of the negative test.
Error Handling Preserves Ordinary Ownership Semantics
Error handling never suspends Sec's ownership rules.
The compiler tracks consumption caused by:
- by-value
matchandtrybindings; - consuming Result projections;
- explicit
<-moves; discard;- return/forwarding of owned values;
- ownership transfer into error payloads.
A value consumed on one path becomes unavailable according to the normal path-sensitive ownership merge rules.
Use-after-consume is a semantic error, not an optional lint.
Error Propagation Runs Normal Cleanup and defer
Propagation is a normal control-flow exit. It executes the same required deterministic cleanup as any other return path.
Propagation must preserve:
- lexical cleanup;
- active
deferexecution; - destruction of initialized locals;
- partial initialization state;
- borrow termination;
- moved/discarded state;
- lifecycle obligations.
try never bypasses cleanup.
A Result produced inside deferred code remains must-use and must itself be handled according to the defer/error/panic rules.
try Does Not Catch Panic
try converts only language-defined fallible/short-circuit behavior of
its protected expression.
let result := try Calculate() + value
If Calculate() may independently panic, that panic effect remains.
try does not catch, unwind or resume arbitrary panic.
Error handling and panic are separate mechanisms. Panic is covered in the next chapter.
Error Handling Requires No General Exception Runtime
Sec error handling can lower to ordinary control flow, tagged carriers, direct branches or target-specific helpers.
The implementation does not require a general exception runtime.
The backend may optimize away temporary Result/Option representations when observable source semantics remain identical.
Lowering must preserve:
- evaluation order;
- success type;
- concrete error identity;
- handler source order;
- guard behavior;
- partial-handler propagation;
- ownership commit points;
- cleanup/destruction edges;
- remaining panic effects.
Diagnostics
Error diagnostics should explain the programmer-visible cause and consequence rather than requiring compiler-theory terminology.
Incompatible propagation
cannot propagate `ParseError` from this `try`
the enclosing function returns:
Result[Config, IOError]
`ParseError` is not assignable to `IOError`
help: handle the ParseError locally
help: map it to an IOError
help: widen the enclosing error channel when that matches the API contract
Missing try on fallible assignment
assignment to `vehicle.TopSpeed` may fail
the setter declares:
SpeedError
help: write:
try vehicle.TopSpeed = requestedSpeed
help: add a local try handler when selected errors should recover here
Success handler in try
`Ok(...)` is not valid in a try handler
the success path of `try` is implicit
help: use `match` when success and failure should both be written explicitly
Unreachable handler
this try handler can never be selected
an earlier unguarded handler already covers the same failure:
Err(_) => Fallback()
help: move the specific handler before the catch-all
Recovery type mismatch
try handler returns `string`, but the protected success type is `Config`
help: return a Config-compatible recovery value
help: leave control flow from the handler instead
Heterogeneous catch-all binding
cannot bind all remaining failures as one named error value
the protected expression has multiple failure types with no declared common channel
help: use `Err(_)`
help: split the expression
help: map the failures explicitly to a common error type
Diagnostics should identify the source operation that consumed, propagated, moved or discarded a value whenever that fact causes a later error.
Language-Server and Tooling Behavior
Hover and analysis should expose:
- the success type of a
tryexpression; - the failure/absence states that may propagate;
- concrete-to-
errorwidening; - which local handlers cover which states;
- which states remain unhandled;
- handler binding type and ownership mode;
- fallible property setter error type;
- fallible initializer error type;
- source locations of ownership consumption;
- the distinction between Result and Option pattern families.
Completion should suggest only alternate/failure handlers appropriate to the resolved protected operation.
The formatter preserves canonical spellings:
try expression
try expression {
Err(pattern) where condition => recovery
}
try assignment
return try expression
Tooling must not reintroduce obsolete nested match { ... } syntax inside
a try handler block.
Best Practices
- Use concrete error types when an API has a clear closed failure domain.
- Use
Result[T, error]only when heterogeneous errors intentionally cross the API boundary. - Use naked
trywhen the current function cannot add useful local recovery. - Use local
tryhandlers when a small number of failure cases have obvious local recovery. - Use
matchwhen success and failure should both be explicit. - Put specific handlers before catch-all
Err(_)handlers. - Use
Err(_)when the error state is intentionally handled but its payload is not needed. - Keep recovery code simple; use a nested
trywhen recovery itself is fallible. - Use
whereguards only when pattern identity alone cannot express the recovery condition. - Remember that guarded move-only bindings do not commit ownership until the handler is actually selected.
- Use
return try expressionfor direct Result-return forwarding instead of manually unpacking and rebuilding the same success/failure channel. - Do not expect
return tryto create a general implicit Result conversion elsewhere. - Use
tryon fallible property assignment; never ignore setter failure. - Use a method instead of a property getter when reads can fail in Sec 0.1.
- Do not use
tryas a panic-catching mechanism. - Let deterministic cleanup and
deferrun normally on propagated failure paths.
Summary
- Sec uses explicit statically typed error handling without hidden exceptions.
erroris a compiler-known root type available without import.- The error-root relation is error-specific and does not introduce general inheritance.
- A concrete error implicitly widens to
error. errordoes not implicitly narrow to a concrete error type.- One concrete error type does not implicitly convert to another.
- Error widening preserves concrete type, variant, payload, ownership and destruction behavior.
- Closed fieldless error families may be declared as
enum Name error. - An error enum may also have an explicit ordinary enum underlying type before the final
errormarker. - Payload-bearing error families use
type Name union error. - The root
errortype does not impose universal Message/Code/Description fields. - Error payloads may own ordinary and move-only Sec values.
- Error values obey ordinary ownership, copy/move, borrowing, lifetime, destruction and discardability rules.
- Fallible functions normally expose
Result[T, E]explicitly. tryis a first-class short-circuit expression form.- The success path of
tryis implicit. - Unhandled compatible failure/alternate states propagate.
tryaccepts Result, Option and compiler-defined fallible language operations.- Fallible operations need not materialize a temporary Result carrier.
- For Result,
Ok(value)is success andErr(error)is the alternate failure state. - For Option,
Some(value)is success andNoneis the alternate absence state. Nonenever becomes an error implicitly.- A protected expression may contain multiple fallible points with different concrete failure types.
- The compiler may track a heterogeneous internal failure set without creating an anonymous source-language error union.
- Sequential failure is not aggregated; ordinary evaluation stops at the first encountered failure.
Err(_)can handle heterogeneous failures without requiring one payload binding type.- A named catch-all error binding requires a single compiler-resolved common error channel.
- The compiler does not infer
errorsolely to make a heterogeneous local binding possible. - Naked
try expressionpropagates unhandled compatible failure/absence. - Result failures propagate only when assignable to the enclosing Result error channel.
- Concrete errors may propagate through an enclosing
errorchannel by normal widening. - Option absence propagates only through a compatible Option return channel.
- Sec never invents implicit Result-to-Option or Option-to-Result conversion.
tryprotects the complete following expression until its natural grammar boundary.- Parentheses may narrow the protected expression.
trypreserves ordinary evaluation order.- The first failure encountered short-circuits the protected expression.
trymay appear anywhere its success value is legal as an expression.trydoes not turn assignment into an expression value.- A local handler block contains alternate/failure handlers only.
Ok(...)is invalid in a Result try handler.Some(...)is invalid in an Option try handler.- Use
matchwhen success and alternate states must both be explicit. - The obsolete nested
match { ... }wrapper inside a try handler block is invalid. - Try handlers are intentionally partial.
- Unmatched compatible failures continue normal propagation.
Err(_)explicitly acknowledges and ignores the matched error payload.Err(_)is legal only when discarding the payload is legal.- Handler order is top-to-bottom and the first successful match wins.
- A provably unreachable later handler is a compile-time error.
- Try-handler guards use
where. - Pattern bindings are visible inside their guard.
- A false guard continues to later handlers or propagation.
- Guard and recovery-code failures are outside the surrounding try's protected set.
- Fallible guard/recovery code uses its own explicit
try. - Prospective move-only handler bindings commit ownership only after pattern match, guard success and handler selection.
- A continuing recovery path in value position must produce a value assignable to the protected success type.
- A terminating recovery path needs no fallback value.
- A handler block may use its final expression as the recovery value in contextual result position.
- That rule does not make arbitrary Sec blocks general expression values.
- For
voidsuccess, a handled failure may complete normally without manufacturing a value. - Fallible assignment uses
try assignment. - A fallible assignment without
tryis invalid. - Successful fallible assignment produces no source-level Result value.
- A fallible property setter uses
try set value ErrorType. - Normal completion of a try setter is success.
- Bare
returnin a try setter is early success. return Err(errorValue)is setter failure.return Ok()is invalid inside a try setter.- Property getters are infallible in Sec 0.1.
- A fallible read should use an ordinary fallible method/function rather than a property getter.
- A fallible initializer declares its error type after the initializer parameter list.
- The initializer's trailing error type is not a success return type.
- Successful initializer completion produces the initialized instance.
- Failed initialization produces no completed instance and follows partial-initialization cleanup rules.
- Fallible construction uses
try new Type(...). return try expressionis a special Result-return forwarding rule.- In
return try, compatible success forwards asOk(value)and compatible failure propagates. return trydoes not introduce a general implicitT -> Result[T,E]conversion.- Ordinary successful Result returns outside that special form remain explicit with
Ok(value). - Sec 0.1 defines no analogous implicit
Some(...)wrapping throughreturn try. tryis partial-success-oriented sugar;matchis explicit exhaustive matching.- Concrete error identity survives widening into
Result[T, error]. - Open
errormatches may narrow using concrete error-specific patterns inside explicitErr(...). - Error-specific narrowing does not introduce general runtime type patterns.
- A match over the open
errordomain needs an explicit remaining Err fallback unless proven narrower. - A generic
_match arm must not silently hide an otherwise unhandled Result error. - Use explicit
Err(_)when intentionally acknowledging an error while ignoring its payload. - Positive
is Some(binding)is the Sec 0.1 one-branch Option payload-binding convenience. - Bindings from
is Some(binding)exist only inside the true branch. - Negative
is not Some(binding)cannot provide that binding on the true path. - Error handling never disables ordinary ownership semantics.
- Use-after-consume after try/match/projection/move/discard remains a compile-time error.
- Propagation is a normal control-flow exit and executes deterministic cleanup.
- Active
deferblocks run on propagated failure paths. trydoes not bypass destruction, borrow termination or partial-initialization cleanup.trydoes not catch, unwind or resume panic.- Error handling and panic are separate Sec mechanisms.
- Sec error handling requires no general exception runtime.
- Backend lowering may optimize carriers/control flow only when observable source semantics remain unchanged.