sig name { }
Following each signature declaration, we find a signature body whose within a pair of braces. In the signature body, we can define a series of relations for which the set defined by the signature is the domain. For instance, in the FSObject signature body, we define a relation called "parent" which relates FSObjects to Dirs.
A sig may also have fields, which look like this (brackets
indicate optional text):
sig name {
//most fields look like this:
field-name-1: field-type-1,
//A signature may refer to signatures not
// defined until later in the model.
//multiple fields with the same type look like this:
field-name-2a, field-name-2b: field-type-2
}
A signature extending another signature is a partition of that other
signature:
sig A extends C {
//fields
}
sig B extends C {
//fields
}
means that A and B are disjoint subsets of C. If A and B have identical bodies, then we can get the same effect by writing
sig A, B extends C { //fields }
We can use in instead of extends to get a slightly different effect -- in declares that one sig is a subsets of another, but does not enforce that it is disjoint from other sigs with the same parent. That is,
sig A in C { //fields } sig B in C { //fields }
means that A and B are both subsets of C, but they are not necessarily disjoint. Once again, if A and B have identical bodies, we can use the shorthand
sig A, B in C { //fields }
In general, two (or more) sigs which have the same definition may be declared together, like this:
sig name1, name2 { //fields }
the abstract keyword is analogous to the abstract keyword of OO languages like Java, although it is not a perfect analogy. Consider some signature defined as follows:
abstract sig Foo { //fields } sig Bar extends Foo { //fields } sig Cuz extends Foo { //fields }
By using the abstract keyword, we make guarantee that there will be no Foo that is not also either a Bar or a Cuz. However, had there been no signatures declared as subsets of Foo or extending it, then this restriction is relaxed; if a signature has no subsets then writing abstract has no effect.
You can force there to always be exactly one instance of (element
in) a signature by using the one keyword. This
also makes sure that every reference to this signature refers to
the same atom.
one sig name {
// fields
}
Examples:
sig FSObject { } sig Dir { contents: set FSObject } sig FileSystem { root: one Dir, objects: set FSObject, contents: Dir lone->set FSObject, parent: FSObject set->lone Dir }