The INTERFACE statement
Interfaces are meant for interacting with data from a dataset. You define an interface to control precisely which data is presented to which users. You have to declare each interface individually.
Each interface has a name that is unique for every interface in the same context.
When running an application in your browser, you are watching one user-interface at any given moment in time. Each hyperlink on your screen represents an atom to which some interface applies1. To navigate to that user-interface, just click on the hyperlink. You will see the interface being applied solely to the atom you just clicked. To determine the atom(s) to which an interface applies, each interface has an interface expression.
The following figure is an example of a user interface, which shows the name, status, e-mail and co-workers of a person called "J. Lovell".
The specification of this interface is given in the following code fragment
INTERFACE Person : I[Person] BOX [ "Name" : personName , "Status" : personStatus , "Email" : personEmail , "Works with" : workswith ]
To understand this fragment, take notice of:
- The name of this interface is
Person. This name immediately follows the keyword
- The expression following the colon,
I[Person], is the interface expression of this interface.
- The interface can be applied to any atom from the domain of the interface expression. So this particular interface is applicable to any atom of type
Person. In the screenshot, it applies to
- The labels "Name", "Status", "Email", and "Works with" correspond to field names in the user interface.
- Each expression at the right of a field name specifies which data is presented in the field. For this reason it is called the field expression for that field. Field name and field expression are separated by a colon.
- Of all pairs
<"J. Lovell", x>from the field expression, the field displays the right atom
x. A field expression always works on one specific atom on the left, which is
"J. Lovell"in this example.
- Field expressions are subject to type checking. The following relations provide an example for getting a type-correct interface:
The source concepts of a field expression must match the target concept of the interface expression.
RELATION personName :: Person * PersonName [UNI] RELATION personStatus :: Person * PersonStatus [UNI] RELATION personEmail :: Person * Email [UNI,TOT] RELATION workswith :: Person * Person
- Looking at the screenshot, we can tell that
"J. Lovell"has one personName (which is
"J. Lovell"), it has no personStatus, one personEmail and three persons to work with in
You can create structure in an interface by nesting. Here is an example:
The specification of this interface is given in the following code fragment.
INTERFACE "Project" : I[Project] BOX [ "Project" : I[Project] , "Name" : projectName , "Current PL" : pl , "Administration" : I[Project] BOX [ "Project leaders" : project~;assignee/\pl BOX [ "Name" : personName , "Status" : personStatus , "Email" : personEmail ] , "Project members" : project~;assignee/\member BOX [ "Name" : personName , "Status" : personStatus , "Email" : personEmail ] ] ]
Notice the following features:
- The structure of an interface is hierarchical. It consists of boxes within a box. This is because a field expression may be followed by a
BOXwith a list of subinterfaces. Without it, it is just a field expression.
- When a field expression is followed by a
BOX, every atom in the codomain of the field expression is displayed in a box of its own on the screen. That box behaves like an interface with the field expression serving as interface expression of that subinterface.
- By this mechanism, the hierarchical structure of the entire interface translates directly to the hierarchical structure of the web-page in which it is displayed.
- The source concept of a field expression must match with the target concept of the field expression outside the box.
- The target concept of a field expression that has a box, must match with the source concepts of each field inside that box.
Especially in more complicated interfaces, you will find it nice to adapt the layout of the fields of your interface. For this purpose, you can substitute the word
TABS, as in the following code fragment.
INTERFACE "Project" : V[SESSION*Project] ROWS [ "Project" : I[Project] , "Name" : projectName , "Current PL" : pl , "Administration" : I[Project] TABS [ "Project leaders" : project~;assignee/\pl COLS [ "Name" : personName , "Status" : personStatus , "Email" : personEmail ] , "Project members" : project~;assignee/\member COLS [ "Name" : personName , "Status" : personStatus , "Email" : personEmail ] ] ]
Notice the effect that these changes have on the user interface.
Notice the following features:
- The keyword
TABSturns the box into a tabulated layout.
- The keyword
COLSturns the layout 90 degrees into columns.
- The keyword
ROWSis default for any box. It does not change the effect of
Compile and run the script Project Administration Example. Start by reproducing everything that is shown above. It is quite likely that you will be trying out your own ideas before you get to the end... Have fun!
What have you learned?
After finishing your assignment, you have learned:
- to explain how an interface definition is displayed on the screen of a user.
- to predict which data items an interface applies to, if you know which pairs are in an interface expression.
- to predict which data items are displayed, if you know which pairs are in a field expression.
- to explain which atoms are used in a sub-interface.
- to understand what the keywords
ROWSdo to your display.
1 More than one interfaces may apply to the same atom. That gives you a choice on runtime to which interface you want to navigate. If no interface applies, that atom is not navigable.