chore: remove as_any from ExecutionPlan#21263
chore: remove as_any from ExecutionPlan#21263timsaucer wants to merge 16 commits intoapache:mainfrom
Conversation
When upcasting to `&dyn Any` from an `Arc<dyn Trait>`, using `(&plan as &dyn Any)` gives an Any for the Arc, not the inner trait object. Document that `.as_ref() as &dyn Any` is required instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alamb
left a comment
There was a problem hiding this comment.
Thanks @timsaucer
The basic idea here is great -- however, this pattern of calling .as_any().downcast_ref()... is super common over the codebase and changing it to (scan.as_ref() as &dyn Any) is pretty 🤮
So in other words, I am not sure this PR is a good as it makes the code harder to read (at least for me). Is there anyway to avoid this (like maybe keeping the as_any as a default impl perhaps?)
|
|
||
| fn f_down(&mut self, node: &'n Self::Node) -> Result<TreeNodeRecursion> { | ||
| if let Some(exec) = node.as_any().downcast_ref::<AggregateExec>() { | ||
| if let Some(exec) = |
There was a problem hiding this comment.
I will be honest that the previous syntax is quite a bit nicer 🤔
There was a problem hiding this comment.
You're right. Moved to draft, at least for the time being.
There was a problem hiding this comment.
Thank you for the push back @alamb. If you take another look, I think we now have a very clean downcast. I also updated the UDFs at the same time and applied the pattern. They have many fewer places where we do downcast_ref or is so it wasn't so noticeable.
Adds an inherent impl on `dyn ExecutionPlan` providing `downcast_ref<T>` and `is<T>` methods, so callers can write `plan.downcast_ref::<MyExec>()` instead of `(plan.as_ref() as &dyn Any).downcast_ref::<MyExec>()`. Both methods work correctly whether `plan` is `&dyn ExecutionPlan` or `Arc<dyn ExecutionPlan>` via auto-deref. Updates call sites in tests and the 54.0.0 upgrade guide accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l, WindowUDFImpl Mirrors the same inherent impl pattern added for dyn ExecutionPlan. Callers can now write `udf.downcast_ref::<MyUdf>()` instead of `(udf.as_ref() as &dyn Any).downcast_ref::<MyUdf>()`, and it works correctly whether the value is a bare reference or behind an Arc. Updates the 54.0.0 upgrade guide accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces all `(plan.as_ref() as &dyn Any).downcast_ref::<T>()` and `(plan as &dyn Any).is::<T>()` call sites with the new inherent methods `plan.downcast_ref::<T>()` and `plan.is::<T>()` added to `dyn ExecutionPlan`. Also removes the now-unused `use std::any::Any` imports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces remaining `(x.as_ref() as &dyn Any).downcast_ref::<T>()` and `(x as &dyn std::any::Any).downcast_ref::<T>()` patterns with the new inherent methods on `dyn ExecutionPlan`. Also cleans up redundant `.as_ref()` calls before `.downcast_ref()` / `.is()` on Arc values, and simplifies `.downcast_ref::<T>().is_some()` to `.is::<T>()` where applicable. Removes now-unused `std::any::Any` imports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes two missed ExecutionPlan patterns: - topk_repartition.rs: remove intermediate as &dyn Any variable - limit_pushdown.rs: remove intermediate as &dyn Any variable Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces `(func.inner().as_ref() as &dyn Any).downcast_ref::<T>()` and `.is::<T>()` call sites with the new inherent methods on `dyn ScalarUDFImpl`. Also simplifies `.downcast_ref::<T>().is_some()` to `.is::<T>()` and removes now-unused `std::any::Any` imports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tterns Replaces `(udaf.inner().as_ref() as &dyn Any).downcast_ref::<T>()` and `.is::<T>()` call sites with the new inherent methods on `dyn AggregateUDFImpl`. Removes now-unused `std::any::Any` imports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces `(udwf.inner().as_ref() as &dyn Any).downcast_ref::<T>()` and `.is::<T>()` call sites with the new inherent methods on `dyn WindowUDFImpl`. Removes now-unused `std::any::Any` imports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| pub fn try_downcast_func<T>(expr: &dyn PhysicalExpr) -> Option<&ScalarFunctionExpr> | ||
| where | ||
| T: 'static, | ||
| T: ScalarUDFImpl, |
There was a problem hiding this comment.
This may look like it's changing behavior because we're changing the generic but if you look at the usage, the downcast must be to a ScalarUDFImpl so this is valid IMO.
…pplied it to expressions
Which issue does this PR close?
This is a follow on to #20812 and #21209 but treats
ExecutionPlan.Rationale for this change
This PR reduces the amount of boilerplate code that users need to write for execution plans.
What changes are included in this PR?
Now that we have trait upcasting since rust 1.86, we no longer need every implementation of these functions to have the as_any function that returns &self. This PR makes Any an supertrait and makes the appropriate casts when necessary.
I have also implemented functions
isanddowncast_refon the trait object for ExecutionPlan and applied this same pattern to the udf, udaf, and udwf implementations. This allows for a clean downcasting and type checking.Are these changes tested?
Existing unit tests.
Are there any user-facing changes?
Yes, the users simply need to remove the
as_anyfunction. The upgrade guide is updated.