Tutorial: Overview of Declarations


  The declaration syntax in gbeta is very simple and consistent. It is also based on "funny" characters, and this makes it hard for the casual reader to understand what is going on in a gbeta program, since the reader's basic assumptions about the meaning of syntax do not reveal enough. The trick is to focus on the few "funny" characters right after the colon, they tell what kind of attribute is being declared here.

The syntax specifications below mention the <Merge> and the <AttributeDenotation> syntax categories. For now, think of a <Merge> as a main part or an identifier, and think of an <AttributeDenotation> as an identifier. The examples go slightly beyond what has been presented sofar, so don't despair if some of the examples can not be fully explained by now.

Declarations of patterns

A pattern is declared by the simplest form of declarations:

<Name> ":" <Merge>

A pattern is the language concept in gbeta which takes care of every aspect of structure description. Whenever a piece of substance is created, its structure is created according to some pattern, and that again consists of predefined and/or main part specified building blocks. To be precise, a pattern also specifies a run-time context, i.e. one or more enclosing objects (origins). Since a pattern includes the specification of some enclosing objects, it does not exist before run-time, and patterns associated with the same syntax (main parts) are still different if their enclosing objects are different. The static analysis works with patterns relative to a given run-time environment: take the analysis version of a pattern and provide it with a concrete run-time context, and there is your pattern! The fact that the run-time context is included into patterns makes it possible to create substance directly from patterns. Here's an example of some pattern declarations:

p: (# q: (# #); 
      r: (# s: (# #);
            t: (# #)
         #);
      u: boolean
   #);
v: (# #)

Declarations of objects

Objects (part objects) are declared using the "@" substance flag:

<Names> ":" "@" <Merge>

A variant declaration specifies that the object should have its own execution stack:

<Names> ":" "@" "|" <Merge>

This is used when creating concurrent threads or co-routines. A few examples:

i,j: @integer;
f: @real;
y: @|(# g: @real do INNER #);
x: @(# k,l.m: @boolean #) & somePattern

Declarations of object references

To allow a name to refer to varying objects during the execution of a program, it is necessary to introduce the notion of object identity. When using the "@" substance flag, a name is declared to denote an object, and that's it, but when using the "^" object identity flag, the name is declared to denote the identity of an object, and by changing the state of this attribute, it lets the name refer to different objects at different times, or possibly to "no object," NONE.

<Names> ":" "^" <AttributeDenotation>

Again, there is a concurrency biased version:

<Names> ":" "^" "|" <AttributeDenotation>

The headline of this section mentions "references" since object identity attributes are often implemented by pointers to memory cells and often denoted "pointers" or "references." Hence, we will use the terms object reference attribute or just object reference.

The <AttributeDenotation> on the right hand side of the declaration specifies the qualification of the object reference attribute. The qualification is a type constraint on the objects which can be referred to by the attribute. The constraint is that the pattern of the referred object should be a specialization of the pattern of the qualification. In other words, the qualification promises a certain richness of the interface, and the actual object will at all times support an interface which is at least that rich.

A few examples are:

ir1,ir2: ^integer;
pr: ^p;
conc_pr: ^|p;

Declarations of virtual patterns

A virtual pattern is a pattern. But a virtual declaration does not declare the precise pattern value, it declares an upper bound on the type (or a lower bound on the structure) denoted by the declared name. We'll return to this in more detail later. there are three variants; the virtual declaration:

<Name> ":" "<" <Merge>

.. the virtual further-binding:

<Name> ":" ":" "<" <Merge>

.. and the virtual final-binding:

<Name> ":" ":" <Merge>

They look like this:

p: (# v:< (# #)#); 
q: p(# v::< (# #)#);
r: q(# v:: (# #)#)

Declarations of pattern references

Just like we can have a name which denotes an object and another name which may denote different objects at different times, we can also have the dynamically varying version of a pattern declaration:

<Names> ":" "##" <AttributeDenotation>

This declares the names to be attributes whose values are patterns. The patterns must be specializations of the pattern denoted by the right hand side of the colon. This is also covered in more detail later. An example is:

pr1,pr2: ##p

Declarations of repetitions

A repetition in gbeta corresponds to what is often designated an array in other languages. Most attributes can be declared in repeated versions:

<Name> ":" "[" <Index> "]" "@" <Merge>

<Name> ":" "[" <Index> "]" "@" "|" <Merge>

<Name> ":" "[" <Index> "]" "^" <AttributeDenotation>

<Name> ":" "[" <Index> "]" "^" "|" <AttributeDenotation>

<Name> ":" "[" <Index> "]" "##" <AttributeDenotation>

The <Index> is an expression whose (integer) value is obtained when the enclosing object is instantiated, and that becomes the initial number of elements in the repetition. In practice, it looks like this:

txt: [100] @char;
conc_xrs: [a+b] ^|x;
prs: [0] ##p

The next section introduces the notion of coercion which denotes the transformation processes that are used to obtain a certain category of entity (e.g. a pattern) from a given entity (e.g. an object). In other words, coercion compensates for the fact that sometimes a declaration has another "funny character" flag than what is needed in the usage context.

 


Signed by: eernst@cs.auc.dk. Last Modified: 3-Jul-01