Skip to content

Run-time type information support #141

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

Merged
merged 26 commits into from
Aug 26, 2022
Merged

Conversation

fsahmad
Copy link

@fsahmad fsahmad commented Dec 15, 2020

Add basic RTTI support to ACT to make it possible to perform dynamic casts on all binding objects.

Implements issue #142

  • Added a new example in Examples/RTTI
    • CppDynamic binding contains a dynamic cast function RTTI::rtti_cast<T>
    • Python binding adds a cast classmethod to the Base class
    • A new method bool ImplementsInterface(CBase*, const std::string&) was introduced on the CWrapper class, that uses dynamic_cast to check if the object can be cast to the interface

Pending tasks

  • Implement the changes to generate the necessary code
  • Consider if the string lookup can / needs to be made more efficient, for example by using statically generated hashes
  • Update documentation

w.Writeln(" static_assert(std::is_convertible<T, CBase>::value, \"T must be convertible to %s::CBase\");", NameSpace)
w.Writeln("")
w.Writeln(" if (pObj && pObj->m_pWrapper->ImplementsInterface(pObj.get(), T::getClassName())){")
w.Writeln(" return std::make_shared<T>(pObj->m_pWrapper, pObj->m_pHandle);")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to call pObj->wrapper()->AcquireInstance(pObj); to make sure reference count is correct.

w.Writeln(" @classmethod")
w.Writeln(" def cast(cls, instance):")
w.Writeln(" if instance and instance._wrapper.ImplementsInterface(instance, cls.ClassName()):")
w.Writeln(" return cls(instance._handle, instance._wrapper)")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to call instance._wrapper.AcquireInstance(instance); to make sure reference count is correct.

@martinweismann
Copy link
Member

Looks quite good.
Apart from @fsahmad 's open points, the following also needs to be sorted out:

  • Pascal implementation must autogenerate the "ImplementsInterface"-function
  • The name of the getClassName-method needs to be configurable via the ACT-XML to avoid accidental name clashes
  • add an automatic test for the Animal-Example (this one is definitely on me)

@fsahmad
Copy link
Author

fsahmad commented May 19, 2021

The name of the getClassName-method needs to be configurable via the ACT-XML to avoid accidental name clashes

I think that might not actually be necessary, it depends on the other binding languages but so far I noticed:

  • In the C++ bindings the methods I added (getClassName / getClassHash) have lowercase names to prevent conflicts
  • In Python I used upper case, but lowercase can be used there too

@martinweismann, @alexanderoster do you see any problem with using this strategy for all other binding languages? Other languages might use an underscore prefix (I think this is a common pattern in JS for example).

Edit: I forgot to mention, if these names do need to be configurable there's an additional complication as these are methods on the Base class, while the current pattern is to add attributes to the Global tag. Also, this would mean the API developer has to add the method to the Base class definition, but the return type for getClassHash is not easily represented in ACT (std::array<uint8, 16> for the MD5 hash).


using namespace RTTI;
while (auto animal = iter->GetNextAnimal()) {
if (auto tiger = rtti_cast<CTiger>(animal)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexanderoster @martinweismann how do you feel about the name of this method (<namespace>_cast), I think it would be better to change this to something like obj_cast because it already resides in the namespace.

For example, using it on a component with namespace Widgets would currently look like this:

bool CheckWidget(Widgets::PBase pObj) {
    auto foo = Widgets::widgets_cast<Widgets::PFoo>(pObj);
    return foo ? foo->IsOk() : false;
}

Depending on the namespace, the method name can become awkward, especially when the namespace isn't imported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.
Considering that class names in the ACT-C++ bindings are usually referred to as Namespace::CClassName, i think using Namespace::obj_cast is more consistent than Namespace::Namespace_cast.

@autodesk-chorus
Copy link

Chorus detected one or more security issues with this pull request. See the Checks tab for more details.

As a reminder, please follow the secure code review process as part of the Secure Coding Non-Negotiable requirement.

@anpilog
Copy link

anpilog commented Sep 30, 2021

Hi @alexanderoster and @martinweismann
It's been a while since this PR has been abandoned.
I'm working on Electron-EAGLE projects now and want to take over this feature as the project is using it since April.
So we essentially have only two choices:

  • work on this PR and make it suitable for merge into next release
  • fork ACT and keep it up to date with mainstream development

Looking into comments on this PR I see next pending tasks:

  • Pascal implementation must autogenerate the "ImplementsInterface"-function
  • The name of the getClassName-method needs to be configurable via the ACT-XML to avoid accidental name clashes
  • add an automatic test for the Animal-Example (this one is definitely on me)
  • Update documentation

Just want to double check if anything missed before taking over this tasks.

class := classes[j]
hash := class.classHash()
w.BeginLine()
w.Printf(" static const RTTI_uint8 s_%sHash[] = {", class.ClassName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hard coded namespace "RTTI" should be replaced with "componentdefinition.namespace"

Same in line 757 and potentially more.

@martinweismann
Copy link
Member

Hi @anpilog ,

thanks for picking this up.

I don't see any fundamental problem left. @fsahmad 's approach is good. I would love to merge the fork back into develop to make this part of the new release.

The list of open points is accurate, except for two items:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants