-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support script object pointer downcast #2018
Comments
There is also the python approach of using super. It would be something like Overall, I like the C# style best, as it doesn't automatically invite other types of casting as a complexity. |
Hmm, but that upcasts as opposed of downcast? AGS already supports getting parent's pointer, you can do:
EDIT: I think I forgot to mention another variant, idk how good it is, but worth mentioning: a static method that casts to this type from parent, like:
I got this idea while thinking that GUIControl.AsButton, AsLabel etc is bad, because it hardcodes the list of descendants, so I wondered if we could instead have
or similar. |
@fernewelten , would you be willing to write a "typecast" operator for the new compiler? I wrote a naive "dynamic cast" implementation in the engine here, in this experimental branch: I'm thinking about a most trivial classic syntax of For pointers, I suppose, the compiler would need to do following:
If this is implemented in compiler, then the remaining task is implementing this in the engine. I think that so long as the instruction is designed, the engine's implementation may be done and improved at its own pace. This should work trivially for user-made managed types. I have got an idea of how to make builtin engine classes work too (there will have to be some changes, but that's engine's problem). It may or not work for plugins depending on how they registered their managed types, but maybe that's rather a matter of documenting the behavior and suggesting that plugin authors program them right. |
Actually what I really want to be able to do is this managed struct T {
import void Do();
}
void T::Do() {
Display("I am only T :( ...");
}
void DoExT(T* inst)
{
inst.Do(); // make it print from ExT somehow, without specifying ExT!!
}
// in some other script
managed struct ExT extends T {
import void Do();
}
void ExT::Do {
Display("I am ExT :) !!!");
} I think it's pointer upcast? I believe this is possible using python super. This would enable making a module that can take a function pointer of sorts, wrapping it as an extended struct. |
@ericoporto your script example is not pointer upcast, it's an example of virtual functions. Pointer upcast is casting from child to parent, and it's already supported in ags script:
|
ah, ok, so it is for this https://www.adventuregamestudio.co.uk/forums/advanced-technical-forum/solved-trying-to-cast-struct-size-of-identifier-does-not-match-prototype/ . I do think the The other approach is no syntax at all and only support implicit cast of managed pointers. Like GUIControl* ctrl;
Button* btn = ctrl; |
This will not make it possible to chain expressions, and also may be prone to mistakes imo. |
Yes, as soon as the Engine supports this, we can get this done. As for the AGS language, my personal favourite would be the
|
Alright, let it be
I can apply my SCMD_DYNAMICCAST implementation, but I do not know how to test it directly without compiler generating it... |
Hmm, so, I've been thinking a possible implementation in the engine, and the big issue is matching a type declared by engine or plugin in script and the same type produced by engine or plugin at runtime. The way I wrote RTTI generation, it composes a fully qualified type name as a pair of "location::type", in order to distinguish types declared internally in scripts. The problem here is that both engine and plugins only know their bare "type" names, but they don't know about this "location" part. Currently it's based on script header filename, which in turn is generated according to some arbitrary rules by the editor. But I don't like having to rely on that. At first I considered relying on "builtin" keyword, but then realized that plugins may also use this keyword (in fact, they should, although existing plugins probably do not). Strictly speaking, engine may assume that since its types (and plugin's types) are declared for all scripts, then if there's any "type" in any location matching internal API name, then it should be that. So it could run around the RTTI table, finding these types, their global typeids, and, say, register a lookup "alias" without "location::" part, pointing to the same typeid, - that is for quicker access when doing any type matching with the engine's types. The problem here though, even if we do that, we can't do same for plugin types, because there's no method in plugin API for registering types, there are only methods for registering type methods... which is an oversight, imo, but whether this will be changed or not is not obvious at the moment. In any case, we cannot tell which types belong to plugins, and cannot create same lookup aliases for them. Eventually I came to a conclusion that we should add some sort of group identifier to the types declared as a engine or plugin API. AGS does not have any ready concept for that currently, there's no such thing as a "namespace" or "package" etc (maybe something like that would be useful, but it's a whole separate story, and I don't want to bring any new big feature right away). What can be done though, is specifying a sort of a optional tag, used instead of "location" when building RTTI table. Such "tag" could be made in a more concise way than the generated header's name, and be ruled by an "official" standard. |
In regards to the above comment. I figured out that it won't be possible or at least not convenient to do what I proposed without a new preprocessor command. The reason is that it's preprocessor who creates NEW_SCRIPT_MARKER in a script file, and preprocessor does not know what the script header means. We have a standalone preprocessor too, so we'd have to pass this information as an additional command-line parameter anyway, which is ugly. I'm now thinking about this solution:
|
The standalone version doesn't have the preprocessor ran separately, it runs integrated with the compiler - this is because of the macros that are configured in the compiler and necessary in the preprocessor, so there's back and forward between the two just with slight differences in how but not in behavior between editor and standalone. |
Okay, but the point is, it still receives all data as command line arguments, while in the editor you can potentially pass arguments directly using a program interface. What I meant above, the standalone compiler program will not know what the header means, is that a engine api, or else. |
Opened a draft PR for the engine side: #2665 |
CC @fernewelten
After RTTI was added in ags4, it is now theoretically possible to find out the managed object's parent(s), knowing its type. This opens a possibility to support downcasting, that is - a conversion from the base type pointer to a child type pointer. As opposed to the upcasting, which may be calculated at compile time, downcasting has to be performed at runtime, as compiler cannot know which type will be stored in the base pointer.
What would be required for this?
Child* child_ptr = (Child*)parent_ptr
;Child* child_ptr = parent_ptr as Child
;cast<T>(parent_ptr)
orcast<T*>(parent_ptr)
, but it looks more complicated.The text was updated successfully, but these errors were encountered: