One thing that GameMonkey (GM) currently lacks is the ability to be used via 'C' APIs (and languages which can support them directly from DLLs such as VB6, C#, Delphi, D, etc). This isn't a failing in my eyes, so I'm not being critical of GM's wonder API (which is infinitely better than Lua's); I'm merely looking for a way to ease the C# Wrapper I'm coding as well as perhaps broaden the GM audience a little. What I'm playing with is writing an anti-wrapper for GM (anti-wrapper is my own word :p).
For the anti-wrapper, we'd need to unwrap each GM class into structs (if data is public) or handles; and functions (which were previously member functions). So gmMachine::ExecuteString would have to be unwrapped to something such as gmMachine_ExecuteString, which would then take an object handle to a gmMachine object (to act as 'this'). Bear in mind that C APIs generally have warts, or library prefixes, to distinguish similar functions from different libraries. For this test, I'm looking at the warts gmcapi, or even just gmc.
Where we have a GM program that goes as follows:
gmMachine *gm = new gmMachine(); gm->ExecuteString( "global a = 1234; print( a );" ); gmTableObject *tab = gm->GetGlobals(); gmVariable v = tab->Get( gm, "a" ); v.m_value.m_int = 9876; tab->Set( gm, "a", v ); gm->ExecuteString( "print( a );" ); delete gm;
The same program in our unwrapped (and warted) API would look as follows:
gmc_gmMachine gm = gmc_gmMachine_New(); gmc_gmMachine_ExecuteString( gm, "global a = 1234; print( a );" ); gmc_gmTableObject tab = gmc_gmMachine_GetGlobals( gm ); gmc_gmVariable v = gmc_gmTableObject_Get( tab, gm, "a" ); v.m_value.m_int = 9876; gmc_gmTableObject_Set( tab, gm, "a", v ); gmc_gmMachine_ExecuteString( gm, "print( a );" ); gmc_gmMachine_Delete( gm );
Yes, the API looks a little noiser and is more verbose, but it works.
My main questions are regarding styling and naming conventions.
- Would the wart gmc_ or gmcapi_ be preferable to you?
- Should functions be cased as they are in the example above, or would you prefer C naming conventions such as:
gmc_gmMachine_ExecuteString
gmc_gmMachineExecuteString
gmc_MachineExecuteString
gmc_Machine_ExecuteString
gmc_Machine_Exceute_String
gmcMachineExecuteString
gmc_machine_execute_string
The last one is how I'd say the C world is used to APIs, but I think I'd prefer the first example. From there it's instantly clear which gm class it was taken from, and which function was used.
It all comes down to preference, I guess. which owuld you prefer to see/use if you HAD to use this API? (Not that many people will).
My main motivation behind this is so that I can use GM with VB6 at work, and use P/Invoke directly on this API via a DLL so that people can start using GM in C# and .NET.
Progress so far is that I've coded up the above example so it works; I stopped to ask this question so I didn't get too far down the wrong track and had to change the entire API for stylistic reasons :p