Skip to content

Appendix H: Coming From Viper, Dafny, or Iris ​

This is a quick dictionary, not a full comparison. If you already know one of these tools, it should help you quickly find the nearest Raven concept.

H.1 From Viper ​

Viper's field/heap model is exactly the same as Raven's. A field access is a permission plus a value, and fractional permissions work identically in both. What Raven adds on top is ghost fields, i.e., fields whose values come from a user-definable resource algebra rather than a plain type, which is what everything from Part 4 onward is built on.

ViperRavenNote
acc(x.f)own(x.f, v)Raven's own names the value too, not just the permission.
acc(x.f, perc)own(x.f, v, q)Same fractional-permission model.
(no direct equivalent)own(x.g, a), g a ghost fielda here is an element of whatever user-definable resource algebra g's declared type names (Part 4). It is a fact about proof-only state with its own composition rule, not just a permission on an ordinary value. Viper has no ghost fields and no notion of a resource algebra at all. This is the other half of what Raven adds on top of Viper's own field/heap model.
predicate, fold/unfoldpred, fold/unfoldDirectly analogous.
(no direct equivalent)invViper has no built-in shared-invariant concept. Front-ends targeting Viper that need concurrency encode it themselves. This is one of Raven's central additions.
macrosinline predAutomatically inlined, no fold/unfold.
inhale/exhaleinhale/exhaleSame ghost statements, same role. Raven's compilation pipeline reduces everything else to exactly these two, just like Viper's does.
domainADTs (data), or the module systemA Viper domain is closest to a restricted interface: a rep type plus axioms characterizing it, but no functors, no implementations, and no functor composition. For a simple algebraic sum type, Raven's data is the direct match. For anything with more structure (a domain used to axiomatize a whole data structure), Raven's module system is the more general and more capable analogue.
Seq[T]Library.Seq[E] (Appendix C)The same operations and axioms, written as functions: append(s, t) for s ++ t, length(s) for |s|, index(s, i) for s[i], and so on. As in Viper, == on sequences compares them entry by entry.
quantified permissionsiterated separating conjunctions (Part 5.3)Raven's ISC design is explicitly built on Viper's, generalized to arbitrary resource algebras rather than just permissions.
magic wand (A --* B)(not currently supported)A magic wand asserts "give up A and you get B back." This is handy for partially unfolding a recursive predicate (walk partway into a linked list, and leave a wand behind that remembers how to fold it back up once you're done with the part you unfolded) without committing to the whole structure at once. Raven has no equivalent construct yet. The same traversals are instead written by carrying the "rest of the structure" explicitly as a separate resource, which is more verbose but doesn't need anything new.
decreases e1, ..., endecreases e1, ..., enSame contract syntax, same lexicographic-tuple concept. However, Viper has no equivalent of Raven's user-definable WellFoundedOrder instances (Appendix G).
no built-in concurrencyinvariants, ghost fields/RAs, atomic contracts, prophecy variablesThe gap Raven is designed to fill. See Parts 4 and 5 in this tutorial, and Appendix J for prophecies specifically.

There is one other, deeper design difference worth knowing about. Viper is built on implicit dynamic frames, a close relative of separation logic in which expressions (in both programs and specifications) can be heap-dependent. Raven instead keeps expressions pure everywhere. A heap read is always a statement (val x := e.f;), never part of a larger expression. This restriction is what lets Raven treat the evaluation of an expression as happening in one atomic step, no matter how many sub-terms it has. By a Lipton-style reduction argument, no other thread can observe or interfere with it partway through. Raven gets that reasoning for free, rather than as something a concurrency proof has to establish itself. This is an important part of why Raven's pure-expression design is a better fit for concurrency than Viper's.

H.2 From Dafny ​

DafnyRavenNote
method/functionproc/funcSame split: side-effecting vs. pure-and-spec-usable.
requires/ensuresrequires/ensuresSame.
loop invariantloop invariantSame concept. However, Raven also uses the word "invariant" in a completely different, unrelated sense for shared concurrent state (inv). Don't conflate the two just because Dafny only needs the first.
decreasesdecreasesSame role, for recursive func/lemma termination. See §1.4.
classes, thisheap-allocated objects via field/Ref, no implicit thisDafny's memory model already assumes ownership tracking under the hood. Raven makes ownership the explicit thing you reason about, which is the subject of Part 2.
datatypedataSame idea, algebraic sum types.
modifies(implicit, via own)This is a deeper difference, not just a change in syntax. Dafny is based on classical Hoare logic, with no notion of a "heap resource," or any resource at all. Frame conditions have to be stated explicitly, by hand, via modifies. Raven's ownership model (Part 2) makes framing a consequence of what you own, rather than something you separately declare.
no built-in concurrencyinvariants, ghost fields/RAs, atomic contractsDafny is sequential-only. This is the biggest thing to unlearn when coming from Dafny. See the "Why this matters for concurrency" sections throughout Parts 1–3.
compiles to executable code(no compilation backend)Dafny compiles verified programs to real executables (C#, Java, Go, Python, JS). Raven, as of this writing, is purely a verification language. There's no backend that turns a verified .rav file into something you can run. The goal is to check a design or an algorithm's correctness, not producing a deployable artifact from it.

H.3 From Iris ​

If you know Iris, you already know the ideas behind Parts 2–5: ownership, shared invariants, resource algebras (Iris's cameras, restricted here to Iris's simpler, non-step-indexed unital-RA fragment), and atomic triples. What Raven adds is automation. Everything you'd build by hand in the Iris Proof Mode inside Rocq is instead compiled down to a first-order SMT query and discharged by Z3. Concretely:

IrisRaven
Invariant Inv N Pinv
A cameraA resource algebra implementing Library.ResourceAlgebra (Appendix A). This is deliberately the non-step-indexed, non-higher-order fragment of Iris's cameras, since that's what stays SMT-automatable.
Atomic triple << P >> e << v, Q >>atomic requires/atomic ensures (Part 5.2)
Ghost state ownership own γ aghost field, own(e.g, v)
Frame-preserving updatefpu
View shift / mask-aware invariant openingRaven's atomicity analysis, checked automatically rather than proved by hand each time

There is a trade-off. Raven's fragment is deliberately less expressive than full Iris. It has no impredicative invariants, no step-indexing, and no higher-order ghost state. That's what makes it automatable. Landmark, foundational proofs like RustBelt still need full Iris in Rocq. Raven is aimed at the more common case of everyday concurrent data structure proofs that don't.