Alpha Technical Note #004
How to use predicates with Alpha


Introduction

Predicates are sets of logical conditions which are to be tested against some attributes. They act as a logical operator and they return a boolean value (1 or 0) to indicate whether the tested values meet the conditions or not.
A simple example of a predicate is expressed loosely by a phrase like "first name begins with A and weight is less than 175 pounds". If you apply this predicate to Alice who weighs 170 pounds, the predicate will return 1. Applied to Andrew who weighs 195.5 pounds, the predicate will return 0 (same for Bob because his first name does not begin with an A!).
There are two kinds of predicates: The previous example was a compound predicate made of two comparison predicates: the predicate "first name begins with A" and the predicate "weight is less than 175".

Building a predicate

The predicates in Alpha are identified by a unique token. There are two methods, explained in the next sections, to obtain a token:

The predicate command

The [predicate] command has a subcommand create which takes, as argument, a string description of the predicate and returns a token. See [predicate create].
The description string is written according to a precise syntax. To learn more about this syntax, see the following document: Predicate Format String Syntax.
The example of the previous section can be described like this: firstName BEGINSWITH 'A' AND weight < 175.
So you create the predicate with the following instruction:
set predic [predicate create "firstName BEGINSWITH 'A' AND weight < 175"]
Here firstName and weight are keys which will be used to declare the attributes.
The purpose of this document is not to describe all the possibilities offered by this syntax. Please read the documentation. You should nevertheless know that it is very flexible and supports wildcards and regular expressions.

The predicate view

In order to build predicates in a more intuitive manner, the [view] command provides a PredicateEditor view. This section explains how to build a view corresponding to the previous example.
The following image shows what this Predicate Editor may look like:

The first row describes a compound predicate, the next two are comparison rows. Using the Plus button, the user can add other comparison rows. One can also delete a row using the Minus buttons.
Here is the code used to build this interface. We first create a dialog view with two buttons:
set root [view root Dialog -frame [list 0 0 400 140]]
hi::addOkCancelButtons $root [list OK Cancel] [list okButtonProc hi::exit]
We then add a Predicate Editor view:
set predView [view create PredicateEditor -parent $root -frame [list 13 40 370 90]]
We now configure this editor view. The most important option is the -items option which lets you specify the row templates.
view configure $predView -items [list \
      [list "firstName" [list "begins" "contains" "ends"] string] \
      [list "weight" [list "<" "==" ">"] float] \
      ] 
Its value is a list of sublists where each sublist describes a template for a comparison row template. In the previous example: Note that there are many other possible comparison operators.
Next, we configure the editor to initially display only two rows (the compound row and one comparison row):
view configure $predView -num 2 
Before we display the dialog, we must define the action of the OK button. This is implemented by the okButtonProc proc (which has been declared above):
proc okButtonProc {token} {
    global predic predView 
    set predic [view configure $predView -value]
    set root [view parent -root $token]
    view delete $root
}
Let us now display the dialog:
view show $root
Here is what we get:

Playing with the buttons, the user might configure the predicate editor like this to reflect our initial example:

When the user presses the OK button, the okButtonProc proc takes care of retrieving the token of the predicate via the -value option of the Predicate Editor view.

Evaluating a predicate

Now that we have obtained a predicate token (either programmatically or graphically), we will use it to test whether some attributes meet the conditions represented by the token. This is done with the [predicate eval] command.
The attributes are specified as a dictionary in which the keys are the same as those used to declare the left hand side of the comparison predicates. In the previous example, there were two keys firstName and weight. Let us see if Alice (who weighs 170 pounds) meets the conditions. Recall that the predicate's token is stored in the variable predic :
«» predicate eval $predic [list firstName Alice weight 170]
1
Now let's try with Andrew who weighs 195.5 pounds:
«» predicate eval $predic [list firstName Andrew weight 195.5]
0

Dealing with dates

The row templates used to configure the Predicate Editor view can be of the following types: date, float, integer, list, string. This type dictates the kind of interface for the right hand side of the comparison rows: floats, integers and strings are set in an edit field, lists are represented by a popup menu and dates by a date picker.
There are three important things to know about dates: Let's modify the previous example to introduce a date (birth date), an integer (number of children) and a list (grade from A to E). Here is the code:
set predView [view create PredicateEditor -parent $root -frame [list 13 46 370 150]]
view configure $predView -flexibility 12 -items [list \
	  [list "firstName" [list "begins" "contains" "ends"] string] \
	  [list "weight" [list "<" "==" ">"] float] \
	  [list "birthDate" [list "<" "==" ">"] date] \
	  [list "children" [list "<=" ">="] integer] \
	  [list "grade" [list "==" "!="] list {A B C D E}] \
	  ] 
view configure $predView -num 6 
Here is what it looks like (initialized with 6 rows):

Going further

Here are three links containing more information about the predicate syntax: As a real life example, the MacMenu package in Alpha implements a predicate editor to add conditions on files to manipulate. One can set conditions on the file's type, creator, size, creation date and modification date.
You can get a string representation of a predicate token with the [predicate format] command. For instance:
«» predicate format $predic
firstName BEGINSWITH "A" AND weight < 175
When a predicate is not needed anymore, delete it with the [predicate delete] command. For instance:
predicate delete $predic

Related Links