ddonche/goblin-lang
0.46.24
1
0
example documentation
[[guarded-destructuring]]

Guarded Destructuring


In Goblin, you can destructure values into bindings while declaring:

  • required fields (<req>)
  • default values (:)
  • fallback behavior (=>)

This is called Guarded Destructuring.

It ensures that:

  • Missing values are always handled
  • Required values are always enforced
  • Defaults are always applied when provided
  • Failures are always resolved explicitly

There are no unhandled states.


Basic Shape

a<req>, b:"x", c | expr => fallback
a<req>, b:"x", c | expr => fallback


What it does

  1. Evaluates expr

  2. Destructures positionally into bindings

  3. Applies defaults:

    • Explicit defaults (b:"x")
    • Implicit fallback for unmarked bindings → ""
  4. Checks required bindings (<req>)

  5. If any required binding is nix:

    • The entire expression resolves to fallback

Example

filename<req>, size:"full", align:"center", caption | :split(body, "|") => "Invalid image syntax"
filename<req>, size:"full", align:"center", caption | :split(body, "|") => "Invalid image syntax"

Behavior

Case Result
Valid input Values are bound normally
Missing optional values Defaults are applied
Missing filename Fallback is used

Equivalent Expansion

parts | :split(body, "|")

filename | parts[0]
size     | parts[1] ?? "full"
align    | parts[2] ?? "center"
caption  | parts[3] ?? ""

if filename.nix?
    return "Invalid image syntax"
xx
parts | :split(body, "|")

filename | parts[0]
size     | parts[1] ?? "full"
align    | parts[2] ?? "center"
caption  | parts[3] ?? ""

if filename.nix?
    return "Invalid image syntax"
xx


Binding Rules

Required (<req>)

filename<req>
filename<req>

  • Must not be nix
  • If nix → triggers fallback

Default (:)

size:"full"
size:"full"

  • Used if value is nix
  • Overrides implicit empty fallback

Unmarked Binding

caption
caption

If nix, becomes:

""
""

This is the implicit default.


Fallback (=>)

The => clause defines what happens when required bindings fail.

=> "<div>Bad input</div>"
=> "<div>Bad input</div>"

This can be:

  • A value (used in output)
  • An action (:say, logging, etc.)
  • Any valid expression

Sheriff Rendering Example

filename<req>, size:"full", align:"center", caption | :split(body, "|") => """
<div class="sheriff-render-error">
  Image cannot be processed because of missing required fields
</div>
"""
filename<req>, size:"full", align:"center", caption | :split(body, "|") => """
<div class="sheriff-render-error">
  Image cannot be processed because of missing required fields
</div>
"""

If parsing fails, this HTML appears directly in the page.


Developer Feedback Example

x<req>, y<req> | coords => :say("You have to give all your numbers a value")
x<req>, y<req> | coords => :say("You have to give all your numbers a value")

  • No crash
  • No exception
  • Controlled failure behavior

Multiple Required Fields

provider<req>, vid<req>, size:"full" | :split(body, "|") => "Invalid video"
provider<req>, vid<req>, size:"full" | :split(body, "|") => "Invalid video"

If any required binding is nix, fallback is used.


Provocation (Advanced)

Guarded destructuring ensures shape correctness.

If you need stricter guarantees (type, range, etc.), use provoke:

x<req>, y<req> | coords => "Bad input"

:provoke(x > 0)
:provoke(y > 0)
x<req>, y<req> | coords => "Bad input"

:provoke(x > 0)
:provoke(y > 0)

Destructuring handles presence.

provoke handles correctness.


Formatting Notes

Inline (preferred)

a<req>, b:"x", c | expr => fallback
a<req>, b:"x", c | expr => fallback

Tight form

a<req>,b:"x",c|expr=>fallback
a<req>,b:"x",c|expr=>fallback

Multiline fallback

a<req>, b | expr => """
Error: invalid input
"""
a<req>, b | expr => """
Error: invalid input
"""


How it differs

Feature Behavior
Destructuring Assigns positional values
<req> Enforces required bindings
: Provides explicit defaults
Unmarked Defaults to "" if nix
=> Defines explicit failure resolution

Why this exists

Goblin frequently works with structured text and dynamic output.

These require:

  • strict shape enforcement
  • safe defaults
  • visible failures
  • no silent breakage

Guarded Destructuring guarantees all of this in one expression.