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

[BUG] Eager copying of struct even though no mutation occurs #2416

Closed
Brian-M-J opened this issue Apr 26, 2024 · 5 comments
Closed

[BUG] Eager copying of struct even though no mutation occurs #2416

Brian-M-J opened this issue Apr 26, 2024 · 5 comments
Labels
bug Something isn't working mojo Issues that are related to mojo mojo-repo Tag all issues with this label

Comments

@Brian-M-J
Copy link

Bug description

Mojo aims to provide copy-on-write semantics, so programmers do not have to pay a price to reassign data if no mutation occurs. However, in the snippet linked below, even though no mutation is performed, the value of demo_obj_1 is copied eagerly as demonstrated by the output:

Called constructor for DemoStruct(List(1, 2, 3, 4, 5))
Called copy constructor for DemoStruct(List(1, 2, 3, 4, 5))
DemoStruct(List(1, 2, 3, 4, 5))
Calling destructor for DemoStruct(List(1, 2, 3, 4, 5))
DemoStruct(List(1, 2, 3, 4, 5))
Calling destructor for DemoStruct(List(1, 2, 3, 4, 5))

This introduces unnecessary run-time costs into the program.

Steps to reproduce

Run this snippet in the playground: https://gist.github.com/modularbot/6aed759930420cd70f38795dbcb874fe

System information

The Mojo playground as of 26-04-2024
@Brian-M-J Brian-M-J added bug Something isn't working mojo Issues that are related to mojo labels Apr 26, 2024
@ematejska ematejska added the mojo-repo Tag all issues with this label label Apr 29, 2024
Copy link
Collaborator

This is working as intended per @jpamer

@ematejska ematejska closed this as not planned Won't fix, can't repro, duplicate, stale May 1, 2024
@Brian-M-J
Copy link
Author

This is working as intended per @jpamer

I don't fully understand what you mean. It's mentioned that:

Because String implements a copy constructor, it's able to be moved into bar and leave behind a copy. Under the hood this is still passing by reference for maximum efficiency, it'll only create a copy if foo is mutated.

...but as demonstrated here, a copy is in fact created as demonstrated by the output (even though no mutation occurs):

Called __init__ for DemoStruct(String("foo"))
Called __copyinit__ for DemoStruct(String("foo"))
Called __del__ for DemoStruct(String("foo"))
Called bar with argument: DemoStruct(String("foo"))
DemoStruct(String("foo"))
Called __del__ for DemoStruct(String("foo"))

__copyinit__ is in fact called, and __del__ is called twice. This seems to contradict the statement in the blog post that Mojo enforces copy-on-write semantics.

I say "Mojo enforces COW" and not "String enforces COW" because it's not like String has some special magic code to enforce COW. Its __copyinit__ just calls List's __copyinit__, which is nothing special. So I can only assume it's the compiler that reasons about mutation and eliminates copies as necessary. Type authors don't have to worry about it.

@soraros
Copy link
Contributor

soraros commented May 2, 2024

Mojo enforces COW

Citation needed.

@Brian-M-J
Copy link
Author

Brian-M-J commented May 2, 2024

Mojo enforces COW

Citation needed.

I already gave it:

it'll only create a copy if foo is mutated

it's not like String has some special magic code to enforce COW. Its __copyinit__ just calls List's __copyinit__, which is nothing special. So I can only assume it's the compiler that reasons about mutation and eliminates copies as necessary. Type authors don't have to worry about it.

@soraros
Copy link
Contributor

soraros commented May 2, 2024

I think you misunderstood what Jack wrote in the blog, he was talking about owned argument and move. String doesn't have COW semantics, and COW is most certainly not enforced by the language. I guess we could expect the compiler to eliminate more unnecessary copy, but I don't think that optimisation is/can be guaranteed (consider when __copyinit__ has other side effect).

fn main():
  var a: String = "a"
  var b = a  # a copy is made here

  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working mojo Issues that are related to mojo mojo-repo Tag all issues with this label
Projects
None yet
Development

No branches or pull requests

3 participants