by David Huynh, July 21, 2003
mys-tique: (www.m-w.com)
Mystique is a programming language designed to wire up Haystack UI. Its core features include:
Mystique inherits some features from Adenine, such as native syntax for RDF resources, RDF literals, and RDF models. However, these features have been changed as detailed below.
1. Infix notation is adopted in preference over Adenine's prefix notation for the reason of readability and familiarity.
2. Prefixed URIs in Mystique have equal expressiveness as full URIs because their suffixes can be delimited by angle brackets. The following URI cannot be prefixed in Adenine
<http://haystack.lcs.mit.edu/homepage.html>
as the period preceding "html" is interpreted as a dereferencement operator. In Mystique, that URI can be prefixed as follows:
@prefix haystack: <http://haystack.lcs.mit.edu/>
haystack:<homepage.html>
3. A full URI starts with < but it must be followed immediately by a non-whitespace character. Otherwise, < is tokenized as a symbol.
4. Statement separators (semicolons in Adenine) are eliminated in favour of subject separators (periods in Mystique). Here are the same code in Adenine and then in Mystique:
5. Annotations can be made on any resource by following it with an attribute container delimited by @{}. Anonymous URIs can be generated using the $ operator. Example:
6. Mystique files can be annotated by @{} at top level and can have 2 additional processing instructions: @version and @encoding. Example:
7. Statement annotations can be made using the ; operator. This operator in essence makes the most recent statement the subject of interest. Example:
There are several kinds of syntactic containers in Mystique. The syntax inside the braces for each type of container can be unique to that type of container.
1. RDF statement containers can be delimited with statements:{} or simply with {}.
2. RDF attribute containers can be delimited with attributes:{}. When used with the @ operator, @ attributes:{} can be shortened to @{}. When used with both the $ and @ operators, $ @ attributes:{} can be shortened to ${}.
3. Query condition containers can be delimited with conditions:{} or simply with %{}.
4. XML containers can be delimited with xml:{}. The content in between the braces can be any valid XML fragment enclosed in one outermost XML element. Example:
5. XHTML containers can be delimited with xhtml:{}.
6. Information closure containers can be delimited with closure:{}. Example:
Mystique has (free) functions instead of methods (although Adenine methods are not really methods either). Functions are named by URIs. A function takes zero or more parameters and returns zero or more results. Parameters and results can be positional or named by URIs, just like in Adenine. Example:
Functions are automatically curried. A function is evaluated when all of its required parameters (those not marked with optional) have been provided. (This feature makes it unnecessary to have anonymous methods as in Adenine.)
A Mystique function can be executed in the long-running mode. That means that when some variables the function depends on change, the function is re-executed from the point in the function code where the changes first affect. In the previous example, if the parameter w is changed, then if it is the case that y is not null and twice x is less than or equal to y, then the second assignment statement is re-executed.
The parameter variables of a function are immutable by the function. The function can change only its local variables and its result variables (u and v in the previous example). Changes to a function's result variables may cause some piece of code in its caller to be re-executed.
In addition to local, parameter, and result variables, a function can also accesses environment variables, which are dynamically scoped. You have to declare which environment variables a function accesses using the accesses keyword:
The long-running mode in which Mystique functions are executed can be convenient for implementing agents and services that react to changes in the system. The following service classifies new email messages:
A function is executed until there is no more code left to execute, or if there is a stop statement. The following function implements the short-circuit and:
Sometimes it is desirable to ignore changes to some particular variables or to actively observe changes to some variables even if a segment of code does not refer to them. The following function
One might also need to mark a code section to run only once when a function is invoked (its stackframe is constructed) or once when a function is terminated (its stackframe is destroyed). This can be done using the initially-normally-finally construct:
for-in and while are supported. Example:
try-catch-finally and throw are supported just like in Java. Functions should also be declared with throws should they throw any exception. Example:
You must have noticed by now that Mystique is statically typed. This is a difference from Adenine and is intended to aid optimization as well as improve code readability. We can also rely on the type signature of a function to construct an appropriate UI to present it to the user.
Mystique is object-based rather than object-oriented because while one can call methods on (Java) objects, one cannot declare new classes in Mystique.
Java objects can be constructed by calling the new function passing in a "constructor function". In the following example,
The new function can take an optional Resource parameter named mystique:Allocation if the constructed object is a "slobject" and its URI has been allocated before. Example:
Adenine makes it super-easy to add data to the store and this feature tends to confuse novice Adenine programmers (as traditional programming requires explicit effort to persist data). This convenience of Adenine leads to coding sloppiness as everything is then put into the store without further thought as to which actually needs to be persisted.
It is my hope that with the various abstractions that Mystique provides, programmers no longer need to use the rdf store as a scratchpad for persisting tidbits of miscellaneous temporary system data.
Mystique is not designed for extensibility as Adenine was. You cannot add new instruction handlers or new constructs. This is a feature, chosen to facilitate optimization. After all, there has been no evidence that new instruction handlers will ever be added to Adenine by Adenine programmers.
The dynamism of Mystique will possibly cause Mystique code to be slow. However, this dynamism is needed for the UI and must be implemented in some way anyway. It is better to have a language abstraction so that optimizations can be applied systematically by the framework rather than individually by UI programmers (who may happen to be inexperienced with optimizations).