> I hope this change makes you happy!
It most certainly does! I'm a huge proponent of code cleanup and organization,
and this looks like a beautiful example of those.
> Finally, the root class, WidgetEvent, has As*Event class. The "*"
> doesn't include the prefix. I.e., for WidgetMouseEvent, the method name
> is WidgetEvent::AsMouseEvent(). This returns the pointer of the instance
> only when the instance is the class or its derived class. Otherwise,
> returns nullptr.
>
> E.g., WidgetDragEvent is defines as:
>
> WidgetEvent
> +- WidgetGUIEvent
> +- WidgetInputEvent
> +- WidgetMouseEventBase
> +- WidgetMouseEvent
> +- WidgetDragEvent
>
> If an instance is WidgetDragEvent, AsGUIEvent(), AsInputEvent(),
> AsMouseEventBase(), AsMouseEvent() and AsDragEvent() returns its
> pointer. The other As*Event() methods return nullptr.
>
> You should not use static_cast for Widget*Event and Internal*Event
> anymore because it may cause wrong casting bug with some mistakes
> (actually, there was such bug!).
I do have a question about this part. It seems that there are 3 distinct
situations where you might be casting pointers around in this inheritance tree.
1. Downcasting to a most-derived class (a leaf in the tree)
2. Downcasting to a non-leaf-node (i.e. a class that is not a most-derived
class)
3. Upcasting
For 1 and 3, I believe we can accomplish these safely using static_cast. For 3,
this is always true. For 1, I believe that the static_cast is safe as long as
you have checked the |eventStructType| member.
That is, the following should be safe:
WidgetWheelEvent *event1 = nullptr;
// Assume that aEvent is a WidgetEvent* that we received from elsewhere
if (NS_WHEEL_EVENT == aEvent->eventStructType) {
// We can now trust this cast
event1 = static_cast<WidgetWheelEvent*>(aEvent);
}
For 2, the |eventStructType| member by itself doesn't give us enough
information to know if a static_cast is safe (you'd have to keep a map of
most-derived classes to all of their parent classes... yuck). In these cases, I
feel that the As*Event functions are providing the same functionality as
dynamic_cast.
That is, the following are equivalent:
// Assume that aEvent is a WidgetEvent* that we received from elsewhere
WidgetInputEvent *event2 = aEvent->AsWheelEvent();
WidgetInputEvent *event3 = dynamic_cast<WidgetInputEvent*>(aEvent);
// At this point, |event2 == event3| should be true
So my question is this; is it preferable to keep the As*Event functions, or to
use regular C++ casts to accomplish the same behavior? We could use static_cast
unconditionally for upcasts, static_cast with a check of |eventStructType| for
downcasts to most-derived event types, and dynamic_cast for downcasts to
non-most-derived event types.
I don't think there would be a meaningful performance impact (case 3 would be
faster, case 2 would be a dynamic cast vs a virtual function call, case 1 would
be a branch vs a virtual function call), but I think it would clean up our
event types even further (again, great work cleaning them up this much!) and it
takes advantage of built-in support from the language to aid us in managing our
event types.
_______________________________________________
dev-platform mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-platform