# In this function, we'll call compute_square
@inngest_client.create_function(
    fn_id="main-function",
    trigger=inngest.TriggerEvent(event="main/event")
)
async def main_function(ctx: inngest.Context):
    square = await ctx.step.invoke(
        "compute-square-value",
        function=compute_square,
        data={"number": 4}  # input data is typed, requiring input if it's needed
    )

    return f"Square of 4 is {square['result']}."  # square.result is typed as number
```

In the above example, our `mainFunction` calls `compute_square` to retrieve the resulting value. `compute_square` can now be called from here or any other process connected to Inngest.

</GuideSection>

</GuideSelector>

## Creating a distributed system

You can invoke Inngest functions written in any language, hosted on different clouds.  For example, a TypeScript function on Vercel can invoke a Python function hosted in AWS.

By starting to define these blocks of functionality, you're creating a smart, distributed system with all of the benefits of event-driven architecture and without any of the hassle.

## Similar pattern: Fan-Out

A similar pattern to invoking functions directly is that of fan-out - [check out the guide here](/docs/guides/fan-out-jobs). Here are some key differences:

- Fan-out will trigger multiple functions simultaneously, whereas invocation will only trigger one
- Unlike invocation, fan-out will not receive the result of the invoked function
- Choose fan-out for parallel processing of independent tasks and invocation for coordinated, interdependent functions