- FAQ: BETA Programming Language (version 1.11 - 08 Dec 97)

 Home >  Programming >

FAQ: BETA Programming Language (version 1.11 - 08 Dec 97)

Section 2 of 6 - Prev - Next
All sections - 1 - 2 - 3 - 4 - 5 - 6

'participate' in Norwegian'. [E. Holbaek-Hannsen, P Haandlykken, K. Nygaard:
System Description and the Delta Language. Norwegian Computing Center, Publ.
no 523, 1973]

When Kristen Nygaard was a visiting professor at Aarhus University in
1973-75, a project was started to develop a programming language based on
the Delta ideas. This language should be a (programming language) successor
to Simula and was called


In the seventies, it was often assumed that a general programming language
was not usable as a systems programming langauge. It was therefore decided
to define a systems programming langauge which should also be used to
implement Gamma. This language was called


Finally the machine level languages were referred to as


Long story:-)

So what happened to Delta and Gamma?

There is a (big) report describing Delta and there has later been some
related work on Delta including using it in a few projects, but it is no
longer being used or developed. The language


was a simplified version of Delta and the result of attempts to formalize
Delta by means of Petri Nets.

The Gamma language was never developed. During the work on Beta it was soon
realized that there was no need for Gamma. It turned out that by having
powerful abstraction mechanisms in Beta, the Gamma-level could be handled by
supplying class libraries and frameworks. You may thus think on the
Gamma-level as the libraries and frameworks of the Mjolner System.

And this is where we are today.

Some of the stuff in Delta could be handled by adding constraints to BETA
and supporting invariants and pre/post conditions. (The idea of invariants
and pre/post conditions for classes were originally suggested by Tony Hoare
for Simula. [C.A.R. Hoare: Proof of correctness of data representation, Acta
Informatics, 4, 271-281, 1972]

The Mjolner System has some libraries supporting initial versions of
constraints and invariants.

It has often discussed changing the name BETA - to avoid the beta-testing
jokes. The suggestion for a name change is Scala - Scandinavian Language and
also Scala means 'going up'... But so far it has been decided to stick with

Q19) How to format BETA programs in LaTeX?

The best way to format BETA programs in the LaTeX formatting system is by
using the lgrind LaTeX package.

You can use the following lgrind style:

beta|the BETA programming language:\
        :kw=if then else for repeat\
            do inner none this enter exit leave restart suspend\
            and or xor mod div\

This lgrind style can be made available in two different ways:

   * Included in the among standard lgrind styles. This is done by copying
     the above definition into the lgrindefs styles file, which is installed
     as part of the lgrind installation (possibly in the
     /usr/share/local/lib/lgrindefs file - dependent on your local setup).
     This installation must be done by the local systems administrator.
   * You can also copy the lgrind style onto a file in your personal file
     system. Let us for further reference assume that this file is called:

Q19.1) How to use the BETA lgrind style

When the lgrind style is made available (as above), you can use it in the
following way.

Let us assume, that you have a BETA source file called

   * If the lgrind style is saved among the standard lgrind styles, you

        lgrind -lbeta -i > prog.tex

   * If the lgrind style is saved in your personal file system, you execute:

        lgrind -lbeta -d $HOME/lgrind/lgrindefs -i > prog.tex

You are now ready to include the BETA source into a LaTeX document. You do
this by inserting the following in the start of the LaTeX document:


Please note, that you only need to insert this once.

This implies, that the lgrind LaTeX style is available. At the position in
the document, where you wish the BETA source code, you just insert one of
the following:

   * \lgrindfile{prog}
     which will simply include the file at that point of text, and will draw
     horizontal lines before and after the listing.
   * \lagrind[htbp]{prog.tex}{caption}{label}
     which will put the listing also within a figure environment, using the
     float options, caption and label you gave.

You insert one lgridfile or lagrind command for each piece of BETA source
code, you wish to include in the document.

PART II: Language Issues


L01) What features do BETA have?

BETA replaces classes, procedures, functions, and types by a single
abstraction mechanism, called the pattern. It generalizes virtual procedures
to virtual patterns, streamlines linguistic notions such as nesting and
block structure, and provides a unified framework for sequential, coroutine,
and concurrent execution. The resulting language is smaller than Simula in
spite of being considerably more expressive.

