Migrating from v0.2 to v0.3

Overview

v0.3 is a breaking release that simplifies the API:

  • acquire! now returns Array (was SubArray/ReshapedArray)
  • unsafe_* functions removed (no deprecation period)
  • acquire_view! added for explicit view access

On Julia 1.11+, Array became a mutable struct, enabling zero-allocation wrapper reuse via setfield! — the same guarantee views had. With Array now zero-alloc too, it's the natural default.

API Changes at a Glance

Return type changes

Functionv0.2 return typev0.3 return type
acquire!(pool, T, dims...)SubArray / ReshapedArrayArray{T,N}
zeros!(pool, T, dims...)SubArray / ReshapedArrayArray{T,N}
ones!(pool, T, dims...)SubArray / ReshapedArrayArray{T,N}
similar!(pool, x)SubArray / ReshapedArrayArray{T,N}
acquire!(pool, Bit, dims...)BitVector / BitArray{N}BitVector / BitArray{N} (unchanged)
trues!(pool, dims...)BitArray{N}BitArray{N} (unchanged)
falses!(pool, dims...)BitArray{N}BitArray{N} (unchanged)
reshape!(pool, A, dims...)Array{T,N}Array{T,N} (unchanged)

Removed functions

v0.2 (removed)v0.3 replacement
unsafe_acquire!(pool, T, dims...)acquire!(pool, T, dims...)
unsafe_zeros!(pool, T, dims...)zeros!(pool, T, dims...)
unsafe_ones!(pool, T, dims...)ones!(pool, T, dims...)
unsafe_similar!(pool, x)similar!(pool, x)

New functions

FunctionReturnsDescription
acquire_view!(pool, T, dims...)SubArray / ReshapedArrayOld acquire! behavior (explicit opt-in)
acquire_array!(pool, T, dims...)Array{T,N}Alias for acquire! (symmetric naming)

Search-and-Replace Guide

For most codebases, a simple find-and-replace handles the migration:

unsafe_acquire!  →  acquire!       (or just delete "unsafe_" prefix)
unsafe_zeros!    →  zeros!
unsafe_ones!     →  ones!
unsafe_similar!  →  similar!

If you were using acquire! specifically for its view return type, switch to acquire_view!:

acquire!(pool, T, dims...)  →  acquire_view!(pool, T, dims...)

Code Examples

Basic migration

# ── v0.2 ──────────────────────────────────────────
v = acquire!(pool, Float64, 100)          # SubArray{Float64,1}
a = unsafe_acquire!(pool, Float64, 100)   # Array{Float64,1}
z = unsafe_zeros!(pool, Float64, 10, 10)  # Array{Float64,2}

# ── v0.3 ──────────────────────────────────────────
a = acquire!(pool, Float64, 100)          # Array{Float64,1} ← now Array!
v = acquire_view!(pool, Float64, 100)     # SubArray{Float64,1} ← explicit opt-in
z = zeros!(pool, Float64, 10, 10)         # Array{Float64,2} ← always Array now

If you relied on view types

Code that depended on acquire! returning SubArray needs updating:

# ── v0.2 ──────────────────────────────────────────
v = acquire!(pool, Float64, 100)
@assert v isa SubArray  # ← was true

# ── v0.3 ──────────────────────────────────────────
v = acquire_view!(pool, Float64, 100)
@assert v isa SubArray  # ← still true with acquire_view!

# Or embrace the new default:
a = acquire!(pool, Float64, 100)
@assert a isa Array     # ← true in v0.3

Type assertions in tests

If your tests asserted view types, update them:

# ── v0.2 ──────────────────────────────────────────
@test v isa SubArray

# ── v0.3 ──────────────────────────────────────────
@test v isa Array                          # for acquire!
@test v isa SubArray                       # for acquire_view! (1D)
@test v isa Base.ReshapedArray             # for acquire_view! (N-D)

Why Array is Better as Default

PropertyArraySubArray/ReshapedArray
FFI/ccall (Ptr{T})Works directlyNeeds parent() conversion
::Array{T,N} constraintsSatisfies directlyType error
BLAS/LAPACKCompatibleCompatible
Zero-alloc reuse (1.11+)Yes (setfield!)Yes (always was)
User expectationNaturalSurprising ("why SubArray?")

Special Cases

Bit arrays — no change

acquire!(pool, Bit, ...) still returns BitVector/BitArray{N}, not Array{Bool}. The Bit sentinel is unchanged:

mask = acquire!(pool, Bit, 1000)   # BitVector in both v0.2 and v0.3
bits = trues!(pool, 10, 10)        # BitArray{2} in both versions

CUDA — no behavioral change

On CUDA, both acquire! and acquire_view! return CuArray. There is no view/array distinction on GPU:

using CUDA
a = acquire!(pool, Float32, 100)       # CuArray{Float32,1}
v = acquire_view!(pool, Float32, 100)  # CuArray{Float32,1} (same)

Julia 1.10 LTS

v0.3 still supports Julia 1.10, but the zero-allocation Array reuse via setfield! only works on Julia 1.11+. On 1.10, acquire! returns a freshly constructed Array wrapper (the underlying buffer is still reused — only the wrapper allocates ~40 bytes).

FAQ

Q: Will my v0.2 code break immediately? Yes — if you used any unsafe_* function, it will be an UndefVarError at runtime. The search-and-replace above fixes this in seconds.

Q: Do I need acquire_view! at all? Most users don't. acquire_view! exists for the rare case where you need a SubArray reference into the pool's backing storage (e.g., for custom memory layouts or view-specific dispatch).

Q: Is there a performance difference between acquire! and acquire_view!? Both are zero-allocation on Julia 1.11+. The only difference is the returned wrapper type.