Skip to content

Tag-based OO-like code #234

@Y-Less

Description

@Y-Less

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)
#endif

Natives 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions