Skip to content

clarify spec/implementation for let: move or copy? #13140

@timotheecour

Description

@timotheecour

should let always move, always copy, or sometimes move and sometimes copy (and in which conditions, and for which --gc flags)?
should an object passing by let argument make a move or copy?

Clarifying this matters as APIs may make assumptions that may not reflect current/future reality and break at some point.

This is not clear right now and the current compiler at least sometimes makes a move instead of a copy.
If --newruntime or --gc:arc is used, whether a move or copy is used is currently obscure

my intuition was: for let b = expr(a), if nothing can modify a after that statement, then make a move, else make a copy. However that's not what I'm observing (neither with --gc:arc nor without that flag).

Example

this came up here: #13116 (comment)

type Foo = distinct string
type Bar = ref object
  foo: Foo

proc main(a: Bar)=
  let b = a.foo
  doAssert cast[int](a.foo.string[0].unsafeAddr) == cast[int](b.string[0].unsafeAddr)

let a = Bar(foo: "abc".Foo)
main(a)

it seems to me in this case at least that the move is safe, so the assert should (and in fact does) pass, but in #13116 (comment) @Araq says:

That's a bug, finally addressed in --gc:arc, the move is unsound.

however, the assert passes even with --gc:arc or --newruntime

Additional Information

However in the top-level snippet of current issue, both --newruntime , --gc:arc and no flags cause let to move instead of copy (ie the assert passes)

proposal

one simple proposal is as follows:

the only tricky point is backward compatibility, but at least it's simple to grok

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions