Proposal: Init Unification

What is the reason for requiring 2 different keyword-only arguments?

  1. Mojo already has the semantics: When you have 2 identical functions, one taking ref and one taking var, the compiler considers those semantically equivalent and will try to choose the var variant:
fn __iter__(self):... # non-consuming iterator
fn __iter__(var self):... # consuming iterator

This is not true for 2 functions with different keyword-only args, as they are considered 2 different functions semantically.

By making __moveinit__ and __copyinit__ into overloads of __init__ where the only difference is ref vs var, we are telling the compiler that these 2 functions are semantically equivalent and it is free to optimize and choose the overload.

# regular argument
fn __init__(out self, other: Self) # copy
fn __init__(out self, deinit other: Self) # move

# keyword-only argument - same keyword arg name.
fn __init__(out self, *, other: Self) # copy
fn __init__(out self, *, deinit other: Self) # move
  1. Another advantage is being able to easily explain the copy + del -> move optimization: since it is the same function which only differs by ref vs var, the compiler is allowed to optimize: self.__init__() + self^.__del__() -> self^.__init__().

In the future, it could be expanded to optimize other similar patterns:

self.__iter__() + self^.__del__() -> self^.__iter__()

The generalized pattern:

my_func(a, b) + a^.__del__() + b^.__del__() -> my_func(a^, b^)

But if we require different keyword-only args, then it will have to be special-cased since it is not considered the same function semantically by the compiler:

Self.__init__(copy=a) + a^.__del__() -> Self^.__init__(take=a^)

2 Likes

I like this idea of not using kwargs for overload resolution of copy /move.

From the proposal: “The keyword only approach ensures easier disambiguation within the overload group.”

One solution to this would be to use kwargs for an init function with the same arguments that should not be a copy/move init (e.g. in String fn __init__(out self, *, uppercased: Self)).

Hello, i love this unification,
makes it really easy to learn and think, imo :heart_on_fire:

1 Like

On keyword arguments, we’re looking at taking one step at a time. Unifying the names is a big step in the right direction. It may be that we don’t need keywords on one or both of them, but starting out unambiguous-for-sure is a conservative approach.

1 Like

Agree. But I did a scan on the modular GitHub repo and could not find a single __init__ function that would overlap with the new __init__ function arguments without keywords. Not sure if ambiguity is really an issue here.

I’m pleasantly surprised that Erica is now a Mojician.