Maybe Treasure, Maybe Nothing: returning and unwrapping option types

In this lesson you'll learn to

  • βœ“Student can return ?t from a function and safely unwrap it with if-then binding and the ? operator.

Student can return ?t from a function and safely unwrap it with if-then binding and the ? operator.

πŸ“– Reference & full walkthrough: Maybe Treasure, Maybe Nothing: returning and unwrapping option types

πŸ” Builds on: north-jungle: verse-optionals fundamentals

🧩 Your capstone piece: FindWinner()?player β€” the safe race-winner lookup (companions: verse-optionals PASS, sug-handling-optional-types PASS, sug-safe-optional-value-access PASS)


What you'll learn

  • What an option (?type) value is and why functions return one
  • How to build option{X} on success and false on failure
  • How to unwrap an option safely with if (X := Maybe?):
  • How to react with real devices: read a button, show a HUD widget, and fire a trigger

How it works

An option holds either one value (option{X}) or nothing (false). You write its type with a leading ?, so ?int is "maybe an int". A function that returns an option is the honest way to answer a question that might have no answer.

The key rule: you can only unwrap an option inside a failure context. The idiom is if (Value := Maybe?): β€” the query operator ? succeeds and binds Value only when the option holds something; the else: branch runs when it's empty. There is no nil and no == nil check in Verse.

In our device, FindBuoyIndex searches a small array of "valid" buoy numbers and returns ?int β€” the index if found, or false if not. When a pirate interacts with the button we call it, then:

  • If we get a real index, we build a HUD message and show it with a real text_block widget via GetPlayerUI[] / AddWidget, then Trigger the cannon.
  • If not, we show a 'no match' widget and do nothing else.

Notice GetPlayerUI[...] uses [] because it's a fallible lookup, and array indexing ValidBuoys[i] is also fallible β€” both must live inside an if/for.

Let's build it

using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

# A cove device that returns an option (?int) and unwraps it to drive real devices + HUD.
option_cove_device := class(creative_device):

    @editable
    BuoyButton : button_device = button_device{}   # pirate interacts here

    @editable
    CannonTrigger : trigger_device = trigger_device{} # fires only on a real match

    # The buoy numbers we consider "ours". Search returns an option over these.
    ValidBuoys : []int = array{3, 7, 9}

    # RETURNS AN OPTION: option{index} if Target is a valid buoy, else false.
    FindBuoyIndex(Target : int) : ?int =
        for (I := 0..ValidBuoys.Length - 1):
            if (Buoy := ValidBuoys[I], Buoy = Target):
                return option{I}
        false  # nothing matched -> empty option

    OnBegin<override>()<suspends> : void =
        # React whenever a pirate presses the buoy button.
        BuoyButton.InteractedWithEvent.Subscribe(OnBuoyPressed)

    OnBuoyPressed(Agent : agent) : void =
        # Pretend the pressed buoy is number 7 (a valid one) for this demo.
        Maybe := FindBuoyIndex(7)
        # UNWRAP the option in a failure context:
        if (Index := Maybe?):
            ShowHUD(Agent, "Match! Buoy at slot {Index} β€” firing cannon.")
            CannonTrigger.Trigger(Agent)   # only fires when there is a real value
        else:
            ShowHUD(Agent, "No matching buoy for this code.")

    # Show a text widget on the interacting player's HUD (real player-UI calls).
    ShowHUD(Agent : agent, Text : string) : void =
        if (Player := player[Agent], UI := GetPlayerUI[Player]):
            Label := text_block{DefaultText := StringToMessage(Text)}
            UI.AddWidget(Label)

    # Wrap a string as a message so a text_block can display it.
    StringToMessage<localizes>(Value : string) : message = "{Value}"

Try it yourself

  1. Place a Button device and a Trigger device in your cove and assign them to BuoyButton and CannonTrigger.
  2. Build Verse, playtest, and press the button β€” you should see "Match! Buoy at slot 1" and the trigger fires.
  3. Change FindBuoyIndex(7) to FindBuoyIndex(4) (not in ValidBuoys). Now you get the "No matching buoy" HUD and the cannon stays silent.
  4. Add a fourth number to ValidBuoys and search for it to confirm the option{I} path still works.

Recap

  • An option (?type) holds one value (option{X}) or nothing (false).
  • Functions that might have no answer should return an option instead of crashing or guessing.
  • Unwrap with if (X := Maybe?): β€” the body runs only when a value is present; else: handles empty.
  • Fallible lookups like GetPlayerUI[], player[Agent], and Arr[i] must live inside a failure context.
  • We used the option to gate real behavior: show a HUD widget and fire a trigger only on a genuine match.
πŸ”’

Keep going β€” free

You've read the intro. The rest of this lesson is free for members. Sign in to continue and track your progress.

Sign in free to continue this lesson
Pass the quiz above to chart this quest in your Journal.

Sources

/guides/return-an-option
Source

Biloxi Studios original lesson

Guided course

Add this lesson to your free study plan.

🧭 The Keeper’s log

Quest complete? Chart your next heading from the πŸ¦‘ West Coves expedition.

β›΅ Take me there