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.

Core rule: 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/select arrows;
  • 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.

Difference: 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:

  1. the pattern matches;
  2. the guard succeeds, if present;
  3. 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 try is 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 match and try bindings;
  • 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 defer execution;
  • 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 try expression;
  • the failure/absence states that may propagate;
  • concrete-to-error widening;
  • 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 try when the current function cannot add useful local recovery.
  • Use local try handlers when a small number of failure cases have obvious local recovery.
  • Use match when 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 try when recovery itself is fallible.
  • Use where guards 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 expression for direct Result-return forwarding instead of manually unpacking and rebuilding the same success/failure channel.
  • Do not expect return try to create a general implicit Result conversion elsewhere.
  • Use try on 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 try as a panic-catching mechanism.
  • Let deterministic cleanup and defer run normally on propagated failure paths.

Summary

  • Sec uses explicit statically typed error handling without hidden exceptions.
  • error is 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.
  • error does 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 error marker.
  • Payload-bearing error families use type Name union error.
  • The root error type 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.
  • try is a first-class short-circuit expression form.
  • The success path of try is implicit.
  • Unhandled compatible failure/alternate states propagate.
  • try accepts Result, Option and compiler-defined fallible language operations.
  • Fallible operations need not materialize a temporary Result carrier.
  • For Result, Ok(value) is success and Err(error) is the alternate failure state.
  • For Option, Some(value) is success and None is the alternate absence state.
  • None never 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 error solely to make a heterogeneous local binding possible.
  • Naked try expression propagates unhandled compatible failure/absence.
  • Result failures propagate only when assignable to the enclosing Result error channel.
  • Concrete errors may propagate through an enclosing error channel 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.
  • try protects the complete following expression until its natural grammar boundary.
  • Parentheses may narrow the protected expression.
  • try preserves ordinary evaluation order.
  • The first failure encountered short-circuits the protected expression.
  • try may appear anywhere its success value is legal as an expression.
  • try does 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 match when 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 void success, a handled failure may complete normally without manufacturing a value.
  • Fallible assignment uses try assignment.
  • A fallible assignment without try is 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 return in 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 expression is a special Result-return forwarding rule.
  • In return try, compatible success forwards as Ok(value) and compatible failure propagates.
  • return try does not introduce a general implicit T -> 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 through return try.
  • try is partial-success-oriented sugar; match is explicit exhaustive matching.
  • Concrete error identity survives widening into Result[T, error].
  • Open error matches may narrow using concrete error-specific patterns inside explicit Err(...).
  • Error-specific narrowing does not introduce general runtime type patterns.
  • A match over the open error domain 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 defer blocks run on propagated failure paths.
  • try does not bypass destruction, borrow termination or partial-initialization cleanup.
  • try does 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.