Language Enhancements

Note: The following enhancements to or deviations from Tutorial D should be considered experimental. Depending on their value (or lack thereof) they may or may not be included in future versions of Rel.

Catalog: Rel provides a simple system catalog, via a predefined relvar called "sys.Catalog". The contents of the Catalog, i.e., the relvars currently defined in a database, may be displayed by retrieving the contents of the sys.Catalog relvar. For example:

sys.Catalog

A relation of all defined relvar names can be obtained using:

sys.Catalog {Name}

Case sensitivity: Rel language keywords are not case sensitive. By convention, keywords are shown here in upper case to visually distinguish them, but the parser recognises them in lower case as well. Rel identifiers and string comparisons are case sensitive.

OUTPUT, WRITE, and WRITELN statements: Statements have been introduced to send raw text to the client. For example, the following:

VAR i INTEGER;
DO i := 1 TO 3;
	OUTPUT i;
END;

Will send the following to the client:

1
2
3

OUTPUT, WRITE, and WRITELN each have slightly different behaviour. OUTPUT sends text in a form that can be parsed by Rel, followed by a new line. WRITELN sends text in a natural human-readable form, followed by a new line. WRITE is the same as WRITELN, but does not send a new line. In the current implementation, the only significant difference between OUTPUT and WRITELN is that OUTPUT will present a CHAR surrounded by double quotes, whereas WRITELN will not include the double quotes.

WRITELN and OUTPUT may be specified with no expression, in order to send a new line. Eg.:

WRITELN;

DROP OPERATOR: Since operators may be overloaded, an alteration to the specified grammar is required to disambiguate the desired operator. For example, the following operator definitions are allowable:

OPERATOR foo(x INTEGER, y INTEGER) RETURNS INTEGER;
	RETURN x + y;
END OPERATOR;

OPERATOR foo(x INTEGER) RETURNS INTEGER;
	RETURN x + 2;
END OPERATOR;

Dropping the first operator is performed with the following:

DROP OPERATOR foo(INTEGER, INTEGER);

Dropping the second is performed with the following:

DROP OPERATOR foo(INTEGER);

Compile-time announcements: A statement has been provided to output strings during compilation. This may be used to provide compilation progress indicators in lengthy scripts. Eg.:

ANNOUNCE 'Operator fibonacci (INTEGER) INTEGER being created...';
OPERATOR fibonacci (r INTEGER) RETURNS INTEGER;
   IF r <= 1 THEN
       RETURN r;
   ELSE
       RETURN fibonacci(r - 1) + fibonacci(r - 2);
   END IF;
END OPERATOR;

Comments: Comments are specified using conventional C++ and Java syntax. Eg:

// This is a comment line

/* This is a multi-line
   comment block */

ORDER: An ORDER operator has been implemented to accept a relation and return a row-ordered ARRAY. This is useful for generating human-readable output. For example:

WRITELN P ORDER (DESC WEIGHT, ASC P#);

ARRAY element dereference: As defined in the Tutorial D grammar, ARRAY elements are dereferenced with "(...)", e.g.:

VAR catalog ARRAY SAME_TYPE_AS(TUPLE FROM sys.Catalog {Name});
LOAD catalog FROM sys.Catalog {Name} ORDER (ASC Name);
OUTPUT catalog(3);

However, Rel defines ARRAY element dereference as "[...]". The above will not work. Instead, use:

VAR catalog ARRAY SAME_TYPE_AS(TUPLE FROM sys.Catalog {Name});
LOAD catalog FROM sys.Catalog {Name} ORDER (ASC Name);
OUTPUT catalog[3];

This avoids ambiguity with operator invocation, and follows a familiar convention that users of C, C++, C#, Java, and a number of other popular general-purpose programming languages are likely to recognise.

FOR: The 'FOR' statement permits iterating over the tuples in an ARRAY and executing arbitrary code. For example:

FOR sys.Catalog {Name} ORDER(ASC Name); 
    WRITELN "Name = " || Name;
END FOR;

The above example is shorthand for:

VAR catalog ARRAY SAME_TYPE_AS(TUPLE FROM sys.Catalog {Name});
LOAD catalog FROM sys.Catalog {Name} ORDER (ASC Name);
VAR i INTEGER;
DO i := 0 TO COUNT(catalog) - 1;
   BEGIN;
       VAR Name INIT(Name FROM catalog[i]);
       WRITELN "Name = " || Name;
   END;
END DO;

FOR is typically used conjunction with ORDER (see above) to permit iterating tuples from a relational expression in a specified sequence, but if no particular sequence is required, ORDER may be specified as shown in the following example:

FOR sys.Catalog {Name} ORDER(); 
    WRITELN "Name = " || Name;
END FOR;

EXECUTE: The EXECUTE statement permits run-time execution of dynamically-generated Tutorial D code. For example, the following uses EXECUTE to emit Tutorial D definitions of user-defined real relvars, by dynamically generating and executing an 'OUTPUT' statement for each relvar using the relvar name obtained at run-time:

FOR sys.Catalog WHERE Owner <> "Rel" AND NOT isVirtual ORDER();
   BEGIN;
	WRITELN "VAR " || Name || " REAL " || Definition || ";";
	WRITE Name || " := ";
	EXECUTE "OUTPUT " || Name || ";";
	WRITELN ";";
   END;
END FOR;

Note that EXECUTE runs in the global scope, rather than the local scope in which it is used.

User-defined OPERATORs written in Java: OPERATORs may be defined in Java. See the Scripts directory of a Rel installation for examples.

User-defined TYPEs written in Java: New built-in TYPEs may be defined using Java within Rel. See the Scripts directory of a Rel installation for examples.