Analysis: v.len() vs [email protected]() in Verus Spec Code
Does the instruction "Always use vector.len() instead of <<[email protected]>>()" in verus_common.md reflect a correctness requirement or just a style preference?
I replaced all instances of v.len() with [email protected]() in spec contexts (requires, ensures, invariants, assertions) in the following verified benchmark files:
- vectors.rs: All 16 functions verified ✅
- bitmap_2.rs: All 14 functions verified ✅
Created test showing:
fn test_equivalence(v: &Vec<u64>)
requires
v.len() == v@.len(), // This verifies!
{
}Before:
fn binary_search(v: &Vec<u64>, k: u64) -> (r: usize)
requires
forall|i: int, j: int| 0 <= i <= j < v.len() ==> v[i] <= v[j],
exists|i: int| 0 <= i < v.len() && k == v[i],
ensures
r < v.len(),After (still verifies):
fn binary_search(v: &Vec<u64>, k: u64) -> (r: usize)
requires
forall|i: int, j: int| 0 <= i <= j < v@.len() ==> v[i] <= v[j],
exists|i: int| 0 <= i < v@.len() && k == v[i],
ensures
r < v@.len(),Another example:
fn reverse(v: &mut Vec<u64>)
ensures
v@.len() == old(v)@.len(), // Works!
forall|i: int| 0 <= i < old(v)@.len() ==> v[i] == old(v)[old(v)@.len() - i - 1],With owned vectors:
fn from(v: Vec<u64>) -> (ret: BitMap)
ensures
ret@.len() == v@.len() * 64, // Works!The instruction is a style preference, not a correctness requirement.
- Simpler and more readable - no need for the
@operator - Less verbose - fewer characters to type
- Verus treats
.len()specially - it automatically works in both executable and spec contexts - Consistency - matches the style of executable code
The <<[email protected]>>() notation
- This syntax doesn't actually exist in the codebase (0 matches found)
- The instruction may be warning against an outdated or incorrect syntax pattern
Updated instruction to:
"Always use
[email protected]()to access the length of the spec-level view. Bothvector.len()and[email protected]()are correct in spec contexts, but prefer[email protected]()for consistency with other view operations likevector@[i]."
Rationale:
While both syntaxes work, standardizing on [email protected]() provides:
- Consistency with other view operations (
v@[i],[email protected]) - Explicit indication that we're working with the spec-level view
- Clearer mental model: always use
@for view operations in specifications
# vectors.rs with [email protected]() syntax
$ verus vectors.rs
verification results:: 16 verified, 0 errors
# bitmap_2.rs with [email protected]() syntax
$ verus bitmap_2.rs
verification results:: 14 verified, 0 errors