# Returning large tuples vs records

**URL:** <https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756>\
**Category:** Learning\
**Tags:** performance\
**Created:** [June 4, 2025, 6:23am UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756 "2025-06-04T06:23:27Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![bluddy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/bluddy/32/104_2.png) [@bluddy](https://discuss.ocaml.org/u/bluddy)\
**Post date:** [June 4, 2025, 6:23am UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756/1 "2025-06-04T06:23:27Z")

</div>

In my [Railroad Tycoon implementation](https://github.com/bluddy/rails), I have a function call tree that’s [quite heavy](https://github.com/bluddy/rails/blob/733648b8927765b6fe8bc8b85ff16f80d5ca732d/src/rails_lib/backend/backend_low.ml#L519): I loop over every train, updating each one (position is updated mutably for performance), and some trains will be entering important decision points or stations, so if I want to keep things functional (and I do), I need to return a whole bunch of data structures, including stations, trains, player\_info etc. This requires returning large tuples of data structures from many execution paths, which gets somewhat icky, and presents scalability issues. From the compiler’s perspective, is there an advantage to returning these tuples vs returning one record that contains these items, i.e. can ocaml optimize this in any way? Since this loop is called very often, I would prefer for it to be performant. Also, how does flambda treat this matter?

---

<div class="post-metadata">

**Author:** ![vrotaru](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/vrotaru/32/39_2.png) [@vrotaru](https://discuss.ocaml.org/u/vrotaru)\
**Post date:** [June 4, 2025, 6:44am UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756/2 "2025-06-04T06:44:03Z")

</div>

To my understanding at runtime you cannot tell between tuples and records. It is all contiguous region of memory with the block tag.

That’s what I get from playing some time ago with C FFI bindinds. This is a good read on this topic - [Representation of OCaml data types](https://ocaml.org/manual/5.3/intfc.html#s%3Ac-ocaml-datatype-repr)

---

<div class="post-metadata">

**Author:** ![vrotaru](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/vrotaru/32/39_2.png) [@vrotaru](https://discuss.ocaml.org/u/vrotaru)\
**Post date:** [June 4, 2025, 6:49am UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756/3 "2025-06-04T06:49:29Z")

</div>

You can try this to convince yourself

```OCaml
type a = int * int;;
type b = { x: int; y : int };;
external conv : a -> b = "%identity";;

let p = conv (2, 2);;

let _ = Printf.printf "{ x = %d; y = %d }\n" p.x p.y;;

```

---

<div class="post-metadata">

**Author:** ![vlaviron](https://avatars.discourse-cdn.com/v4/letter/v/ec9cab/32.png) [@vlaviron](https://discuss.ocaml.org/u/vlaviron)\
**Post date:** [June 4, 2025, 9:09am UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756/4 "2025-06-04T09:09:17Z")

</div>

> [@bluddy](#):
>
> Also, how does flambda treat this matter?

Flambda can remove local tuple or record allocations, but is stuck at function boundaries. You can use inlining to remove a few such boundaries, but you will probably not manage to remove all allocations with that.

On the other hand, there are a few promising things on the Jane Street fork:

- An `[@unboxable]` attribute on functions allows Flambda2 to automatically split your functions into a wrapper that takes or returns allocated values, and the main body taking individual parameters and returning multiple results. The wrapper is then inlined whenever possible, removing most of the allocations.
- Unboxed tuple and record types are coming (maybe they’re already there actually, I’m not sure). This allows you to return multiple values without allocating memory, without relying on optimisations. This would make your code incompatible with upstream OCaml though.

---

<div class="post-metadata">

**Author:** ![Zeta](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/zeta/32/6003_2.png) [@Zeta](https://discuss.ocaml.org/u/Zeta)\
**Post date:** [June 4, 2025, 2:37pm UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756/5 "2025-06-04T14:37:49Z")

</div>

Also labeled tuples are on their way: [First alpha release of OCaml 5.4.0](https://discuss.ocaml.org/t/first-alpha-release-of-ocaml-5-4-0/16722)!

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [June 4, 2025, 2:51pm UTC](https://discuss.ocaml.org/t/returning-large-tuples-vs-records/16756/6 "2025-06-04T14:51:59Z")

</div>

> [@bluddy](#):
>
> Since this loop is called very often, I would prefer for it to be performant.

Orthogonal to your questions, but have you actually benchmarked your code to gauge whether it needs to be more “performant”?

Cheers,  
Nicolas
