Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investigate using code generation for implementing reflection automatically #1420

Open
RiscadoA opened this issue Dec 16, 2024 · 0 comments
Open
Labels
A-Core B-Reflection D-Complex Looks hard P-Normal This issue isn't a big priority, but it would still be nice to have it closed soon S-Needs-Design Demands some time designing an implementation

Comments

@RiscadoA
Copy link
Member

RiscadoA commented Dec 16, 2024

Problem

Currently writing reflection code for all components is very cumbersome.
Additionally, we are duplicating information / detaching the reflection implementation from the type declaration. It's very easy to get the reflection definition unsynchronized from the actual type.
One thing that happens frequently is a field name changing and the dev forgetting to change its name on the reflection side, or the dev adding a field and forgetting to also add it to the reflection implementation.
It's also very easy to enter typos which break stuff, such as writing the name of the type wrong.
Overall, this makes the reflection experience very cumbersome, particularly when working on a actual game.

Solution

We previously had a similar system in place but for a different purpose, in the old serialization system. It automatically generated serialization methods for types from their fields. We scrapped it entirely because the system generated headers which needed to be included in user code. This led to a bad experience with IDEs.

With the new reflection system we now have in place, the whole generated part of the reflection can be hidden a way into a single .cpp per compilation target. On the user side, the only thing that would change, would be us adding a new macro CUBOS_AUTO_REFLECT;, which could be used like this:

struct Player
{
    CUBOS_AUTO_REFLECT;

    /// @brief Health of the player.
    float health;
};

CUBOS_AUTO_REFLECT could be simply defined as #define CUBOS_AUTO_REFLECT CUBOS_REFLECT, i.e., it does nothing by itself.
The code generator would parse the source code, searching for occurrences of CUBOS_AUTO_REFLECT, and then, generate a matching CUBOS_REFLECT_IMPL` for each type, i.e.:

#include "header-where-player-is-defined"

CUBOS_REFLECT_IMPL(Player)
{
  return Type::create("some::namespace::Player")
     .with(ConstructibleTrait::typed<Player>().build())
     .with(FieldsTrait{}.with("health", &Player::health);
}

Since we're parsing the source code, we can do cool stuff, such as storing the documentation of each field in the reflection! This would be very useful for getting useful descriptions in the editor.

We could also do some cool stuff such as using macros for hinting stuff to the code generator. for example:

struct Player
{
    CUBOS_AUTO_REFLECT;

    /// @brief Health of the player.
   CUBOS_PROPERTY(Rename, "hp")
   CUBOS_PROPERTY(Range, 0, 100)
   float health;
};

These macros could evaluate to nothing, i.e., #define CUBOS_PROPERTY(...) /*empty*/. The code generator would do the actual work.

Open problems

  • How would you parse the code? We should use a library for this. Clang is pretty cool but seems like a pretty big dependency to fetch... is there something more lightweight?
  • What if the type we're generating reflection for is in a .cpp file? We wouldn't be able to include it in the generated file, thus I think we wouldn't be able to support that use case, which is a bit irritating
  • WIP probably there's other problems, if we follow through with this we should think it through!
@RiscadoA RiscadoA added A-Core B-Reflection D-Complex Looks hard S-Needs-Design Demands some time designing an implementation P-Normal This issue isn't a big priority, but it would still be nice to have it closed soon labels Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Core B-Reflection D-Complex Looks hard P-Normal This issue isn't a big priority, but it would still be nice to have it closed soon S-Needs-Design Demands some time designing an implementation
Projects
None yet
Development

No branches or pull requests

1 participant