Standard collections should use type information to identify finiteness #1512
Replies: 10 comments 6 replies
-
|
My 2 cents: I'm not fully sure if we can define a
Personally, I think alternative 2 is more elegant and would likely be easier to maintain in the long run. |
Beta Was this translation helpful? Give feedback.
-
|
I would love to have a FiniteMap type. One advantage that hasn't been mentioned yet is that FiniteMap<K, V> can have K be marked |
Beta Was this translation helpful? Give feedback.
-
|
I'm glad it's getting traction! As a second order suggestion, if we pull this off, I think it make senses to have Map be the finite version. Experience suggests finite maps appear much more frequently than infinite. (I'm not super concerned about "existing users of Map". The language is young; better to make good choices now than start the ossification process early.) |
Beta Was this translation helpful? Give feedback.
-
|
I'm going to add that, pedagogically, the nuance of |
Beta Was this translation helpful? Give feedback.
-
|
There's one important technical thing to consider, which is that commonly used functions like |
Beta Was this translation helpful? Give feedback.
-
|
Well, we could have a That means that common patterns like this still don't work: Dafny solves this with a shallow syntax analysis that recognizes the finiteness of that set expression. We could instead ask users to use standard library functions, such as I guess the idea is this: By hypothesis there are only a few common patterns that people use to generate most finite sets (map domains); that's why Dafny can get away with syntax regexes. If that's so, we'd encode those same patterns with a few std library functions (like |
Beta Was this translation helpful? Give feedback.
-
|
More supporting evidence for making finite/infinite more obvious in the type system: |
Beta Was this translation helpful? Give feedback.
-
I like both of these ideas, but we'll need a way to allow them to work together. Right now, you can only put one accept/reject-recursive types declaration on any given struct, so I think we'll need a more flexible declaration of accept/reject. |
Beta Was this translation helpful? Give feedback.
-
|
Okay, I have a draft of these changes here: Current status: Observations to discuss: Error messages: The error messages for using the wrong type of set aren't very good. I'd want "expected ISet, found Set," but instead we have "expected false, found true". Ergonomics for finite constructions: Code that uses finite Set has some trouble producing witnesses for the map in Set::int_range().map() constructors. Moreso with whichever library it was that wanted nat ranges; had to build up a library. Not sure there's anything more elegant we can do. I think we need to see code written from scratch in finite style to see how well it's working out. VerusSync isn't generic: In my changes, verussync macros use IMaps. This is opinionated, it sort of forces applications (verified-memory-allocator, verified-node-replication) to stay in IMap land. Conceivably, we could make verussync generic over finiteness, but I'm out of bandwidth for trying that experiment. I think these issues might be tolerable in exchange for finally landing this first version of the feature, but maybe I'm saying that just because I've been staring at it for too long. |
Beta Was this translation helpful? Give feedback.
-
|
Veritas project links and status: verified-memory-allocator page-table verified-storage node-replication |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
-
Where Dafny has separate types for set/iset and map/imap, Verus chose a single type for each that supports infinites, and then adds broadcast rules that say ∀m.m_is_finite() ⇒ m.some_good_thing().
The unfortunate consequence is that, when you're expecting your maps to be finite, and they're not, you end up chasing down wild goose assertion failures, since the broadcast rules can't tell you that they're failing to trigger.
This reminds me of one of the main motivations for creating Verus in the first place: ownership types moved a bunch of confusing SMT errors into crystal clear type errors. I propose that we should separate infinite maps (sets, seqs) from finite maps (sets, seqs) using types.
Having to split into a separate Map:IMap type would suck. How about a Finite trait, and define type Map = IMap + Finite? In common usage, we'd always type Map, as usual, and get finiteness, but most of the map properties would actually derive from IMap, so they'd be available there, too. And impl IMap could offer as_finite() -> Map that requires is_finite(): that is, you can use an SMT obligation to upgrade the type.
Beta Was this translation helpful? Give feedback.
All reactions