Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stdlib] Add Variant.is_type_supported method. #4057

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

rd4com
Copy link
Contributor

@rd4com rd4com commented Mar 5, 2025

Hello,
this commit adds a method to check if a Variant supports a type, for example:

def MyFunction(mut arg: Variant):
    if arg.is_type_supported[Float64]():
        arg = Float64(1.5)

def main():
    var x = Variant[Int, Float64](1)
    MyFunction(x)
    if x.isa[Float64]():
        print(x[Float64]) # 1.5

@rd4com rd4com force-pushed the add_variant_method_is_type_supported branch 2 times, most recently from c771a24 to a43a1fd Compare March 5, 2025 20:45
Example:

```mojo
def MyFunction(mut arg: Variant):
Copy link
Contributor

@gryznar gryznar Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function name in Mojo should be snake_cased. I see also more reasons for having it as fn

Copy link
Contributor

@gryznar gryznar Mar 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rd4com, still relevant. Maybe we can also choose more self explanatory names for arg and func which illustrate usage example better than my_function and arg?


Example:
```mojo
def MyFunction(mut arg: Variant):
Copy link
Contributor

@gryznar gryznar Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same what above

Copy link
Collaborator

@JoeLoser JoeLoser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me understand a bit more about why this is useful?

Note that in C++, we have something similar: for checking if any of the non-active types match the asked type (https://en.cppreference.com/w/cpp/utility/variant/holds_alternative). In mp11, for type list, we have boost::mp11::mp_contains if you're familiar with that.

@soraros
Copy link
Contributor

soraros commented Mar 6, 2025

It can be used in _get_ptr. If the team finds this patch useful, we should refactor that part a bit.

@rd4com
Copy link
Contributor Author

rd4com commented Mar 6, 2025

Hello, thanks for the reviews 👍

Here is the reasoning:

If arg were Variant[Int, Bool], it would be less useful there,
because the function only takes *Ts = (Int, Bool)
(the programmer that creates the function knows that arg conform to this,
and just assign an Int() to it)

If arg is just Variant, mojo auto-parametrize the function🔥 :

 def MyFunction(mut arg: Variant)

and we can take any Variant, like if we would:

 def MyFunction[*Ts: CollectionElement](mut arg: Variant[*Ts])

So from within that function, we have to check if the variant support a type,
before mutating the arg, for example 👍

The usecase is pretty narrow,
we might need this later for implicit conversion of arg:T to Self in Variant.__init__ too
(currently, every CollectionElement implicitly comes in and is constrained during __init__ )

@gryznar
Copy link
Contributor

gryznar commented Mar 6, 2025

What's the case for naming function "MyFunction" (like struct) and not "my_function" and using def instead of fn?

my_function in this case is also tatally abstract and does not bring any value for understanding

@rd4com
Copy link
Contributor Author

rd4com commented Mar 6, 2025

Yep, thanks for reviewing and working together to refine the pr @gryznar ❤️‍🔥 🤝 ,
just waiting for the overall pr idea to be welcomed first,
so that i don't implement the reviews to close the PR later 👍

@gryznar
Copy link
Contributor

gryznar commented Mar 6, 2025

Yeah, I see. Sorry for reminding, but this hurts my eyes 😂

Copy link
Contributor

@martinvuyk martinvuyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I understand the need for this functionality.

But maybe we can try and make it more obvious at first glance

    fn can_be[T: CollectionElement]() -> Bool:
        """Check if a type can be stored inside the `Variant`.

But I think this would be even better once we have a mechanism to use __contains__ in parameter space:

if Int in Variant[Int, String]:
    print("can be an Int")

it would only need VariadicPack to have a __contains__ for types.

I'll play around with the idea and see if we have the type system features or if I manage to force it.

@gryznar
Copy link
Contributor

gryznar commented Mar 7, 2025

I like naming and future enhancment from @martinvuyk . In his example it is self explanatory

Copy link
Collaborator

@JoeLoser JoeLoser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM once the minor style comments are addressed. Ping me once they're addressed and I'm happy to sync this in and land it.

Thank you!

fn is_type_supported[T: CollectionElement]() -> Bool:
"""Check if a type can be used by the `Variant`.

Example:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion Move this after the API docs for parameter/returns sections for consistency with other Mojo code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, implemented the suggestion 👍

But had to add:

For example, the Variant[Int, Bool] permits Int and Bool.

So that it ends with an . 👍

But it does convey too the idea that you suggested in the other review,
WDYT?

@JoeLoser JoeLoser self-assigned this Mar 18, 2025
@rd4com rd4com requested a review from a team as a code owner March 19, 2025 23:40
rd4com and others added 6 commits March 20, 2025 01:07
Hello,
this commit adds a method to check if a `Variant` supports a type,
for example:
```mojo
def MyFunction(mut arg: Variant):
    if arg.is_type_supported[Float64]():
        arg = Float64(1.5)

def main():
    var x = Variant[Int, Float64](1)
    MyFunction(x)
    if x.isa[Float64]():
        print(x[Float64]) # 1.5
```

Signed-off-by: rd4com <[email protected]>
Co-authored-by: Joe Loser <[email protected]>
Signed-off-by: rd4com <[email protected]>
Co-authored-by: Joe Loser <[email protected]>
Signed-off-by: rd4com <[email protected]>
Co-authored-by: Joe Loser <[email protected]>
Signed-off-by: rd4com <[email protected]>
@rd4com rd4com force-pushed the add_variant_method_is_type_supported branch from 7550737 to fedd86f Compare March 20, 2025 00:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants