alliedmodders/sourcemod — pull request #38 by dvander (2014-06-16 09:16:00+00:00)
Title: Introduce "methodmaps".

A few years ago Sawce suggested a way to introduce syntactic OO-sugar into our API. The idea was to introduce an `x.y` operator that would call native `y` if it could accept `x` as an implicit first parameter. At the time it wasn't clear to me how we could make this work. But now I think I have something. With this, we should be able to incrementally opt our users into an API that feels object-oriented. It's also a fairly powerful extension to the tag system, in that it doesn't require actual objects - for example, a "Player" tag could be used to make all of the player-based natives feel object-y.

This feature is a bit of a work in progress and should probably wait for 1.7 to branch. But it's working enough for review. Since there were a lot of indent-fails in the areas I had to touch, it might be best to review it commit by commit.

Anyway, methodmaps: they work like this.
```
methodmap Handle {
Close = CloseHandle;
};

methodmap AdtArray < Handle {
Clear = ClearArray;
Clone = CloneArray;
Size = GetArraySize;
PushCell = PushArrayCell;
Iterate = native GetArrayIterator(AdtArray:iter);
};

public main() {
new AdtArray:array = CreateArray();
array.PushCell(5);
array.PushCell(10);
array.Close();
}
```

A "methodmap" attaches a list of named functions onto a tag. When the `.` operator is used on a tagged scalar, the tag on the left-hand side is used to find an associated methodmap. The right-hand symbol is used to lookup the method. The left-hand side is magically passed as an implicit "this".

methodmaps can either point to an existing native, or an inline-declared native. This is because most APIs will need to support both calling conventions. For brand new APIs (like the transaction API), it seemed okay to just change the signatures to encourage methodmap use.

Methodmaps also support simple linear inheritance, and the type system has been extended to support that as well. For example, it is legal to assign a `Transaction` to a `Handle` as long as there is a `methodmap Transaction < Handle {}` somewhere.

Unfortunately, this is not expressive enough to just start porting random APIs over. The AdtArray example above assumes that we'd change the signatures of all the individual natives to take in `AdtArray` tags. That would break older code. I think what I'll have to do is introduce another inline syntax, like:

```
methodmap AdtArray < Handle {
Size = stock (AdtArray:array) { return GetArraySize(array); }
}
```

Alternately, I could lax the rules for `this` a bit - so the first parameter can be the base type (right now it must be the derived type). Not sure yet.