M
Modular•13mo ago
tac

__moveinit__ and __del__

When the __del__ method is not implemented, the __moveinit__ method is less likely to be invoked. Why is this the case? Consider the following example code:
struct Pair:
var x: Int
var y: Int

fn __init__(inout self, x: Int, y: Int):
print("Running init")
self.x = x
self.y = y

fn __moveinit__(inout self, owned existing: Self):
print("move init")
self.x = existing.x
self.y = existing.x

fn __copyinit__(inout self, existing: Self):
print("copy init")
self.x = existing.x
self.y = existing.y

fn copy(owned pair: Pair) -> Pair:
return pair

fn main():
let p = Pair(1, 2)
let moved = copy(p^)
let moved2 = moved^
struct Pair:
var x: Int
var y: Int

fn __init__(inout self, x: Int, y: Int):
print("Running init")
self.x = x
self.y = y

fn __moveinit__(inout self, owned existing: Self):
print("move init")
self.x = existing.x
self.y = existing.x

fn __copyinit__(inout self, existing: Self):
print("copy init")
self.x = existing.x
self.y = existing.y

fn copy(owned pair: Pair) -> Pair:
return pair

fn main():
let p = Pair(1, 2)
let moved = copy(p^)
let moved2 = moved^
On execution, the output is:
copy init
move init
copy init
move init
However, when we include the __del__ method as follows:
struct Pair:
# omitted
fn __del__(owned self):
print("deleted")

fn copy(owned pair: Pair) -> Pair:
return pair

fn main():
let p = Pair(1, 2)
let moved = copy(p^)
let moved2 = moved^
struct Pair:
# omitted
fn __del__(owned self):
print("deleted")

fn copy(owned pair: Pair) -> Pair:
return pair

fn main():
let p = Pair(1, 2)
let moved = copy(p^)
let moved2 = moved^
The output changes to:
move init
move init
deleted
move init
move init
deleted
The presence or absence of the __del__ method impacts the sequence of method calls __copyinit__ and __moveinit__, potentially affecting the performance. Why does this occur?
7 Replies
JIMC
JIMC•13mo ago
Because move init is always favored over copy init
tac
tac•13mo ago
I know moveinit is preferred but why does copyinit run when del is unimplemented?
Jack Clayton
Jack Clayton•13mo ago
From the programming manual:
One additional note is that while the Mojo compiler provides good predictability and control, it is also very sophisticated. It reserves the right to eliminate temporaries and the corresponding copy/move operations. If this is inappropriate for your type, you should use explicit methods like copy() instead of the dunder methods.
One additional note is that while the Mojo compiler provides good predictability and control, it is also very sophisticated. It reserves the right to eliminate temporaries and the corresponding copy/move operations. If this is inappropriate for your type, you should use explicit methods like copy() instead of the dunder methods.
I think it's because the compiler is smart enough to realize that copying would be more efficient with that type, but having custom __del__ behaviour might disallow that? Just speculation but that's my guess
Chris Lattner
Chris Lattner•12mo ago
+1, Mojo assumes/expects that you're implementing well behaved types where "copy + del" is equivalent to "move" This is true for "almost everything", and knowing this allows the compiler to perform optimizations that (e.g.) C++ and Rust can't do. The flip side of this is that if you implement a type where these properties aren't true for some reason that you'll have a bad day 🙂 The solution to that is to just play by the rules: you can implement your own copy and move methods (or come up with other exciting verbs 🙂 if you need to, and the compiler won't touch them If you're familiar with C++ and care about performance you might see code litered with std::move operations etc, even for basic types like std::string and std::vector. Mojo allows you to relax a bit because it has your back and will generally "do the right thing" without you micromanaging it. That said, if you're a control freak, then have at it with ^ etc.
ModularBot
ModularBot•12mo ago
Congrats @Chris Lattner, you just advanced to level 5!
Chris Lattner
Chris Lattner•12mo ago
Does that make sense to you?
Sarctiann
Sarctiann•12mo ago
I love witnessing the creation of this language. I love seeing so many twists and turns. It is beautiful to see how experience (yours haha) allows one to participate in both the basic and the complex at the same time. Holding the necessary focus to achieve the goal of having a language with the most beautiful high-level syntax, and not only "the possibility of interacting with low level" but making it competent in comparison with C++ or Rust, which already has its good. deserved prestige. Thank you @Chris Lattner, @Jack Clayton and the entire Team for doing this. 🙂
Want results from more Discord servers?
Add your server