Mess? I'd call a column called `flags` containing a bunch of arbitrary numbers the mess.
Bitflags have use cases, but this isn't one of them.
I want a kind of tree structure of bitflag values, and I'm trying to think of a good way to do it. For example a Grass /Stone tile, maybe 4 bits for the tile type (0001 = Grass), and then from that point forward, the remaining flags depend on the tile type (Grass having the next 2 bits for the grass colour, stone having 1 bit for whether it's cracked or not, etc), but in a safe and efficient abstraction where I can't accidentally mix them up. I don't want a pirate software monstrosity where I can't keep track of the different combinations.
Regarding your case, I'm pretty sure that such type safety can be achieved. It is depending on the ecosystem you're working but if its C++ I would go for CRTP implementation with heavy load of template meta programming - like defining TYPE_ID=1 for grass, TYPE_ID=2 for stone and creating BaseTile -> GrassTile/StoneTile with polymorphism on std::variant.
I think this is not exactly the tree structure, but your minimal case can be achieved by assigning different "concern" to different set of bits in the number. For instance bits 31..24 will be TYPE_ID and 23..0 will be attributes (color of the grass, is the stone cracked). However it will quickly become to small to build anything reliable, but then I would change the structure of tiles to have one non-bit flag integer for block type and the one placed sequentially next to it to the attributes bitflag (max. 31 attributes per block? should be quite enough)
You would also need to establish the whole map format - header of the file (version could possibly be stored per map and exist in header, not per tile?), chunks (per-chunk header, chunk data), optimization strategies like RLE, unique separators, serialization and deserialization, endianness auto-conversion and probably more.
Anyways, please correct me if I am wrong but compiler will help you with types only after static_asserts - as I imagine it would be useful mostly for defining interactions between blocks (which ones are allowed and which ones are not). For every other case the compiler would need to know your map at the compile time to help, and it can't be done.
In TypeScript (its a main example of language in the article, I'm not 100% sure if its possible to do such compile time checking but arktype.io would be an excellent choice for this kind of implementation. I really encourage you to check out their solutions as really complex systems can be built on top of it)
kosolam•5mo ago
neg4n•5mo ago
The benefits of applying it in cases of enormous data transfer and its volume on disk are also not that big (I did projected benchmarks of bandwidth and disk usage in the article), as things replaced by bit flags are possibly only a drop in the ocean in such application's backends. But still - it is one of an option of the optimization.
And if you decide to go with the bit flags implementation - I must respectfully disagree with changing stack being classified as the low hanging fruit to pick. In my opinion it is the most error-prone event that could happen in development lifecycle of any product. Both from business and technical perspective considering factors such as talent pool availability, team mentoring, migration process, testing the systems on automated/real users level and likely loads more. All these things introduce costs and time complexity. It would be a tough decision to make for the CTO.
I may be wrong but IMHO it would be easier to hire one guy that knows systems from a little lower level perspective, mentoring the team (that have web dev only knowledge) and establishing solid development rules while proceeding with bit flags than migrating whole (or even a part) application to the other stack, changing the team completely or creating a possibly terrible in its results responsibility of one developer to manage it.
Curious to hear different opinions!