[stdlib] Add filter_types to variadic#5714
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
e018854 to
5a6f21a
Compare
BEGIN_PUBLIC [Stdlib] Add variadic type filtering utilities Adds three new compile-time utilities to `Variadic` for filtering type sequences: - `exclude_type[*types, type=T]` - Remove a single type from a variadic - `keep_types[*types, keep_types=...]` - Keep only specified types - `exclude_types[*types, exclude_types=...]` - Remove multiple types These utilities enable ergonomic manipulation of `Variant` types and other variadic type sequences at compile time. Example usage: ```mojo comptime Filtered = Variadic.exclude_type[*Variant[Int, String, Bool].Ts, type=Int] comptime NewVariant = Variant[*Filtered] // Variant[String, Bool] ``` Includes comprehensive tests demonstrating all three filtering modes and chaining behavior. END_PUBLIC
BEGIN_PUBLIC [Stdlib] Improve variadic filtering API and add comprehensive tests Updates the variadic filtering utilities to use variadic parameters for a more ergonomic API, and adds comprehensive test coverage: API improvements: - Changed from `element_types=...` to `*element_types` variadic parameters - Renamed `Trait` to `T` to match stdlib conventions (consistent with `Variadic.types`, `Variadic.slice_types`, etc.) - Simplified parameter names: `type` instead of `exclude_type` for single exclusions Usage is now more concise: ```mojo // Before Variadic.exclude_type[exclude_type=Int, element_types=MyTypes] // After Variadic.exclude_type[*MyTypes, type=Int] ``` Tests added: - `test_exclude_type()` - Remove a single type from a variadic - `test_keep_types()` - Keep only specified types - `test_exclude_types()` - Remove multiple types - `test_filtering_chained()` - Chain multiple filtering operations END_PUBLIC
BEGIN_PUBLIC
[Stdlib] Replace specialized filters with generic filter_types
Replaces the three specialized filtering functions (`exclude_type`, `keep_types`,
`exclude_types`) with a single generic `filter_types` function that accepts a
user-defined predicate.
Implementation:
- Added `_TypePredicateGenerator[T]` - Generator type for predicates that take
a type and return Bool
- Added `_FilterReducer` - Generic reducer that filters based on any predicate
- Added `Variadic.filter_types[*types, predicate=...]` - Public API
This design is more flexible and composable than having separate specialized
functions. Users can write any filtering logic they need:
```mojo
# Exclude a single type
comptime IsNotInt[Type: Movable] = not _type_is_eq[Type, Int]()
comptime Filtered = Variadic.filter_types[*MyTypes, predicate=IsNotInt]
# Keep only specific types
comptime IsNumeric[Type: Movable] = (
_type_is_eq[Type, Int]() or _type_is_eq[Type, Float64]()
)
comptime Numeric = Variadic.filter_types[*MyTypes, predicate=IsNumeric]
# Exclude multiple types
comptime NotIntOrBool[Type: Movable] = (
not _type_is_eq[Type, Int]() and not _type_is_eq[Type, Bool]()
)
comptime Filtered = Variadic.filter_types[*MyTypes, predicate=NotIntOrBool]
```
Tests include filtering to exclude single types, keep only specific types,
exclude multiple types, and chaining filter operations.
END_PUBLIC
filter_types to variadic
|
@lsh Idea: can we make them conditional methods on |
JoeLoser
left a comment
There was a problem hiding this comment.
Thanks for this contribution, @saviorand! Filtering types is a useful ergonomic improvement for working with variadics. Before merging, I think we should resolve @soraros's #5714 (comment) about whether this should be a conditional method on Variadic itself. The current API:
comptime step2 = Variadic.filter_types[*step1, predicate=IsNotInt]vs potentially:
comptime step2 = step1.filter[predicate=IsNotInt]@lsh - could you weigh in on the preferred API direction?
Overall this is solid work - just want to nail down the API design before merging. Thanks again for the contribution!
| @@ -305,6 +305,55 @@ def test_map_types_to_types(): | |||
| assert_true(_type_is_eq[variadic[1], String]()) | |||
|
|
|||
|
|
|||
There was a problem hiding this comment.
Suggestion Can you add a test for filtering to an empty result (a predicate that matches nothing) to ensure that edge case is handled correctly.
|
@soraros I think that would be really nice, but there are some tradeoffs to consider. I would expect an API kind of like VariadicIter[*elts].map[mapper].filter[pred].resultthough this means that every use now needs to explicitly pull the elements out at the end. I think another important distinction is that this API would not be lazily evaluated. I'm still open to exploring that API though! |
|
@lsh Yea, and we can of course land and iterate. |
|
@JoeLoser @soraros thanks for the feedback! I definitely like the idea. |
|
I'd say we can land this and write the abstraction after. I have an idea I'll try out |
|
!sync |
|
This is super cool, nice work! |
|
!sync |
|
✅🟣 This contribution has been merged 🟣✅ Your pull request has been merged to the internal upstream Mojo sources. It will be reflected here in the Mojo repository on the main branch during the next Mojo nightly release, typically within the next 24-48 hours. We use Copybara to merge external contributions, click here to learn more. |
|
Landed in 050840a! Thank you for your contribution 🎉 |
A few convenience functions to make it easier to work with variadics