Partial borrowing and borrowed parts
Partial borrow from a struct
Imagine the following
struct From
var a: int32
var b: int32
end
activity main ()
var f: From
run outIsPlus1(f.a)(f.b)
await true
end
The compiler can statically decide on partial borrowing for structs. But not for arrays.
The following code would be rejected
activity main (i: int32)
var f: [2]int43
run outIsPlus1(f[1])(f[i])
await true
end
It cannot be decide at compile-time that f[1]
and f[i]
do not overlap.
That means borrowing form arrays borrows the whole array.
Structs with references
A struct may contain a field that is a reference in order to define an alias or an associated data type.
Structs with references contain borrowed fields.
struct RefStruct
var a: int32
let ref b: int32
end
Return a struct with references requires to define which references a borrowed by the struct.
function initRefStruct (refb: int32) returns RefStruct shares refb
return {a = 42, b = refb}
end
var b: int32 = 1
var result = initRefStruct(b)
// b is immutably borrowed to result here
The result of type RefStruct
shares read-only reference refb
. That means it immutably borrows refb
.
As a consequence result
immutably borrows b
.
Consequently b
is frozen after result
is iniatialized.
We could also write initRefers
in the following way.
function initRefStruct (refb: int32) returns RefStruct shares refb
var r: RefStruct = {a = 42, b = refB}
return r
end
The return value is a shallow copy of the struct.
The borrow checker conservatively overestimates all possible borrowing if the return value is constructed through different control path.
function initRefStruct (refb: int32, refother: int32) returns RefStruct shares refb, refother
if aB < aB2 then
return {a = 42, b = refb}
else
return {a = -42, b = refother}
end
end
It also overestimates the sharing if the shares
refers to an output, although the RefStruct
value immutably borrows refb
.
function initRefStruct () (refb: int32) returns RefStruct shares refb
refB = refB + 1
return {a = 42, b = refB}
end
var b: int32
var rs: RefStruct = initRefStruct()(b)
Overestimation is necessary for a rather simple signature.
For separate compilation borrowing in the result must become part of the signature of a function without inspection of the actual code.
The three variants have of initRefStruct
have the following signatures
function initRefStruct (refb: int32) returns RefStruct shares refb
function initRefStruct (refb: int32, refOther: int32) returns RefStruct shares refb, refother
function initRefStruct ()(refb: int32) returns RefStruct shares refb
Struct with references can only be assigned once, because a references need to be defined at the point of their declaration.