Lua Style Guide Discussion Thread

About the post on making your variables' types clear, I've been using "p" as a prefix for object-like tables in Lua. Technically the "p" refers to pointer, which is why it's used in the DLL that way, but I feel it offers some consistency across those two code bases, even though "pointers" don't exist for us to use in Lua. I think Firaxis use pPlayer and pUnit and such in their Lua code as well.

Also, I have a question about GameInfoTypes. Say you have this:

Code:
local myString = "UNIT_WORKER"
local iWorkerID = GameInfoTypes.?

This is obviously a simplified version, but can I query GameInfoTypes using a string with the identifier in it? Mainly I'm using this when looking up units in other tables (say UnitClasses) and wanting to grab the Unit's ID out of the database now that I've got the string (so I can actually use InitUnit and other similar functions.)
 
Thalassicus had a nice thread on this here. There was some discussion there about Hungarian notation versus "camel case" notation for variable names. I find a strict adherence to Hungarian very annoying and uninformative. Knowing variable type has never been a problem for me. E.g., x,y are always integers. Much more informative to have recX, recY, hexX, hexY, which actually does tell me something I need to know. An i prefix there is superfluous.

As you noted in the other thread, Firaxis is not consistent with itself on many things. The best you can do (if you use them for a guide at all) is sort of follow what they usually do. Even that might not always be the best idea.

I believe Firaxis uses "g_" for file locals rather than globals in most cases, at least in the UI files. (But since many UI files run in their own state, this may be a distinction without a difference.) Anyway, I followed that convention and then was forced (not quite happily) to use "gg_" for actual mod globals. Since my mod also has certain global tables that are preserved through save/exit/reload, I came up with a third prefix (just "g") for those.

Firaxis uses iPlayer and playerID very interchangeably. If you feel you have to use Hungarian notation (yuck!), then you should use the former only. I settled on a rule for my own mod which was that iPlayer, iUnit, iPlot, etc would always be used for indexed game objects. However, buildingID, policyID, unitID, etc would always refer to ID for any database item. Then you can use buildingType, policyType, unitType to refer to the Type field in the DB (a string; and no, I will not use an "s" prefix). Firaxis often (not always) uses buildingInfo, policyInfo, etc to refer to the whole row in the DB, which I follow. The ID/Type suffix is totally consistent with the DB (which I find most helpful) but, as a consequence, is inconsistent with many of the Lua function names (where "Type" always means database ID: e.g., plot:GetImprovementType(), unit:GetUnitType(), etc.). But as I mentioned above, trying to be consistent with Firaxis is like chasing your own tail.


Edit: Btw, are you offering to rewrite my mod's 20,000 lines of Lua once a standard is determined?
 
Edit: Btw, are you offering to reformat my mod's 20,000 lines of Lua once a standard is determined?
Ha! All I want to do is get something up with basics in it for new modders to hang their hat on. Obviously, as already stated, nobody has to do anything, it's just a guide.

In most cases I agree with you that a variable describes it's type, e.g. iCount -- I don't really need to know that a counter is an integer. I think the difference perhaps is in distinguishing between simple and complex variables. count, without the i, could represent an instance of a counter, thus pCount instead of iCount.

To an experienced modder/programmer they can mostly likely easily tell what count represents by how it is used, but, there is room for confusion.

Variable naming conventions are certainly not a 'hill I'm willing to die on'. I don't feel that strongly about it. Back in the days of C/C++ before all those nice library functions like safe pointers you kids get to use, it was more important.

Thanks for the link to the other thread, btw :)

Edit: I updated the guide to reflect your concerns, also.
 
As I think of more things, or as people have suggestions and questions, I will update this. But I'm not moving it forward right now at any priority on my own, without contribution or more of a demand :) It's not that I can't think of more to add, but I want to add things that are style related. So mentioning save games and how to share data between files or mods, seems off topic.
 
pcall

As long as GameEvents is broken in it's bug reporting, and perhaps for other reasons as well, I going to recommend pcall be used for GameEvents. There are many ways to do this, and I'll link to a thread discussing it in a moment, but here is a simple code sample of one way, first.

Code:
function MyEvent(arg1, arg2)
  -- do stuff
end

function P_MyEvent(arg1, arg2)
  print(pcall(MyEvent, arg1, arg2))
end

GameEvents.SomeGameEvent.Add(P_MyEvent)

Pcall in depth

While this seems like a good idea, in practice it is not. The overhead of another function call and creating the call stack frame within Lua will become significant in late game AI turn processing - something that almost certainly will not show up in (initial) play testing, so is very likely to go unnoticed.

Hooking SetPopulation() like this would have no issues - as even with 10+ AIs late game with 20+ cities each, only a small number of those cities will be changing their population in any one turn. However, if you also hooked CityCanTrain(), CityCanConstruct() and CityCanCreate() in a similiar manner, each of those cities will have around 40 possible choices of units/buildings/projects so even if only 5% need a new task you are looking at over 400 additional function calls and stack frame creations. Use the same technique on UnitSetXY() and even by mid game you'll be impacting turn times. And that's just for one mod, multiply that by several mods all hooking those events in this manner and the impact could be game breaking.

The only need for pcall() is to capture errors - something that shouldn't be occuring in final code on a regular basis. It is therefore only needed during testing to trap unexpected edge cases and un-allowed for circumstances. It should not be necessary in the final released mod and if any errors do slip through, the pcall() can be reinstated when they are being tracked down and fixed by the modder.

At the very least the use of pcall() should be limited to a debug mode, eg

Code:
local bDebug = false

...

GameEvents.SomeGameEvent.Add(bDebug and P_MyEvent or MyEvent)


Moderator Action: post moved from the main Lua Style Guide thread
 
Back
Top Bottom