The pattern concept is the basic construct. A pattern is a description from
which objects may be created. Patterns describe all aspects of objects, such
as attributes and operations, as seen in traditional object-oriented
languages, but also aspects such as parameters and actions, as seen in

Objects are created from the patterns. Objects may be traditional objects as
found in other languages, but they may also be objects which correspond to
procedure or function activations, exception occurrences, or even coroutines
or concurrent processes.

Objects may be created statically or dynamically and the objects are
automatically garbage collected by the runtime system when no references
exist to them any longer.

Patterns may be used as superpatterns to other patterns (the subpatterns).
This corresponds to traditional class hierarchies, but since patterns may
describe other types of objects, inheritance is a structuring means
available also for procedures, functions, exceptions, coroutines, and

Patterns may be virtual. This corresponds to traditional virtual procedures
but again the generality of the pattern construct implies that also classes,
exceptions, coroutines, and processes may be virtual.

Virtual patterns in the form of classes are similar to generic templates in
other languages. The prime difference is that the generic parameters (that
is, the virtual class patterns) may be further restricted without actually
instantiating the generic template. The generality of the pattern also
implies that genericity is available for classes, procedures, functions,
exceptions, coroutines, and processes.

Patterns may be be handled as first-order values in BETA. This implies the
possibility of defining pattern variables which can be assigned pattern
references dynamically at runtime. This gives the possibilities for a very
dynamic handling of patterns at runtime.

You can find more introductions to the BETA language by looking at the BETA
Language Tutorial.

L02) What changes have been made to the BETA language definition?

The BETA language definition has been stable since 1992, apart form the
following minor changes:

L02.1) String Literals as References

The pattern text enters and exits a char repetition. This means, that a text
may be initialized using constant strings as follows:

      t: @text;
   do 'hello' -> t;

Many operations involving texts, however, takes references to texts as
enter/exit parameters. This is mainly for efficiency reasons.

To allow easy invocation of such operations on string literals, the
following is also allowed:

      t: ^text;
   do 'hello' -> t[];

The semantics of this is, that a text object is instantiated, initialized by
the constant string, and finally assigned to the text reference.

L02.2) Simple If

Often the following If statement is used:

      b: @boolean;
   do (if b//TRUE then ... else ... if);

The current version of the compiler supports an extension to the BETA
language called Simple If. This extension means, that the case-selector //
may be omitted, if the evaluation on the left hand side exits a boolean.
That is, the above may be written

      b: @boolean;
   do (if b then ... else ... if);

Like in the general if-statement, the else part if optional.

L02.3) Xor Primitive

An xor primitive is supported as a basic operation on booleans. That is

      b1, b2, b3: @boolean
   do b1 xor b2 -> b3

is possible.

L02.4) Short-circuit Boolean Expressions

Boolean expressions are implemented as short-circuit. That is, in

      B1 or B2

B2 is not evaluated if B1 is true, and

      B1 and B2

B2 is not evaluated if B1 is false.

L02.4) Labelled imperatives

Labelled imperatives were previously defined in the language in two forms:

   L: Imp;


   (L: Imp1; ...; :L)

The second form has now been removed from the language. Instead, the
compiler offers the form

   L: (# do Imp1; ... #)

Note that this form is implemented very efficiently in the case where there
are no declarations in the object descriptor (i.e. between (# and do).

L03) How do I deal with concurrency in BETA?

The processes of BETA (concurrent objects) are based on a simple
fork-mechanism and semaphores. Based on these mechanisms, pattern
definitions are available for shared variables in the form of monitors, and
for synchronous process communication based on a port communication
metaphor. The abstractions also contain facilities for utilizing future
values in connection with process interactions.

L04) How do I deal with persistence in BETA?

The Mjolner System contains a library that implements a persistent store for
BETA objects. Any BETA object can be stored into the persistent store and
subsequent obtained from the store in a type-safe way. There are no
requirements that the persistent objects must inherit from any specific
superpattern, and persistent objects are fully type-checked both when saved
in the persistent store, and when retrieved from the persistent store.

L05) How do I deal with distribution in BETA?

