2.7. Clone

Clone is designed to create a deep copy of the data. Cloning is invoked via the clone operator :=:

a := b

Cloning can be also invoked via the clone initializer in a variable declaration:

var x := y

This in turn expands into clone_to_move:

var x <- clone_to_move(y)

(see clone_to_move).

2.7.1. Cloning rules and implementation details

Cloning obeys several rules.

Certain types like blocks, lambdas, and iterators can’t be cloned at all.

However, if a custom clone function exists, it is immediately called regardless of the type’s cloneability:

struct Foo {
    a : int
}

def clone ( var x : Foo; y : Foo ) {
    x.a = y.a
    print("cloned\n")
}

var l = Foo(a=1)
var cl : Foo
cl := l                 // invokes clone(cl,l)

Cloning is typically allowed between regular and temporary types (see Temporary types).

POD types are copied instead of cloned:

var a,b : int
var c,d : int[10]
a := b
c := d

This expands to:

a = b
c = d

Handled types provide their own clone functionality via canClone, simulateClone, and appropriate das_clone C++ infrastructure (see Handles).

For static arrays, the clone_dim generic is called, and for dynamic arrays, the clone generic is called. Those in turn clone each of the array elements:

struct Foo {
    a : array<int>
    b : int
}

var a, b : array<Foo>
b := a
var c, d : Foo[10]
c := d

This expands to:

def builtin`clone ( var a:array<Foo aka TT> explicit; b:array<Foo> const ) {
    resize(a,length(b))
    for ( aV,bV in a,b ) {
        aV := bV
    }
}

def builtin`clone_dim ( var a:Foo[10] explicit; b:Foo const[10] implicit explicit ) {
    for ( aV,bV in a,b ) {
        aV := bV
    }
}

For tables, the clone generic is called, which in turn clones its values:

var a, b : table<string;Foo>
b := a

This expands to:

def builtin`clone ( var a:table<string aka KT;Foo aka VT> explicit; b:table<string;Foo> const ) {
    clear(a)
    for ( k,v in keys(b),values(b) ) {
        a[k] := v
    }
}

For structures, the default clone function is generated, in which each element is cloned:

struct Foo {
    a : array<int>
    b : int
}

This expands to:

def clone ( var a:Foo explicit; b:Foo const ) {
    a.a := b.a
    a.b = b.b   // note copy instead of clone
}

For tuples, each individual element is cloned:

var a, b : tuple<int;array<int>;string>
b := a

This expands to:

def clone ( var dest:tuple<int;array<int>;string> -const; src:tuple<int;array<int>;string> const -const ) {
    dest._0 = src._0
    dest._1 := src._1
    dest._2 = src._2
}

For variants, only the currently active element is cloned:

var a, b : variant<i:int;a:array<int>;s:string>
b := a

This expands to:

def clone ( var dest:variant<i:int;a:array<int>;s:string> -const; src:variant<i:int;a:array<int>;s:string> const -const ) {
    if ( src is i ) {
        set_variant_index(dest,0)
        dest.i = src.i
    } elif ( src is a ) {
        set_variant_index(dest,1)
        dest.a := src.a
    } elif ( src is s ) {
        set_variant_index(dest,2)
        dest.s = src.s
    }
}

2.7.2. clone_to_move implementation

clone_to_move is implemented via regular generics as part of the builtin module:

def clone_to_move(clone_src:auto(TT)) : TT -const {
    var clone_dest : TT
    clone_dest := clone_src
    return <- clone_dest
}

Note that for non-cloneable types, Daslang will not promote := initialize into clone_to_move.