-
-
Notifications
You must be signed in to change notification settings - Fork 416
Partial fix for issue# 9769. #459
Conversation
bool opEquals(Object lhs, Object rhs); | ||
bool opEquals(T, S)(T lhs, S rhs) | ||
if (is(T == class) && is(S == class) && | ||
is(typeof({bool a = lhs.opEquals(rhs); bool b = rhs.opEquals(lhs);}))) |
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.
How about is(typeof(lhs.opEqual(rhs)) : bool) && is(typeof(rhs.opEquals(lhs)) : bool)
?
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.
opEquals
should never return anything other than bool
on any type.
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.
But I probably should change it so that it specifically checks that the type is exactly bool
rather than that it assigns to bool
.
Hi Kenji (@9rnsr), can you have a look at this too? |
Can we get a DIP for the whole topic? |
@dawgfoto Okay. I fixed the template constraint and added the missing test (good catch, by the way).
Certainly, but that will take some time as it really should include information on how the transition will be done, and that will take some time to sort out. This small piece with But we do need to get the ball rolling on figuring out what changes need to be made for all of this and start getting them made, or it won't be happening for a while, and that much more code will end up breaking as a result. |
One question:
|
#1. I don't think that it was really suggested (and certainly wasn't decided on) that Any class hierarchy would have a base class that was used in their |
@jmdavis OK, I understand. Thanks for quick answer. |
bool opEquals(T, S)(T lhs, S rhs) | ||
if (is(T == class) && is(S == class) && | ||
is(typeof(lhs.opEquals(rhs)) == bool) && | ||
is(typeof(rhs.opEquals(lhs)) == bool)) |
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.
For structs, they have already less restriction for the return type of opEquals
than this.
I think this should be is(typeof(lhs.opEquals(rhs)) : bool) && is(typeof(rhs.opEquals(lhs)) : bool))
.
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.
Then I would strongly argue that structs should be more restrictive rather than making this less restrictive. TDPL specifically says that opEquals
returns bool
, and I don't think that there's a valid reason for it to ever return anything else. We already got rid of equals_t
, which existed solely because D1 had made the mistake of originally defining opEquals
as returning int
. opEquals
should always return bool
.
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 say it's okay to simplify here and just require bool.
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 also agree. Also, because of the way auto and template inferal works, "implicitly convertible to" just isn't that useful:
auto b = (a == b); //Is b a bool, who knows?
void foo(T)(T t);
foo(a == b); //Calls foo!bool ? who knows?
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.
Could this maybe be used for some expression template trickery?
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.
Could this maybe be used for some expression template trickery?
I'm afraid that I don't know what you mean. I'm not familiar with expression templates.
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.
@9rnsr: okay with just requiring bool
?
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.
Ok. I can agree.
I think it's damn straight intolerable that we need to duplicate swaths of real code between object.di and object_.d. Any ideas on how we can fix that? I'm thinking of something along the lines of mixin(import). Speaking of the larger issue, I'm willing to give this a pass as a special base runtime thing; if we figure this is a pattern that regular projects need to follow we should probably change the language. |
D needs better support for hiding implementation details. |
Okay. Updated per the comments, and I also removed the overloads for |
Seems like long gone day. Any fuel in this fire? Okay to close? |
This looks desirable. @jmdavis? I'll close, please reopen if You Are The Chosen One. |
I think that this is very desirable. It's the first step in fixing the problem with I should have pushed for it be merged previously, but I've been very busy, and it fell by the wayside. AFAIK though, it's just as valid now as when I first opened it. |
I just rebased with the latest master, since it's old, and there were no merge conflicts. |
Okay. I'll have to close this temporarily. I think that it has an infinite loop or something in it, since when I run the unit tests, they never finish. I'll have to investigate what's wrong, since there was no problem like this before. |
Yeah, it looks like some screwy stuff is going on with the overload rules right now that results in the fully templatized overload never getting called: |
I commented on the bug report. Also I'm currently working on a new AA implementation, so this comes in time. |
Okay, I think that I have a function signature that works with the new overload rules. Certainly, the unit tests are now passing, whereas they were resulting in infinite recursion before. Regardless, given how we're dealing with |
This makes it so that the global opEquals function is templated. It is therefore now possible for classes to implement opEquals without overiding Object's opEquals method, including giving it different attributes (such as const). However, the hack version of the global opEquals which takes const Objects and casts away const has been left for the moment, and the opEquals on Object has not been touched. At minimum, before the hack version can go away, work will need to be done on the other classes in object_.d to make them handle const properly. Also, the opEquals on Object will probably have to go away before that if we don't want to break code, as it's the only reason that const Objects have been able to be compared before now, and until types stop using Object's opEquals, that's still the only way that they'll be able to be compared. But at least with these changes, it'll be possible for classes to be compared without it if they change their signatures for opEquals to not take Object.
Drat. It looks like the dmd tests are failing even though the druntime tests and phobos tests are fine. I didn't think to run the dmd tests. I'll have to investigate what broke. |
The dmd tests were failing due to the fact that https://d.puremagic.com/issues/show_bug.cgi?id=12537 And all it takes to trigger that is to templatize |
return opEquals(cast()lhs, cast()rhs); | ||
} | ||
|
||
bool opEquals(Object lhs, Object rhs) | ||
private void _testOpEquals(T, U)(bool expected, T lhs, U rhs, size_t line = __LINE__) |
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.
Would it be better to move _testOpEquals
and _testOpEquals2
inside the unittest block? That way it will not be included in a non-unittest build. (Note: if you do this then the private
modifier will need to be removed)
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.
IIRC, templatizing functions inside a unittest block doesn't work, or if it does, you only get to instantiate it once. But the function can be versioned with version(unittest)
easily enough.
Regardless, I need to rebase this and try the workaround proposed in https://issues.dlang.org/show_bug.cgi?id=12537 to see if I can get this working. IIRC, it was working perfectly fine before except for the win32 build thanks to bug# 12537. But without that bug being fixed or having a workaround, it was pretty much dead in the water.
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.
Maybe templates inside unittest blocks has been fixed because I've already rebased this commit and made that change and it seems to work for me (https://github.com/D-Programming-Language/druntime/pull/1087/files#diff-7eac7eb46e31907f148813e793155274R197). The DMD tests are still failing, but I could try to find a workaround as well. I'll spend some time on it today and see what I can figure out. I'll let you know if I make any progress.
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.
It looks like there's some sort of issue when alias this comes into play. It's probably a compiler bug, but it'll need to be isolated so that we can be sure and report it appropriately - though if it is a compiler bug, it's likely another blocker. :(
I have an AA implementation and promised myself to be disciplined and with with So where are you guys with this proposal now? Is |
@mleise The current attempt at templatizing But it's gotten almost no attention, so it hasn't been merged. Now, that still leaves plenty of other work that needs to be done towards being able to actually remove |
@jmdavis I encourage you to open threads on the forum about neglected PRs so as to bring attention to them. Thanks! |
@jmdavis Thanks for the update. |
This makes it so that the global opEquals function is templated. It is
therefore now possible for classes to implement opEquals without
overiding Object's opEquals method, including giving it different
attributes (such as const).
However, the hack version of the global opEquals which takes const
Objects and casts away const has been left for the moment, and the
opEquals on Object has not been touched. At minimum, before the hack
version can go away, work will need to be done on the other classes in
object_.d to make them handle const properly. Also, the opEquals on
Object will probably have to go away before that if we don't want to
break code, as it's the only reason that const Objects have been able to
be compared before now, and until types stop using Object's opEquals,
that's still the only way that they'll be able to be compared. But at
least with these changes, it'll be possible for classes to be compared
without it if they change their signatures for opEquals to not take
Object.
http://d.puremagic.com/issues/show_bug.cgi?id=9769