As the new parser approaches completion, it is time to start considering the implications. I have already made the executive decision of implementing half of this in the past, but what has been implemented will need some recoding, and the new parser allows for marvelous new extensions I would like to take advantage of. As such, I figure it would be good of me to draw up this proposal both to inform developers and open the floor for comments before they are implemented.
Developers heretofore have used the global [bubble]enigma::instance_event_iterator[/bubble] to determine the current instance and interface with its locals. At first glance, there's nothing wrong with this, but when we really consider its implications, we start to see its limitations:
- Threads cannot manipulate this variable concurrently.
- Sideways casts between virtual ancestors cannot be made correctly in other files.
- Functions which change scope must synchronize their use of this variable.
- This variable does not, in itself, affect the scoping of scripts and functions called therein.
We can correct all of this by having reflexive functions, such as [snip=edl]instance_destroy()[/snip], take an additional parameter, [bubble]_E_SELF[/bubble], of a particular C++ instance type (eg, [snip=edl]_OBJ_object0*[/snip]).
This is similar to the mechanism with which you are likely already familiar, the [bubble]varargs[/bubble] type, which allows you to request an stdargs-like overload which you can treat like an array of parameters. It is similar in that each of these are semantics that can be declared in C++, but only used in EDL via the intervention of the parser.
The proposal, then, is as follows:
- Any parameter with the type [bubble]enigma::varargs[/bubble] will be allowed to be passed an infinite number of parameters, as an array. The parser will handle packing the parameters given into the array in an efficient manner.
- Any parameter with the name [bubble]_E_SELF[/bubble] and a pointer-to type will be invisible to the user and filled in by the compiler with a pointer to the instance in question, meaning [snip=edl]this[/snip] in events and member scripts, and [snip=edl]with->inst[/snip] in [snip=edl]with[/snip] statements.
The lexical stipulations should be my concern rather than yours. Basically, don't assume you can do anything stupid. For instance, the following is a set of legal overloads:
int max(double, double);
int max(double, double, varargs);
While the following is ambiguous:
int max(double, double);
The reason, of course, is that if you pass it two doubles, both functions are equally logical choices. Now, I could choose to give weight to the concrete matches precedence, but I'm asking for your opinions on that, first.
Now, as for the [bubble]_E_SELF[/bubble] parameter, if you think you have a better method of unambiguous identification for this which corrects issue (2) given above, let me know. Or, if you prefer a different name, such as just SELF, let me know as well. Otherwise, this will be the new format for the prototype:
void instance_destroy(enigma::object_basic* _E_SELF);
So, post suggestions, or be aware that these two modifications mean changes to the API, including existing functions.
Floor's open. Be informed. Feel free to contribute.