Skip to content

Add ergonomic int_or(value, fallback) helper for Result-returning int() #128

Description

@larimonious

Summary

int(x) correctly returns Result<Int, String> now, but common app code needs an ergonomic “parse with fallback” helper so developers do not have to write the same small wrapper in every app.

Suggestion: add a standard helper such as:

int_or(value, fallback) -> Int

or possibly an overloaded/convenience form:

int(value, fallback) -> Int

Motivation

Issue #51 made int() return Result instead of throwing on invalid input. That was the right semantic move: parsing can fail, and app code should not silently pretend bad external data is valid.

The practical friction showed up while upgrading the Avant Garde app to ntnt 0.4.10. Existing code had patterns like:

let status = int(data["status"] ?? 0)
if status >= 300 {
    ...
}

Under the current semantics, status is a Result, so this correctly fails as:

Type error: Cannot apply '>=' to Result and Int

The fix was to add local wrappers like:

fn safe_int(value: Any, fallback: Int) -> Int {
    let parsed = int(value) otherwise {
        return fallback
    }
    return parsed
}

and then use:

let status = safe_int(data["status"] ?? 0, 0)

That is correct, but it is also boilerplate for a very common boundary case: query params, env vars, API payloads, JSON feeds, dates/times, HTTP status fields, cache metadata, etc.

Proposed API

Preferred shape:

int_or(value: Any, fallback: Int) -> Int

Behavior:

  • If int(value) succeeds, return the parsed integer.
  • If int(value) returns Err(...), return fallback.
  • Should work for the same accepted inputs as int: Int, Float, String, Bool.
  • Should not throw for ordinary parse/conversion failure.

Examples:

int_or("42", 0)      // 42
int_or("", 0)        // 0
int_or("nope", -1)   // -1
int_or(None, 0)      // 0

Alternatives

Keep requiring otherwise

let n = int(value) otherwise { return 0 }

This is semantically fine, but noisy when the desired behavior is local fallback, not route/function early return. It also encourages each app to create its own safe_int helper.

Overload int(value, fallback)

This may be more discoverable, but it changes the arity/meaning of int and could blur the clean “int() returns Result” rule. I mildly prefer int_or because it keeps the failure-handling choice explicit.

Add a generic unwrap_or(result, fallback)

Useful more broadly, but still leaves parse-with-fallback less obvious for the highest-frequency case. This may be complementary rather than a replacement.

Why this is still compatible with #51

This does not argue for reverting int() to throwing or returning a bare integer. int() returning Result<Int, String> is good. The request is for a companion convenience helper for the common, deliberate fallback path.

Current model is semantically honest; this would make the safe path ergonomic enough that app code does not grow little safe_int mushrooms everywhere. Which is very on-brand for web apps, but not ideal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions