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.