TechTalk Genome v4.2

Implicit Functions

[ alias : implicit-function ]

The OQL syntax uses implicit functions (inlined and unnamed functions) to project, filter and sort sets. These implicit functions are declared with the square bracket operators ([ and ]) and can use any identifiers declared in outer scopes of the expression. The implicit functions in OQL are evaluated on elements of a source Set<T>. The order in which this evaluation occurs is indeterministic and therefore the implicit functions must not have any side effects.

The Candidate Element

The element that is currently being evaluated is also know as the candidate element of the source set. The candidate element can be accessed implicitly by using the this keyword in the implicit function body as in the following example:

    extentof(Person)[this.Age < 25] 

The OQL query above results in a set of persons younger than 25 years.

Similar to OOP languages, the this keyword can be used both explicitly or implicitly. Referring to a property or method automatically acceses the candidate element for the specified property or method. Thefore the following OQL query is identical to the previous one:

    extentof(Person)[Age < 25] 

Identifiers in OQL are declared in a cascading manner, ie. identifiers declared in nested scopes hide any identifiers with the same name declared in outer scopes. This rule therefore applies to the this keyword in the following OQL query as well:

    extentof(Person)[this.Age < 25 && !this.Cars[this.Age > 25].IsEmpty] 

the first two occurences of the this keyword refer to the candidate element of extentof(Person) while the third occurence refers to the candidate element of the Cars collection. Hence the query returns all persons younger than 25 years who have at least one veteran car.

Aliasing the candidate element

While the cascading manner of handling identifiers in OQL is appropriate most of the time, there are certain cases when the nested expression has to refer candidate elements from both scopes. OQL provides a feature to assign an explicit name to the candidate element by aliasing it as in the following example:

    extentof(Person)[p: p.Age < 25 && !p.Cars[c: c.Age > 25].IsEmpty] 

The OQL query above is identical to the previous one. Both the candidate elements have been aliased, the candidate element of the Person extent can be referred to as p while the candidate element of the Cars collection can be referred to as c. This allows both candidate elements to be compared to each other as in the following example:

    extentof(Person)[p: !p.Cars[c: p.FavouriteColor == c.Color].IsEmpty] 

When the candidate element of an implicit function is aliased, the this keyword (if defined in outer scopes) is not hidden. Therefore, when a function aliases the this keyword, all references to the candidate element must be explicitly qualified with the alias:

    extentof(Person)[Age < 25 && !this.Cars[c: Age > 25].IsEmpty] 

The query above returns an empty set since it queryies for persons that are both younger and older than 25 years. The reason for this is that the nested query aliases the candidate element of the Cars collection to c but the Age > 25 clause (implicitly) uses the this keyword and is therefore evaluated on the candidate element of the person extent. Hence the previous query is identical to:

    extentof(Person)[p: p.Age < 25 && !p.Cars[c: p.Age > 25].IsEmpty] 

See Also

Projection | Filtering