The Mjolner System contains a distributed object system in which BETA
objects may reside on different hosts, and communicate transparently with
each others, just as if they were residing on the same host. The objects may
even be residing on different host types (e.g. on Macintosh and Unix
workstations, respectively).

L06) How do I deal with exception handling in BETA?

Exception handling is dealt with through a predefined library containing
basic exception handling facilities. The exception handling facilities are
fully implemented within the standard BETA language in the form of a library
pattern, and the usage is often in the form of virtual patterns, inheriting
from this library pattern.

L07) Can classes be treated as first-order elements in BETA?

Yes, they can. This is possible by using the pattern variable construct in
BETA. A pattern variable may dynamically be assigned pattern references.
Pattern variables may be used to dynamically create instances of the
pattern, currently contained in the pattern variable.

L08) What about garbage collection in BETA?

Garbage collection is conducted automatically by the BETA runtime system
when it is discovered that no references to the object exist. The garbage
collection mechanism is based on generation-based scavenging. The
implemented garbage collection system is very efficient.

L09) How do I create a "parameterized class"?

A parameterized class (a template in C++ or a generic class in Eiffel) is
created in BETA by using the virtual pattern mechanism. The generic
parameter is specified as a virtual attribute of the pattern, and
subpatterns of this patterns may now make further restrictions on the
generic parameter by further binding the virtual attribute. Generic
instantiation is done by either making a final binding of the virtual
attribute, or by instantiating an object directly from the pattern.

L10) What is the difference between a virtual binding, a further binding and
a final binding (i.e. between :<, ::<, and ::)?

