Verse Wiki — the Verse handbook for Blueprint authors
Extension · EXTRA

sync Returns a Tuple: Multi-Value Returns in the Concurrent World

tuple's Lesson 18 debut was "one function spitting out several values," but its most beautiful entrance waits for the concurrency chapter: the concurrency instruction sync sets several jobs running at once, waits for all of them to finish, then hands their results back packed into one tuple, in the order you wrote them. This page is the early spoiler for that team-up.

1. sync: The Bus Leaves Only When Everyone's Aboard

A later concurrency chapter will formally introduce Verse's set of "do several things at once" instructions: spawn, race, sync, branch… For now, meet just one of them: sync. Its rule fits in a sentence — the jobs in its block start at the same time, and sync waits until every one of them is done before moving on. Like a two-player dungeon: each player grinds their own quest, and the results screen won't pop until both have cleared. (In Blueprint terms, imagine lighting up several execution wires at once; sync is the merge point that "only lets things pass once everyone has arrived.")

Now the question: the two jobs each have their own result — one might produce some text (a string), the other an integer (an int). As one single value, what should sync "hand back"? Fixed count (how many jobs there are is written in stone at Compile time), possibly different types, matched one-to-one by position… read those three conditions out loud and you'll recognize the exact portrait of tuple from Lesson 18's selection table. Correct: sync's result is a tuple, and the Epic developer community even has a dedicated tutorial about it, "The Tuple Result of Sync in Verse."

2. Packed in Written Order, Not Finishing Order

Here's a minimal two-runner example. RunLap is an async function that "waits a while" (marked <suspends>, with a Sleep inside — the equivalent of the little-clock Delay node in Blueprints); when the lap is done, it hands over the runner's name as its result:

relay_device.verse
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }

relay_device := class(creative_device):

    RunLap(Name:string, Seconds:float)<suspends>:string =
        Sleep(Seconds)
        Print("{Name} crossed the finish line")
        Name

    OnBegin<override>()<suspends>:void =
        # sync: two lanes start together; wait until both runners finish
        Results := sync:
            RunLap("Red", 2.0)
            RunLap("Blue", 3.0)
        # Results are packed into a tuple in written order: (Red's result, Blue's result)
        First := Results(0)
        Second := Results(1)
        Print("Scoreboard: {First} and {Second} both finished")

Reading the code: RunLap is an execution line that "Delays a few seconds, prints who crossed the line, then hands over the name." Inside OnBegin (game start, the equivalent of Event BeginPlay), the two indented lines under sync: — Red and Blue — light up at the same time and each runs its own race; sync is the merge point that "only lets through once both reach the finish." Their results get packed into the two-slot parcel Results; Results(0) takes the first slot (Red), Results(1) takes the second (Blue), and the scoreboard prints at the end.

The key detail is the word "order": Red finishes in 2 seconds, Blue in 3 — the finish times differ, but Results(0) is always the result of the line written first in your code (Red's line), and Results(1) is always the second. Packing order follows the order of the code text and has nothing to do with who finishes first — which nails down the result's types and meaning completely at Compile time. You can take values by slot number with confidence, no "slot 0 is Red today, Blue tomorrow" jump scares.

A recap against Lesson 18: tuple slot numbers must be hard-coded fixed numbers, each slot's type is determined on its own, and the slot count is fixed for good — and put up against sync, every one of those fits perfectly. However many job lines you write, that's how many result slots you get; each line's result type is known at Compile time, so each slot's type is known too; Results(0) takes the value with the never-misses parentheses, and the fruits of a round of concurrent teamwork land safely in your pocket. One aside: sync's sibling race takes the other road: the jobs race, and only the first one to finish keeps its result — the rest are eliminated on the spot. One wants "everyone across the line, packed into one tuple"; the other only wants "that one value from first place." Two ways to play concurrency, two result shapes — a comparison saved for the concurrency chapter.

In the example above, Red finishes in 2 seconds and Blue in 3. Whose result does Results(0) hold?

Sources & Further Reading

Compiled from an Epic developer community tutorial; for the fuller story of sync, defer to the official docs and this site's concurrency chapter: