Tweaked the API a bit. Now @bind x = 1 is for immutable variable-bound objects, while @bind :mut x = 1 is for mutable. I feel like @bind is a good word for the Julia programmer because it reminds them you are binding the object to a specific variable.
Also there are now loops. There are also a bunch of Base functions forwarded now that will automatically check the .moved property before doing a read:
julia> @bind x = [1.0]
Bound{Vector{Float64}}([1.0])
julia> @move y = x
Bound{Vector{Float64}}([1.0])
julia> sin(x[1])
ERROR: Cannot use x: value has been moved
Also, for anything that is isbits, BorrowChecker.jl will just automatically deepcopy instead of moving. This is actually the same behavior of Rust (via the Copy trait). If something is allocated on the stack, just create copies rather than unbinding, since there’s no need:
julia> using BorrowChecker
julia> @bind x = 1
Bound{Int64}(1)
julia> @take x
1
julia> @take x
1
But if something is not isbits, like a vector, it will unbind from the variable:
julia> @bind array = [1, 2, 3]
Bound{Vector{Int64}}([1, 2, 3])
julia> @move array2 = array
Bound{Vector{Int64}}([1, 2, 3])
julia> array
[moved]
My general design principle is just to try to get the API as close to Rust’s borrow checker as possible, because obviously they know way more than me about all the subtleties of each design choice.
You can freeze/thaw things with this interface too. Just move it to a mutable variable:
julia> @move :mut array3 = array2
BoundMut{Vector{Int64}}([1, 2, 3])
julia> array3[end] = 4
4
julia> array3
BoundMut{Vector{Int64}}([1, 2, 4])
julia> array2[end] # bad!
ERROR: Cannot use array2: value has been moved
Then, for loops can now use @bind to get array elements. This moves the contents of the iterator:
julia> @bind :mut for var in 1:5
@show var
end
var = BoundMut{Int64}(1)
var = BoundMut{Int64}(2)
var = BoundMut{Int64}(3)
var = BoundMut{Int64}(4)
var = BoundMut{Int64}(5)
It also correctly binds the iteration symbol to the object, to help catch mistakenly leaving the BorrowChecker.jl system:
julia> @bind for var in 1:5
@show var
var2 = var # Bad!
@move var3 = var2
end
var = Bound{Int64}(1)
ERROR: Variable `var2` holds an object that was reassigned from `var`.