modularml / mojo

The Mojo Programming Language
https://docs.modular.com/mojo
Other
22.36k stars 2.55k forks source link

[Feature Request] Initializers for implicit conversions through traits for builtin types e.g. String with Stringable, Int with Intable #1398

Open theopomies opened 7 months ago

theopomies commented 7 months ago

Review Mojo's priorities

What is your request?

I suggest the addition of new initializers for builtin types that take in argument a type implementing a trait resulting in said builtin type when applicable, such as String with Stringable and Int with Intable.

Here is an example

@value
struct MyString(Stringable):
    fn __str__(self) -> String:
        return "MyString"

fn main():
    # let s: String = MyString() # Error: "cannot implicitly convert 'MyString' value to 'String' in 'let' initializer"
    # Currently you need to do
    let s = str(MyString())

    # With the proposed improvement we get that working
    let ss: ImprovedString = MyString()

# I suggest we add to the String's initializer the following
@value
struct ImprovedString:
    # ...

    var s: String  # I'll use composition here but pretend my whole struct is the STD type

    # fn __init__(inout self, other: Stringable): # Doesn't work yet, maybe in the future
    fn __init__[T: Stringable](inout self, other: T):
        self.s = str(other)

    # ...

# Note: The same could be done for the Intable trait, and any related traits

What is your motivation for this change?

This changes allows for a better developper experience where the language behaves like we expect after reading #type-annotations and #implicit-type-conversion of the Mojo Manual

Any other details?

No response

mojo-for-ai commented 7 months ago

Man, you are a genius, thanks for suggesting this

soraros commented 7 months ago

-1 for allowing more implicit conversion in general. See also #1310. -1e10 for adding more implicit conversions to String. Actually, I vote to remove them all, except for StringLiteral and maybe StringRef.

theopomies commented 7 months ago

-1 for allowing more implicit conversion in general. See also #1310.

-1e10 for adding more implicit conversions to String. Actually, I vote to remove them all, except for StringLiteral and maybe StringRef.

Coming from Rust I am generally not favorable for implicit conversions, however the language promotes it in its documentation, and I'm more favorable for a language that behaves as expected than I'm against implicit conversions...

As stated in the request, I don't want more implicit conversions, if any, I merely suggest that the mentioned links in the doc made me think it would behave as proposed in the suggestion.

soraros commented 7 months ago

@theopomies Imagine being able to pass a string comparator to a function that sorts floats because Stringable, or the other way around because Intable, and the compiler can't even warn you about it. Even passing an integer comparator to sort[Float] is dangerous (wrong semantics), because NaNs.

theopomies commented 7 months ago

@soraros sure, but once again I merely suggest that if the language goes the way of implicit conversions as it already is, I believe the behavior I describe should be implemented

This is not a matter of wanting more conversions, but more like a philosophy that the language should behave like we expect it should with the principle of least surprise. And with the described implicit conversions of the documentation, I expected it to behave like that.

If it were about what I prefer I would also be more pedantic like you and remove implicit conversions completely.

But we must also remember that the philosophy is to have a language somewhat accessible like Python...

theopomies commented 7 months ago

Note I didn't know about #1310 at the time of writing If the language goes forward with removing implicit conversions or making them more explicit, which I'm highly in favor of, this feature request doesn't make sense anymore

soraros commented 7 months ago

What you are suggesting is change to the stdlib(S), and not the language(L), right? Let's tell them apart:

  1. Being able to use IC - L
  2. Constructor automatically become candidate for IC - L
  3. Some std types using IC - S
    1. Some of these usages are more legit than others, so hopefully we can remove some of them (my opinion, not fact) - S

Note that given 2., every time we add a new constructor to a stdlib type, we necessarily also give it more ICs possibilities. We might want more conversion, but not necessarily implicit ones. Also because of 2., S and L are intertwined. Or, at least I think, the design of S is limited by L.

Also in my opinion, our options are:

In summary, my categorisation of this feature request is: (mis)using a incomplete language feature (2.) to make the stdlib consistent with some of its capabilities (3.) that are only there because the language is incomplete. This part is of course just my opinion, we don't have to reach any consensus; I hope we can agree though, is because it's not a language change, at least it can wait.