-
Notifications
You must be signed in to change notification settings - Fork 88
Description
Making PAWN more OO-like has been discussed over and over and over again. While I'd personally be against a fully-fledged rewrite a-la SourcePawn Transitional Syntax,, I think I have a relatively light-weight proposal to introduce a good set of OO features very very little cost in terms of changes (and nothing breaking). Basically, just map this:
native Tag.Function(a, b);
stock Tag.Function(a, b)
{
}To this
native Tag_Function(Tag:this, a, b);
stock Tag_Function(Tag:this, a, b)
{
}This follows long-standing SA:MP Module_Function conventions, plus a this convention, and would not introduce new requirements for passing around "objects", as this is still just a cell - what you want to do with that in terms of treating it as a handle to more data is entirely up to the library author (or whoever). It would even remain compatible with old code as calling Tag_Function(handle, 0, 0) would call the correct function even if it was declared with the new Tag.Function() syntax.
Some libraries already use a macro to support Library::Method() syntax, which is why I didn't suggest adopting :: for this (plus it would probably be more complex to get working around the existing tag syntax). That could even be an avenue for writing global libraries:
#if __COMPILER_MODIFIED
#define this,) this)
#define Object::%0(%1) Object_%0(Object:this,%1)
#else
#define Object::%0(%1) Object.%0(%1)
#endifNatives would work the same:
native File.Write(const string[]) = fwrite;Would compile as:
native File_Write(File:this, const string[]) = fwrite;Clearly entirely compatible with the existing native.
To call the methods, use a strongly tagged variable (I'd suggest against allowing this on weak tags - far too likely to cause unexpected calls):
new StrongTag:x;
x.Method();Compiles as (sort of):
new StrongTag:x;
tagof(x)_Method(x);Or more accurately:
new StrongTag:x;
StrongTag_Method(x);Obviously that would require the tag of a variable to be known at compile time, and this could not work for run-time polymorphism:
Func({ Tag1, Tag2 }:x)
{
x.Method();
}Tag returns (and hopefully chaining) could work, but I know that would be much harder to implement as it would require more manipulation of the AST:
Tag:Tag.M1()
{
return this;
}
Tag:Tag.M2()
{
return this;
}
// Call:
new Tag:x;
x.M1().M2();
// Becomes:
Tag_M2(Tag_M1(x));Or no reason to keep the same tag:
Tag2:Tag1.M1()
{
return that;
}
Float:Tag2.M2()
{
return 1.0;
}
// Call:
new Tag1:x;
x.M1().M2();
// Becomes:
Tag2_M2(Tag1_M1(x));This is not full objects, and is mostly based around tag-based handles, but I think it goes a long way. I wrote something about supporting operators as well, but they already have overloading and wouldn't need the dot-call syntax.