-
-
Notifications
You must be signed in to change notification settings - Fork 420
Give TypeInfo_Class/TypeInfo_Interface.isBaseOf like C#/Java isAssignableFrom #2770
Conversation
Thanks for your pull request, @n8sh! Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + druntime#2770" |
src/object.d
Outdated
{ | ||
if (parent is null) | ||
return false; | ||
if (parent is this || parent.name == this.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use if (parent is this || parent.name == this.name)
instead of opEquals
because TypeInfo_Class.opEquals
isn't marked as any of nogc/nothrow/pure/safe and isn't callable on a const argument or with a const receiver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamic casting just compares TypeInfo pointers, so if you don't expect copies of TypeInfo being made at runtime, you don't have to compare names. You might also just call rt.cast_._d_isbaseof
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If pointer comparison is good enough for dynamic casting then it is good enough for this purpose too. Thank you for the tip regarding _d_isbaseof
.
Seems like a good idea to me. I'm not sure about the implementation though; is |
976fea2
to
e0229ca
Compare
What's the use case for this ? Java / C# reflection is primarily runtime, while D's is primarily compile time. |
My personal use case was implementing multimethods when the classes involved aren't known at compile time. |
@n8sh Perhaps rebasing on top of master should fix the error on BuildKite. |
Changing to use |
src/object.d
Outdated
for (auto ti = cast() child; ti !is null; ti = ti.base) | ||
if (ti is this) | ||
return true; | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's some case for classes where this gives the wrong answer but _d_isbaseof
gives the right answer I haven't found it. Unless such a case can be found I'll leave it here since _d_isbaseof
potentially does a lot more work and extern(C)
function calls are opaque to the optimizer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking back at this, checking straight up the inheritance chain rather than using _d_isbaseof means that the receiver TypeInfo_Class and argument TypeInfo_Class must represent actual classes rather than being the .info field of some TypeInfo_Interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solution: detect an interface's ClassInfo (TypeInfo_Class that does not represent a class) by checking if the initializer has length zero.
@@ -14,6 +14,9 @@ | |||
module rt.cast_; | |||
|
|||
extern (C): | |||
@nogc: | |||
nothrow: | |||
pure: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding some attributes here so the compiler enforces the same attributes I claim in the private extern(C)
declaration in object.d
.
125559e
to
84d1ed5
Compare
@n8sh whats the status of this? |
@thewilsonator The code is ready but discussion is open regarding whether this should be added. |
It could also do with a changelog entry. |
I don't see any reason to reject this giving that there are attempts to call c# code from d. |
@n8sh ping. Address rainers comments. |
283cfaf
to
8008f6f
Compare
6d6a791
to
7d20e09
Compare
@thewilsonator Any objections so far? |
None from me, but it doesn't seem to pass. |
@n8sh the test are not passing, could you rebase? |
7c636d0
to
23dea06
Compare
@thewilsonator the tests have pass, need to add auto merge label to this as I don't have the authority to do so |
Does this work with |
@Geod24 I don't know the answer to that but it works the same as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay in review. A few nits, otherwise LGTM.
Regarding the shared
question, I asked because identity comparison can break in the presence of multiple TypeInfo
, which IIRC can happen when using dynamic loading. But if _d_isbaseof
does it, it should be fine 🤷♂
@@ -101,7 +104,7 @@ int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset) | |||
return false; | |||
} | |||
|
|||
int _d_isbaseof(ClassInfo oc, ClassInfo c) | |||
int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use tail recursion and make this const
, in order to avoid the cast
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not mess with the implementation of _d_isbaseof
in this PR.
@@ -74,7 +77,7 @@ void* _d_dynamic_cast(Object o, ClassInfo c) | |||
return res; | |||
} | |||
|
|||
int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset) | |||
int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto recursion
Ah I found it: #2828 |
Equivalent to C#/Java isAssignableFrom. Naming the method "isAssignableFrom" would be more familiar to people coming from C#/Java but is potentially misleading: "alias this" and overloadable opAssign mean that this would not actually indicate whether values of one type could be assigned to another. Adding qualifiers to rt.cast_ functions.
What is the hold up here? |
The objection time limit is up |
This is equivalent to C#/Java
isAssignableFrom
with the argument swapped with the receiver. Naming the method "isAssignableFrom" would be more familiar to people coming from C#/Java (and I would find it convenient since it's one fewer difference to remember between languages) but is potentially misleading: "alias this" and overloadable opAssign mean that this would not actually indicate whether values of one type could be assigned to another.I used the name "isDerivedFrom" since the phrase "derives from" appears in the D online documentation. Swapping the argument order is not ideal, so if someone can think of a sensible name that would work with the same argument order as "isAssignableFrom" please suggest one.