Regarding to how sink works:

A `sink` annotated parameter `a` basically tells the compiler that, inside the 
procedure, you're planning to - in C++ terms - move `a` somewhere. This allows 
you to have only one `=sink` invocation with no intermediate temporaries at the 
'final' move location even when passing a value down through multiple procedure 
calls (`sink` needs to be present on the respective parameters though). You're 
not required to actually move `a` on all code paths or even at all, the 
compiler just makes sure that you can do so without disturbing anything at the 
callsite by creating a temporary there if necessary.

Note that `sink` is, strictly speaking, not merely a hint since:
    
    
    proc a(x : var int, y : int) =
      x = move y
    
    
    Run

does not compile, while: 
    
    
    proc b(x : var int, y : sink int) =
      x = move y
    
    
    Run

does.

The following Nim code: 
    
    
    type
      A = object
        x : int
      B = object
        a : A
    
    proc set(b : var B, a : sink A) =
      b.a = a # Compiler infers `=sink` (move) here. No need to use `move`
      # b.a = move a
    
    proc test1() =
      var a = A(x : 0)
      var b : B
      b.set(a)
    
    proc test2() =
      var a = A(x : 0)
      var b : B
      # A copy of `a` gets passed to `set`
      b.set(a)
      # modify a
      a.x = 1
    
    proc test3() =
      let a = A(x : 0) # Using let here (roughly the same as const in C++)
      var b : B
      # No copy is created here. `a` gets moved from even though it's a let 
(constant) since `a` is last used here
      b.set(a)
    
    Run

directly translated to C++20 (while keeping the same abstraction level):
    
    
    struct A {
      int x;
    };
    
    struct B {
      A a;
    };
    
    void set(B& b, A& a) {
      b.a = std::move(a);
    }
    
    void test1() {
      A a{.a = 0};
      B b;
      set(b, a);
    }
    void test2() {
      A a{.a = 0};
      B b;
      {
        A temp = a; // Could also use the copy-constructor here instead of 
copy-assignment
        set(b, temp);
      }
      a.x = 1;
    }
    void test3() {
      // const A a{.x = 0};
      
      // No equivalent since you can't bind a const l-value to a l-value 
reference. You'd have to either make `a` non-const or introduce a copy
    }
    
    Run

Reply via email to