meta capability
A new meta capability has been added for greater flexibility to efficiently handle some situations.
When the model contains at least one attempt to reference a meta atom, then the model will be automatically augmented with meta atoms as follows:
- For each user-defined sig X, we add a meta atom “X$”; and for each field Y in a user defined sig X, we add a meta atom “X$Y”.
- Given the meta atom “X$” representing some user signature; “X$.fields” represents the meta atoms for its immediate fields and “X$.subfields” the meta atoms for it and all descendants’ fields.
- Given the meta atom “X$Y” representing some field; “X$Y.value” represents the actual field value in the real world.
- An atom “sig$” is added that represents the union of all meta atoms that represent signatures as well as a “field$” atom representing the union of all meta atoms that represent fields.
So, for example, say we have the following model:
sig A {
x: Int,
y: Int,
z: Int
}
One common thing you might want to have is an equals predicate:
pred eq[a1, a2 : A] { a1.x=a2.x and a1.y=a2.y and a1.z=a2.z }
The inconvenience with doing it this way is that it gets very long as there are more fields in the sig and if you happen to add a new field in A you have to remember to modify the eq predicate as well.
Using the meta capability this predicate could be written more succinctly (and with no impact on performance) like this:
pred eq[a1, a2 : A] { all f:A$.subfields | a1.(f.value)=a2.(f.value) }
You can also have more a intricate model such as:
sig A { x: Int }
sig B extends A { y: Int->Int }
and the following will still work:
pred eq [b1, b2 : B] { all f:B$.subfields | b1.(f.value)=b2.(f.value) }
We do some manipulations to make this common idiom work because it’s a fairly common one:
whenever we see an expression of the kind all f:GUARD | body
or some f:GUARD | body
where GUARD’s
type is a subtype of (sig$+field$)
, we replicate the body multiple times for each possible meta atom
in existence, and bind f
to each possible meta atom one-at-a-time. We do this in such a way that there’s
no impact in performance; the cost of writing a frame condition using the meta capability is exactly the
same as if you manually enumerate each field.
But this is a one-off case, so always be mindful about the expressions you write since these will still need to type-check.