As a user/dev, I want to compare/diff/relate Candid values
Is your feature request related to a problem? Please describe.
When building CI workflows, we need a human-readable representation of how two Candid values relate when they are not equal.
This human-readable representation would be included in reports of CI failures (e.g., lists of "expected versus observed" test outputs).
To compute that representation meaningfully, we need some constructive math to define it.
Describe the solution you'd like
This issue proposes a new Rust crate, which would augment the existing candid crate with higher-level implementations of various relations over candid values and types.
Let's call it candid_relate.
It gives semantic operations over ASTs of Candid values and types, including:
- Structural comparison (in the sense of
mo:base/Order.Order) - Structural editing, with a representation of diffs/deltas.
- Equality checks, in a semantic sense that requires types (re-implement some semantics of Candid, but at a higher level of abstraction, with more debugging information when things "go wrong").
This crate is not essential for building candid services, but would be essential for any candid tool that tries to debug expected versus observed values of candid data.
Here's an example of some related uses, demonstrating diff, delta and equal, and how they inter-relate:
// suppose we have two Candid ASTs, and a type that classifies each:
let (x : candid::Ast, y : candid::Ast, t : candid::Type) = ... ;
// (note: candid values x and y each have a common candid super-type, t)
// At the common type, we can edit one value into the other
let d : candid_relate::Delta = candid_relate::diff(x, y, t);
// difference/delta is represented by d, and can be applied as follows:
let z = candid_relate::delta(x, d);
// equal at the common supertype t, but perhaps not generally:
assert_eq!( candid::equal(z, y, t) );
When two values are not equal, a CI script could use this crate to help pretty-print a report that summarizes ("usefully") how the two values differ, e.g., by implementing the Show trait, or something similar:
println!("{}", d)
Describe alternatives you've considered
- Standard equality test (gives limited insights when the answer is "false", hence this proposal)
Additional context
-
This came up while trying to build useful tools (in Rust) for CI to run to generate reports, and reports about failures of IC services written in Motoko/Rust.
-
Caching and cache repair: The proposed "incremental edits representation" is (potentially) related to a future effort that would make query results systematically incremental across the Internet Computer. Just as we prescribe a representation of data by designing Candid, the representation of edits to these values could also be shared/systematic/general.
@chenyan-dfinity Should we have multiple crates in this repo, like other Rust language projects? Or separate repos for each crate? (The downside of separate is that we loose visibility outside of dfinity org, and the cost of making more within the dfinity org is high, in terms of process involved --- seems easiest/best now to do a multi-crate repo?)
Should we have multiple crates in this repo
Nervermind that question. I see that we do now.
New question: May I do a PR to add candid_relate here as well? WDYT?
Sure, feel free to make a PR here.
pretty-print a report that summarizes ("usefully") how the two values differ
FYI I recently tried the pretty crate and find it very nice. See this PR: https://github.com/dfinity/candid/pull/56
MVP in #58 with some tracking issues for the missing pieces:
- [ ] #68
- [ ] #67