Well, in Napoleon for exemple, the improvements are looked after by a function findImprovementByName(string), which then look each time in all 40 improvements for such a named improvement to return it.
Didn't put my head in recent codes howether, like OTR.
I wondered if this system using strings as reference had an advantage I may miss (nooby with lua after all) in compare with an early allocation like made with units, tribes and cities ?
You would have to ask @Knighttime or @tootall_2012 why they chose to use string comparisons to get objects. It may just be that everything was new, and the only example we had was a conversion of the Fantasy scenario by TNO. If the only 'known' options were either civ.getImprovement(id) or findImprovementByName(string), then the latter is certainly easier to use and read. I use that method in the Legacy Event Engine, but only because of the way the data is provided in a legacy events.txt file.
I would recommend the "object table" method of referencing things for a couple reasons:
1. It is more human readable than direct integer references.
2. It allows you to change the name of the object (unit type/city/improvement etc.) in the rules or game without breaking anything in your code.
3. If you want to change the 'slot' for the unit/improvement/tech/etc., you can make the change in one place, and have the rest of your code work.
4. You can "merge" unit types or improvement types by having 2 keys in the table reference the same value, and many events will still work properly. (I could probably come up with a counterexample with a bit of time, so you'll still have to test relevant events.)