API Reference
Ownership Macros
BorrowChecker.MacrosModule.@own
— Macro@own [:mut] x = value
@own [:mut] x, y, z = (value1, value2, value3)
@own [:mut] for var in iter
# body
end
@own [:mut] x # equivalent to @own [:mut] x = x
@own [:mut] (x, y) # equivalent to @own [:mut] (x, y) = (x, y)
Create a new owned variable. If :mut
is specified, the value will be mutable. Otherwise, the value will be immutable.
You may also use @own
in a for
loop to create an owned value for each iteration.
BorrowChecker.MacrosModule.@move
— Macro@move [:mut] new = old
Transfer ownership from one variable to another, invalidating the old variable. If :mut
is specified, the destination will be mutable. Otherwise, the destination will be immutable. For isbits
types, this will automatically use @clone
instead.
BorrowChecker.MacrosModule.@clone
— Macro@clone [:mut] new = old
Create a deep copy of a value, without moving the source. If :mut
is specified, the destination will be mutable. Otherwise, the destination will be immutable.
BorrowChecker.MacrosModule.@take
— Macro@take var
Returns the inner value and does a deepcopy. This does not mark the original as moved.
BorrowChecker.MacrosModule.@take!
— Macro@take! var
Take ownership of a value, typically used in function arguments. Returns the inner value and marks the original as moved. For isbits
types, this will return a copy and not mark the original as moved.
References and Lifetimes
BorrowChecker.MacrosModule.@lifetime
— Macro@lifetime a begin
@ref ~a rx = x
# use refs here
end
Create a lifetime scope for references. References created with this lifetime are only valid within the block and are automatically cleaned up when the block exits.
BorrowChecker.MacrosModule.@ref
— Macro@ref ~lifetime [:mut] var = value
@ref ~lifetime [:mut] (var1, var2, ...) = (value1, value2, ...)
@ref ~lifetime [:mut] for var in iter
# body
end
Create a reference to an owned value within a lifetime scope. If :mut
is specified, creates a mutable reference. Otherwise, creates an immutable reference. Returns a Borrowed{T} or BorrowedMut{T} that forwards access to the underlying value.
This will not detect aliasing in the iterator.
Types
BorrowChecker.TypesModule.AbstractOwned
— TypeAbstractOwned{T}
Base type for all owned value types in the BorrowChecker system.
BorrowChecker.TypesModule.AbstractBorrowed
— TypeAbstractBorrowed{T}
Base type for all borrowed reference types in the BorrowChecker system.
BorrowChecker.TypesModule.Owned
— TypeOwned{T}
An immutable owned value. Common operations:
- Create using
@own x = value
- Access value using
@take!
(moves) or@take
(copies) - Borrow using
@ref
- Access fields/indices via
.field
or[indices...]
(returns LazyAccessor)
Once moved, the value cannot be accessed again.
Internal fields (not part of public API):
value::T
: The contained valuemoved::Bool
: Whether the value has been movedimmutable_borrows::Int
: Count of active immutable borrowssymbol::Symbol
: Variable name for error reporting
BorrowChecker.TypesModule.OwnedMut
— TypeOwnedMut{T}
A mutable owned value. Common operations:
- Create using
@own :mut x = value
- Access value using
@take!
(moves) or@take
(copies) - Modify by setproperty! or setindex!:
x.field = value
orx[indices...] = value
- Borrow using
@ref
or@ref :mut
- Access fields/indices via
.field
or[indices...]
(returns LazyAccessor)
Once moved, the value cannot be accessed again.
Internal fields (not part of public API):
value::T
: The contained valuemoved::Bool
: Whether the value has been movedimmutable_borrows::Int
: Count of active immutable borrowsmutable_borrows::Int
: Count of active mutable borrowssymbol::Symbol
: Variable name for error reporting
BorrowChecker.TypesModule.Borrowed
— TypeBorrowed{T,O<:AbstractOwned}
An immutable reference to an owned value. Common operations:
- Create using
@ref lt x = value
- Access value using
@take
(copies) - Access fields/indices via
.field
or[indices...]
(returns LazyAccessor)
Multiple immutable references can exist simultaneously. The reference is valid only within its lifetime scope.
Internal fields (not part of public API):
value::T
: The referenced valueowner::O
: The original owned valuelifetime::Lifetime
: The scope in which this reference is validsymbol::Symbol
: Variable name for error reporting
BorrowChecker.TypesModule.BorrowedMut
— TypeBorrowedMut{T,O<:OwnedMut}
A mutable reference to an owned value. Common operations:
- Create using
@ref lt :mut x = value
- Access value using
@take
(copies) - Access fields/indices via
.field
or[indices...]
(returns LazyAccessor)
Only one mutable reference can exist at a time, and no immutable references can exist simultaneously.
Internal fields (not part of public API):
value::T
: The referenced valueowner::O
: The original owned valuelifetime::Lifetime
: The scope in which this reference is validsymbol::Symbol
: Variable name for error reporting
BorrowChecker.TypesModule.LazyAccessor
— TypeLazyAccessor{T,P,S,O<:Union{AbstractOwned,AbstractBorrowed}}
A lazy accessor for properties or indices of owned or borrowed values. Maintains ownership semantics while allowing property/index access without copying or moving.
Created automatically when accessing properties or indices of owned/borrowed values:
@own x = (a=1, b=2)
x.a # Returns a LazyAccessor
Internal fields (not part of public API):
parent::P
: The parent value being accessedproperty::S
: The property/index being accessedproperty_type::Type{T}
: Type of the accessed property/indextarget::O
: The original owned/borrowed value
BorrowChecker.TypesModule.OrBorrowed
— TypeOrBorrowed{T}
Type alias for accepting either a value of type T
or a borrowed reference to it.
BorrowChecker.TypesModule.OrBorrowedMut
— TypeOrBorrowedMut{T}
Type alias for accepting either a value of type T
or a mutable borrowed reference to it.
Traits
BorrowChecker.StaticTraitModule.is_static
— Functionis_static(x)
This trait is used to determine if we can safely @take!
a value without marking the original as moved.
This is somewhat analogous to the Copy
trait in Rust, although because Julia immutables are truly immutable, we actually do not need to copy on these.
For the most part, this is equal to isbits
, but it also includes things like Symbol
and Type{T}
(recursively), which are not isbits
, but which are immutable.
Errors
BorrowChecker.ErrorsModule.BorrowError
— Typeabstract type BorrowError <: Exception end
Base type for all errors related to borrow checking rules.
BorrowChecker.ErrorsModule.MovedError
— TypeMovedError <: BorrowError
Error thrown when attempting to use a value that has been moved.
BorrowChecker.ErrorsModule.BorrowRuleError
— TypeBorrowRuleError <: BorrowError
Error thrown when attempting to violate borrow checking rules, such as having multiple mutable references.
BorrowChecker.ErrorsModule.SymbolMismatchError
— TypeSymbolMismatchError <: BorrowError
Error thrown when attempting to reassign a variable without using proper ownership transfer mechanisms.
BorrowChecker.ErrorsModule.ExpiredError
— TypeExpiredError <: BorrowError
Error thrown when attempting to use a reference whose lifetime has expired.
Experimental Features
BorrowChecker.Experimental.@managed
— Macro@managed f()
Run code with automatic ownership transfer enabled. Any Owned
or OwnedMut
arguments passed to functions within the block will automatically have their ownership transferred using the equivalent of @take!
.
This is an experimental feature and may change or be removed in future versions.
Internals
Normally, you should rely on OrBorrowed
and OrBorrowedMut
to work with borrowed values, or use @take
and @take!
to unwrap owned values. However, for convenience, it might be useful to define functions on Owned
and OwnedMut
types, if you are confident that your operation will not "move" the input or return a view of it.
Many functions in Base are already overloaded. But if you need to define your own, you can do so by using the request_value
function and the AllWrappers
type union.
Core Types
AllWrappers{T}
: A type union that includes all wrapper types (Owned{T}
,OwnedMut{T}
,Borrowed{T}
,BorrowedMut{T}
, andLazyAccessor{T}
). This is used to write generic methods that work with any wrapped value.
Core Functions
request_value(x, Val(:read))
: Request read access to a wrapped valuerequest_value(x, Val(:write))
: Request write access to a wrapped value
Examples
Here's how common operations are overloaded:
- Binary operations (like
*
) that only need read access:
function Base.:(*)(l::AllWrappers{<:Number}, r::AllWrappers{<:Number})
return Base.:(*)(request_value(l, Val(:read)), request_value(r, Val(:read)))
end
- Mutating operations (like
pop!
) that need write access:
function Base.pop!(r::AllWrappers)
return Base.pop!(request_value(r, Val(:write)))
end
The request_value
function performs safety checks before allowing access:
- For read access: Verifies the value hasn't been moved
- For write access: Verifies the value is mutable and not borrowed
Note that for operations that need write access, and return a view of the input, it is wise to modify the standard output to return nothing
instead, which is what we do for push!
:
function Base.push!(r::AllWrappers, items...)
Base.push!(request_value(r, Val(:write)), items...)
return nothing
end
While this violates the expected return type, it is a necessary evil for safety. The nothing
return will cause loud errors if you have code that relies on this design. This is good! Loud bugs are collaborators; silent bugs are saboteurs.