I’m the author of the blog-post cited by @c-cube … and the approach taken there might be different from what you’re after.
The next blogpost: Cranial Burnout: A Component-based GUI with Functional Flavour has an updated note thanks to Leo White suggesting looking at “mixins”. Unfortunately, I see the link in the post is stale… instead look here: Classes - Real World OCaml, and the relevant material starts under the heading “Virtual Classes and Methods”, eventually getting the subheading “Mixins”.
Comparing the two approaches, mixins and my implementation of “components”:
They both offer a means of composing properties… and behavior, though with mixins behavior is more direct, whereas components imply behavior via properties.
One major difference is that mixins offer static guarantees and language-level support, whereas the components are dynamic (suited to additions and removals at runtime).
Also, the components are naturally grouped by property, and suited to operating by-property. The mixin objects could of-course be grouped similarly, but there’s no requirement (or natural inclination).
I once worked at a company where another team (on a different game) was using a mixin approach, while we were using components similar to what I posted about (though in C++ in both cases).
Anyway, their game-objects were predefined classes built of mixins. The player inherited from twenty-or-more mixins, like Controllable, Targetable, etc.
Again, the difference was that they had compile-time guarantees, and quick access to properties/features from a game-object.
What we had was more flexible at runtime, and imposed a property-wise style of processing rather than traditional object-wise.
In this specific situation, processing by-property turned out detrimental (good postmortem material here!): primarily because the team overall was still familiar with OO-style, typical game-code like
object.Update(). However, property-wise updates can be very helpful: It can be compatible with data-oriented design, systems processing an array (table) of data, which many do for perfomance (new Unity ECS, as opposed to old Unity OO-ish components). It also simplifies multithreading and avoids weird update-order bugs (which are usually ignored-with-hope-nothing-is-serious, but would require double-buffered game-state to actually update correctly – whereas any specific property-table sensitive to update-order can easily be double-buffered where required).
I tried to think of a way to satisfy the interface you propose, but the type-theory part of my brain is pretty weak. But one limitation would be that you couldn’t really have a function which conditionally adds a component at runtime, right? What would the return type be? Schrödinger object?
But you could use the mixin approach to flexibly compose (predefined) entity types… and perhaps also satisfy a component-like interface, though I’m not sure it’s of value in this case – might be!
It’s nice to see someone exploring this space in OCaml. Is this game-related?