[Proposal] Customizable Type Merging in Mojo

This is a discussion thread for the following proposal from @clattner: max/mojo/proposals/custom-type-merging.md at main · modular/max · GitHub

1 Like

Will __merge_with__ have a defined ordering, or will the compiler try flipping it if one parameter ordering doesn’t exist? I could see this causing a lot of dependency loops unless there’s some kind of “order-agnostic” behavior.

Easy™, just make sure all the __merge_with__ rules form a lattice.

Consider a merge between two values of type A and B. The compiler will invoke mergewith on A (with the type of B) and mergewith on B (with the type of A) and then require them to agree. If not, it will throw an error.

Doesn’t that force dependency cycles between libraries?

For example, if A is a runtime arbitrary precision float from the Mojo ecosystem, and B is Float32, one would expect that the Float32 can promote to the arbitrary precision float. For those checks to match, that means that the stdlib now needs to depend on the library containing type A in order to pull in the type.

To me, feels like the absence of A.__merge_with__[B]() -> B in the presence of a B.__merge_with__[A]() -> A should indicate that B should be converted to A. I agree that if both exist and they can’t agree on which type to promote to, then there should be an error thrown.

It can, but that is better solved with a feature like “extensions”, which we agree we want to add someday. You can read about the feature in Swift for example (another example intro).

In your specific example though, this won’t come up. If Float32 impl converts to your APFloat type, then you don’t need to use this feature at all.

Thanks for the clarification! If extensions are a near-term feature then I don’t have any issues with this.

Implemented in f40b470.

3 Likes

Hi Owen,

I implemented this yesterday and added the algorithm pseudo code to the proposal doc (look for an update in the next nightly). The final design takes your suggestion:

To me, feels like the absence of A.__merge_with__[B]() -> B in the presence of a B.__merge_with__[A]() -> A should indicate that B should be converted to A. I agree that if both exist and they can’t agree on which type to promote to, then there should be an error thrown.

Yep, this is how it works. If you implement B.__merge_with__[A]() -> A then things will “just work” because the A side of the branch doesn’t need to be converted. You can even implement B.__merge_with__[A]() -> C so long as A implicitly converts to C or you implement A.__merge_with__[B]() -> C to make the behavior merge specific.

Please give it a try and let me know if you have any additional questions!

1 Like

Thanks for the detailed docs! It will be interesting to compare this to Rust’s Into/From trait pair which has similar functionality. Being able to also make use of implicit conversions is a nice quality of life feature as well!

2 Likes