Open ivan-mogilko opened 1 year ago
How does/would this resolve in the new compiler if the object member (instance or, in this proposal, static) matches a global function or variable? For example, given this struct:
managed struct Example {
Character* player;
static Hotspot* hotspot;
import void Wait(int time);
import static Example* Random(int max);
import void Test();
import static void TestStatic();
};
… Would these references point to the internal members, or to the global functions and variables by the same name?
void Example::Test()
{
Wait(10); // AGS Wait() or this.Wait()?
player.ChangeRoom(-1); // AGS player or this.player?
}
void Example::TestStatic()
{
hotspot = hotspot[Random(AGS_MAX_HOTSPOTS)]; // AGS Random() or Example.Random? AGS hotspot[] or Example.hotspot? (Fails to compile if AGS hotspot[]?)
}
Or will the compiler complain about clashing function/variable names?
And if it resolves to the local reference, is there any way to access the global one?
I just tried it, and if struct's member matches the name of the global symbol, then compiler assumes the global symbol, so you must call it with this.
This is rather unexpected, and contradicts to how C/C++/C# deal with this. Looks like the order of resolving a name is reversed (starts with global symbols instead of local ones....)
While it's reversed, it makes sense as there's nothing you can put forward that points to the global scope but for the local scope you havethis
keyword.
A consequence of this is that adding any new global functions or variables to the AGS API can unexpectedly change the behavior of existing code.
But perhaps global functions and variables are not supposed to be used (or, at least, introduced) in AGS 4?
It's a good thing to put everything in a "namespace" (like a static class), but they will keep being there for a while, also noone can prevent people from writing modules with global functions.
I suppose that AGS script may benefit from global namespace accessor (like ::
in C++) that would make scope distinction explicit where necessary.
To explain the current situation:
AGS doesn't currently have a good way of saying "take the global symbol, not the struct symbol", but it does have a good way of saying "take the struct symbol, not the global symbol" (namely, put this.
in front of that symbol).
That's one of the reasons why when there is a global possibility as well as a struct possibility, the compiler prefers the global. If the programmer wanted the struct variable instead, they could use this.
and say so.
The other reason is what the compiler actually does when it looks up symbols: It simply looks into its tables, and if the symbol is defined there, it considers the job done. But when it isn't defined in its tables, it doesn't give up just yet (as the old compiler did), but makes another try with this.
in front of the symbol, and if that is defined, it takes that.
int X;
struct S {
int X, Y;
import function Foo();
}
function S::Foo()
{
Display("%d", X); // `X` is defined, it's that global up there in Line 1, so I'm going with it.
Display("%d", this.X); // The X within the struct must be meant
Display("%d", Y); // What? Don't know `Y`. Let's try `this.Y`. Ah that's defined? Okay, use that.
}
So what do you want the compiler to do? Hide global X
when this.X
is defined? It can be done.
What about a local X
? Would that hide the X in the struct?
int X;
struct S {
int X;
import function Foo();
}
function S::Foo()
{
int X = 7;
Display("%d", X); // Display the local `X`, the global `X` or `this.X`?
// Currently, the compiler would find the local X first and consider the job done.
}
But perhaps global functions and variables are not supposed to be used (or, at least, introduced) in AGS 4?
As far as I know, global functions of the AGS interface are sort of deprecated: When new functions have been added to the interface, they were all under some umbrella type (if nothing fits, under Game
). That must have already started in Chris Jones' time. What remains are some very old or very common functions such as Display()
.
So what do you want the compiler to do? Hide global X when this.X is defined? It can be done. What about a local X? Would that hide the X in the struct?
Well, i believe that there has to be a universal unambiguous rule for which scope takes the precedence. And in my opinion the precedence should be given to a local scope, because that's a standard, and without it writing generic code will be a complicated task.
New compiler already allows to omit the
this
keyword when addressing object's methods and fields from a object's method, but I found that when calling static methods from object's method you still have to typeTypename.Function()
.If possible, I propose to also let omit the typename in this scenario.
Unless this goes against the desired syntax design, in which case you may cancel this suggestion.