To illustrate the difference between new and further-bindings, consider

   p:  (# v:<  (# do ...; inner #) #);
   q: p(# v::< (# do ...        #) #);
   r: p(# v:<  (# do ...        #) #);

in which a pattern p with a virtual attribute v, and two subpatterns, q and
r, are declared. Pattern q further-binds p's virtual attribute, while
pattern r declares a new virtual attribute v which has no connection to p's
v, except that it happens to have the same name. [This may or may not be
what the programmer intended, so perhaps a warning should be issued in this

Thus, if rp is a pointer of type p, and rp happens to denote a q object,
then calling rp.v will cause q's v part to be executed in addition to p's
(because v has been further-bound in q). However, if rp denotes an r object,
then calling rp.v will cause only p's v part to be executed, not r's
(because p's v attribute has not been further-bound). [Of course, if rr
denotes a pointer of type r, then rr.v will cause r's v part to be

A final binding has the same effect as a further-binding, except that it
specifies that the virtual may not be further-bound from this point on.
There are (at least) three different reasons why you might want to use final

   * Modelling: Final-bindings are often considered to be a nice feature
     from a purely object-oriented modelling perspective since it indicates
     that the model is no longer extensible with respect to this attribute.
   * Efficiency: The compiler is able to generate tighter code when it is
     known that a pattern is not virtual (any longer).
   * Inheritance: It is not allowed to inherit from a virtual pattern; but
     it is ok to inherit from a final-bound one.


L11) What about invariants in BETA?

Invariants are not an integrated part of the BETA language. However, it is
possible to create an invariant system as a framework or library, entirely
written in BETA. In the Mjolner System, an experimental invariant system is
available. The system offers class invariants as well as pre- and
post-conditions for operations. The invariant system also offers the ability
to control whether the invariants are checked or not, either on individual
object basis or system-wide.

L12) What about change propagation in BETA?

Change propagation (as in Model-View-Control - MVC) is also available in
BETA (with extended facilities). Change propagation is available as an
experimental part of the current system.

L13) What about futures in BETA?

Futures are used in concurrent programming to return results from a
concurrent computation, even before they have been calculated. The result
can then be passed around as any other value, and only when an attempt is
made to access it, the reader will be blocked until the result is made
available by the concurrent computation. Based on the existing BETA
facilities, futures can easily be implemented, and an experimental futures
library is available as part of the current system.

L14) Why can variables declared in execution blocks not be accessed in

Consider the following code fragment:

   P: (# do ...; (# x: ... do inner P #); ... #)
   PP: P(# do ... #)

According to the BETA visibility rules, x may not be referenced from the
do-part of PP. Why?

The answer lies in the fact that patterns may have more than one inner
section. Consider the following (slightly modified) example, where inners
are placed in different inserted descriptors, each containing declarations
of different sets of local variables:

   P: (#
      do ...;
         (# x: ... do inner P #);
         (# y: ... do inner P #);
   PP: P(# do ... #)

In this case, the do-part of PP is executed twice via inner, but with
different sets of local variables (x and y, respectively). It is therefore
meaningless to refer to any one of these in the do-part of PP.

L15) How do I implement a copy (or clone) operation?

It is often useful to be able to make a genuine copy of an object. It is
currently being discussed to introduce a 'clone' operation into the object
pattern, which should take care of this copying automatically, but no
decision has been made as to how and when.

Until then, the following trick does the job:

   P: (# (* internal P structures *)
         copy:< (* generic copy operation *)
           (# copyType: ##P;
              theCopy: ^P;
           do this(P)##->copyType##;
              (* insert here code to  implement the copying
               * of internal P structures into theCopy *)
              INNER copy;
              (* possible finalization of the copying process *)
           exit theCopy[]

   Q: P(# (* internal Q structures *)
            (# Qcopy: ^Q
            do theCopy[]->Qcopy[];
              (* insert here code to  implement the copying
               * of internal Q structures into Qcopy *)
              INNER copy;
              (* possible finalization of the Q copying process *)

   R: Q(# (* internal R structures *)
            (# Rcopy: ^R
            do theCopy[]->Rcopy[];
              (* insert here code to  implement the copying
               * of internal R structures into Rcopy *)
              INNER copy;
              (* possible finalization of the R copying process *)

Given the declarations

   a: @R;
   aCopy: ^R;



will make a copy of the a object with the proper qualification (here R), and
a state that is a copy of the state of a.

Note: The

      Rcopy: ^R
   do theCopy[]->Rcopy[]

part of the copy further binding is an inconvenience, but is necessary to
persuade the type system to allow remote access to the R-parts of the
theCopy object.

L16) Why doesn't BETA have multiple inheritance?

[Ole Lehrmann Madsen ( writes:]

I shall try to explain why there is no (traditional) multiple inheritance in
BETA. Please note that I am not trying to argue against MI. The following is
only an attempt to explain why it is not in BETA.

When BETA was designed we did not think that the concept of multiple
inheritance was ready for being incorporated in the language. One of the
main design goals for BETA was that it should be good for modelling. Most
usages of MI seemed to be for pure code reuse, i.e. a new class may be
defined by inheriting from a number of classes and then redefining the parts
that should differ. Often this is done without there being any conceptual
relation between the new class and the ones it inherits from. We did not
like that way of using inheritance.

MI in BETA should be there to model classification hierarchies which are
non-tree structured. In my experience, such hierarchies are rare in
practice. What is more common is that you may want several independent
tree-structured classification hierarchies for the same objects. A set of
person objects might be classified according to their profession,
nationality, and religion. This gives three class-hierarchies. People often
handle such situation using MI, but this will merge the hierarchies in a way
that makes it difficult to identify the three original ones.

We would like to support such independent classification hierarchies in
BETA, but no concrete proposal exists.

The various proposals for solving name conflicts and overlapping
superclasses also seemed rather complex. We did not want the semantics of
basic constructs to be complicated to understand.

For BETA there are a number of additional problems:

   * Virtual patterns from a common superclass may have conflicting bindings
     in the superclasses:

        A: (# V:< A1; ... do ... inner ... #);
        B: A(# V::< A2; ... do ... inner ... #);
        C: A(# V::< A3; ... do ... inner ... #);
        D: B & C (# V:: A4; ... do ... #);

     (The syntax B & C has tentatively been used for MI in BETA.)

     Here A2 and A3 must both be subclasses of A1, and A4 must be a subclass
     of both A2 and A3. (In her Ph.D. Thesis, Kristine Thomsen defined a
     language along these lines, which handled virtual bindings a la those
     in BETA. It should be available from the Computer Science Department,
     Aarhus University.)

   * The semantics for combining inners of multiple superclasses must also
     be defined. In the example above, should B's do-part be executed before
     C's or vice versa? Since we are not in favour of making the order of
     superclasses significant, we were considering letting the execution
     order of B and C be non-deterministic, in the sense that the
     implementation may execute B or C in any order. (Thomsen's thesis also
     deals with combing inners and proposes a number of other alternatives.
     You may also want to take a look at: K. S. Thomsen: "Inheritance on
     Processes, Exemplified on Distributed Termination Detection",
     International Journal of Parallel Programming, pages 24-37, November

Finally, we have not felt an strong need to support MI in the traditional
sense, since BETA has other means for handling some of the most common MI

In BETA you may inherit from part-objects and at the same time further-bind
its virtuals:

   A: (# f:< ... #);
   B: (# g:< ... #);
   C: (# ...
         X: @A(# f::< (# ... #); ... #);
         Y: @B(# g::< (# ... #); ... #);

X and Y are singular part-objects; due to BETA's block structure the virtual
bindings of f and g may refer to variables in the enclosing C-object.

Given the declaration W: ^C, the functions f and g may be invoked as W.X.f
and W.Y.g. The difference from MI is that you have to qualify using X and Y.
Some people think of this as an inconvenience; others think of it as an
advantage since it forces them to be explicit about name conflicts between A
and B. If you prefer writing W.f and W.g, you may define f and g functions
in C and let them forward the calls to X.f and Y.g.

Given the declaration V: ^A, then W.X[]->V[] is possible, and an invocation
of V.f calls the further-binding of f in X, thereby possibly
accessing/changing the state of C.

To sum up, this form of multiple inheritance via part objects is very
similar to non-overlapping inheritance in C++.

As a final example, consider the following well-known MI case:

                 /      \
   WindowWithBorder    WindowWithTitle
                 \      /

In BETA this may be handled using block-structure

     (# ...
        Border: (# ... #);
        Title: (# ... #);
   W1: @Window(# B: @Border; T: @Title #);
   W2: @Window(# T1,T2: @Title #);

Here W1 has a border and a title, whereas W2 has no border and two titles.
(For a further discussion, see K. Osterby: "Parts, Wholes, and Subclasses",
Proceedings of the 1990 European Simulation Multiconference, pages 259-263,

To sum up, we did not think that traditional MI has been worth the
complications it will add to the language, since many of the MI cases can be
handled by other means. We are, however, still discussing MI, and it may end
up being supported more directly.

L17) What is the rationale behind the syntax of BETA?

[Ole Lehrmann Madsen ( writes:]

When we designed BETA, we spent a lot of time discussing syntax - it is one
of those things people can really disagree about. We tried to develop what
we considered to be a nice and readable syntax with as few long keywords as

The following type of brackets are used:

     (# ... #)     object
     (* ... *)     comment
    (if ... if)    if-imperative
   (for ... for)   for-imperative

We did consider using { and } for objects or comments, but ended up not
doing it; we did not feel a strong need to have BETA look like C.

As we did not like long keywords (as in Pascal or Ada), BETA uses symbols
like @, ^, |, and :< instead. We believe that for a small language like
BETA, it is an advantage to have a compact syntax. This way, you can have
more code on a page or in a window. (Of course, {,} is shorter than (#,#),
but we preferred the syntax to be consistent with (if,if), etc.)

It is not our experience that the syntax of BETA presents any obstacle to
learning the language. BETA has very few constructs (and symbols), and while
they may seem strange at first, they are easy to learn and use. Try it!

You can find a quick overview of the BETA syntax by looking at the BETA
Quick Reference Card

L18) How do the scope rules of BETA actually work?

The BETA scope rules may seem slightly complex to the new BETA programmer,
but are actually rather intuitive and simple. There are three visibility

  1. Names declared in the descriptor itself are visible within the
  2. Names declared in the superpattern of a descriptor are visible within
     the descriptor.
  3. Names declared in outer blocks (i.e. enclosing descriptors) are visible
     within the descriptor.

These rules are applied in order to find the definition for a given name

   * Start by using rule 1, looking for a local declaration.
   * If not found, then use rule 2 to find the declaration in the
     superpattern (if the descriptor has one). While using this rule, you
     may apply rule 1.
   * If still not found, then use rule 3 to find the declaration in the
     enclosing descriptors. While using this rule, you may apply rule 1 and

Note: This method implies that it is possible to reuse the same name for
different declarations, as long as the declarations are in different

To see how the rules interact, take a look at the example program below. It
illustrates most of the combinations, and has the resulting output is shown
in comments after each imperative.

   (# a: (# do 1->screen.putint #);
      P1: (# do a; INNER P1 #);
      P2: (# a: (# do 2->screen.putint #);
          do a
      P3: P1(# do a #);
      P4: P1(# a: (# do 3->screen.putint #);
          do a
      P5: P1(# foo1: (# do a; inner foo1 #);
               foo2: (# a: (# do 4->screen.putint #)
                     do a; inner foo2
      P6: P5(# a: (# do 5->screen.putint #);
               foo3: (# do a; inner foo3 #);
               foo4: foo1(# do a; inner foo4 #);
               foo5: foo2(# do a; inner foo5 #);
      P: @P6;
      a;                (*   1 *)
      P1;               (*   1 *)
      P2;               (*   2 *)
      P3;               (*  11 *)
      P4;               (*  13 *)
      P5;               (*   1 *)
      P6;               (*   1 *)

      P.foo1;           (*   1 *)
      P.foo2;           (*   4 *)
      P.foo3;           (*   5 *)
      P.foo4;           (*  15 *)
      P.foo5;           (*  44 *)

      P.foo1(# do a #); (*  11 *)
      P.foo2(# do a #); (*  44 *)
      P.foo3(# do a #); (*  51 *)
      P.foo4(# do a #); (* 151 *)
      P.foo5(# do a #); (* 444 *)


L19) What is a pattern?

The following is an attempt to explain the pattern concept. The description
is divided into two parts: a description in the form of examples, and a more
abstract explanation.

To begin with, think of a pattern as a generic word for the concepts class,
procedure and function. This is not all there is to it, but it will get you
started. In BETA, a pattern is anything starting with (# and ending with #).
As a simple example, here is a function that multiplies two numbers:

   multiply: (# a,b: @integer;
             enter (a,b)
             exit a*b

The multiply pattern takes two integers, a and b, and returns their product.
These kinds of patterns are often called functional patterns, since their
use correspond to functions (or procedures) in other languages. In BETA, a
call to multiply might look like:


putInt is a procedure that writes the result on the screen.

As another example, let's build a stack class in the typical object-oriented

   stack: (# content: [100] @integer;
             currentSize: @integer;
             push: (# e: @integer;
                   enter e
                   do currentSize+1->currentSize;
             empty: (# exit (currentSize=0) #);
             pop: (# e: @integer;
                  do content[currentSize]->e;
                  exit e

Now, stack is also just a pattern. You may call it a class pattern since its
meant to be used as a class: to make instances, the actual stacks. And just
in case you were wondering: Yes, the push, empty, and pop methods defined
for stack are also patterns (functional/procedural patterns), defined inside
the stack pattern.

BETA offers a lot of extra functionality which could make the example much
more realistic (information hiding, generic stacks, exceptions due to
overflow, dynamic expansion of the stack capacity, etc.), but let's keep the
example simple.

Having shown a few practical examples, here's the more elaborate

A pattern is used for instantiating objects (static objects, dynamic
objects, inserted objects, etc.). A pattern declaration in its full form
looks like this (other forms below):

   P: S(# decl1; decl2; ... decln;
       enter enterlist
       do imperatives
       exit exitlist

This declares P as a (direct) subpattern of S. (S thus is the (direct)
superpattern of P.) S may be omitted, in which case object (the direct or
indirect superpattern of all patterns) is assumed. Each part (declarations,
enter part, do part and exit part) can be omitted. (Thus "P: (# #);" is

Each declaration can be a declaration of a pattern, a virtual pattern, a
further or final binding of a previously declared virtual pattern, a static
item, a dynamic item, a static component, a dynamic component, a repetition

Section 2 of 6 - Prev - Next
All sections - 1 - 2 - 3 - 4 - 5 - 6

Back to category Programming - Use Smart Search
Home - Smart Search - About the project - Feedback

© | Terms of use