Special BETA Constructs for JVM/CLR Support
To facilitate interoperability with JVM and CLR, a
number of special constructs have been introduced into BETA. These
constructs are mostly temporary workarounds, to get things up and
running, and will be attempted handled in a more elegant way in a
future release.
Special Prefix Patterns
A number of special superpatterns are available, which when used as
prefix for a pattern will modify the
way the pattern is mapped to JVM/CLR code. These are:
ExternalClass
The pattern ExternalClass
is
used to declare classes originating from outside BETA, e.g. Java or C#
in BETA syntax. This is currently needed to allow the BETA compiler
to support type-safe use of non-BETA classes. As this can be quite
tedious to do by hand, a tool has
been made, that will read the binary external classes and emit BETA
declarations corresponding to them. In a future version of the BETA
compiler, this may be automated.
See ExternalClass below for specific usage of
ExternalClass
.
class
The pattern class
is used to restrict a pattern to class
usage only. As a BETA pattern can be used as both a class/type and as
a method, normally code will be generated for both usages. Using
class
as prefix for a pattern will make the compiler not
generate code for the usage of the pattern as a method.
class
is only used for patterns implementing
functionality in BETA, i.e. not for classes in Java/.NET.
proc
The pattern proc
is used to restrict a pattern to method
usage only. As a BETA pattern can be used as both a class/type and as
a method, normally code will be generated for both usages. Using
proc
as prefix for a pattern will make the compiler not
generate code for the usage of the pattern as a class.
proc
is used both for patterns implementing
methods in BETA and for methods in external classes.
cons
Using cons
as a prefix of a pattern tells the compiler to
generate special code for the pattern to be used as a
constructor. These methods have special internal names and
calling conventions in the generated byte codes. Specifying
cons
implies proc
, i.e. the pattern cannot
be used as a class.
There may be specified more than one constructor, as long as they
differ in enter
lists (corresponding to
signatures in the byte code).
cons
can be used both in a BETA pattern implementing
functionality to be used from BETA and/or external languages, and in
ExternalClass
declarations.
However, there is a problem in the current implementation: If the
constructor is to be called from BETA code, it should include a local
variable of the same type as the class it is creating, and the
constructor should return this value, e.g.:
Foo:
(# ...
create: cons
(# result: ^Foo;
exit result[]
#);
#)
On the other hand, if the constructor is to be called from outside
BETA, you should not declare the variable and the exit part,
since this will lead to illegal byte code.
See Constructors below for further
information on how to specify and use constructors in BETA patterns.
static_proc
Using static_proc
as a prefix for a method in an
ExternalClass
specification (as opposed to just
proc
) tells the BETA compiler that this is a
static method, which has a special calling convention in the
byte code, and which is invoked on the external class itself and not on
an object.
Notice that specifying static_proc
as a prefix of a
pattern implementing functionality in BETA is not supported;
the compiler will currently not complain, but generate non-functional
(illegal) byte code.
static_cons
Using static_cons
as a prefix for a method in an
ExternalClass
specification (as opposed to just
cons
) tells the BETA compiler that this is a
static constructor which has a special calling convention in the
byte code, and which is invoked on the external class itself and not on
an object.
Notice that specifying static_cons
as a prefix of a
pattern implementing functionality in BETA is not supported;
the compiler will currently not complain, but generate non-functional
(illegal) byte code.
Notice, that since these are to be used as superpatterns, you cannot
specify a "real" superpattern. We hope to introduce a notation a la
the .NET attributes into BETA, to allow for specifying these
special behaviours without using superpattern notation.
Specifying JVM Packages
BETA code compiled with jbeta
by default is emitted to
the JVM package named beta
. If another package is to be
used (e.g. to because some java code is to use the BETA generated
code), a new BETA property has been defined:
PACKAGE 'org.foo.bar';
This property can be added in the beginning of the file, typically just
after ORIGIN
.
To access an external class, you just make a BETA pattern with the
prefix ExternalClass
, and declares the various methods in
this external class, you want to access, as local patterns with
prefixes
proc
/static_proc
/cons
/static_cons
.
You furthermore specify the fully qualified class name of the
class in the form of an assignment to an attribute called
className
inside the do-part of the
ExternalClass
. Finally you can declare (non-static) fields of the
external objects, just by declaring dynamic BETA references with the
correct qualification.
As an example, here is an excerpt of the ExternalClass
declaration corresponding to the Java String
class:
String: ExternalClass
(#
_init: cons (* constructor *)
(# result: ^String;
exit result[]
#);
...
_init_ArrayOfC: cons (* constructor *)
(# result: ^String;
arg1: [0]@char;
enter (arg1[])
exit result[]
#);
...
compareTo_String: proc (* overloaded compareTo *)
(# result: @int32;
arg1: ^String;
enter (arg1[])
do 'compareTo' -> procname;
exit result
#);
compareTo_Object: proc (* overloaded compareTo *)
(# result: @int32;
arg1: ^Object;
enter (arg1[])
do 'compareTo' -> procname;
exit result
#);
...
do 'java/lang/String' -> className;
#)
And here is the corresponding .NET declarations:
String: ExternalClass
(# ...
_init_ArrayOfChar: cons (* constructor *)
(# result: ^String;
arg1: [0]@char;
enter (arg1[])
exit result[]
#);
_init_char_int32: cons (* constructor *)
(# result: ^String;
arg1: @char;
arg2: @int32;
enter (arg1, arg2)
exit result[]
#);
...
CompareTo_Object: proc (* overloaded CompareTo *)
(# result: @int32;
arg1: ^Object;
enter (arg1[])
do 'CompareTo' -> procname;
exit result
#);
CompareTo_String: proc (* overloaded CompareTo *)
(# result: @int32;
arg1: ^String;
enter (arg1[])
do 'CompareTo' -> procname;
exit result
#);
...
do '[mscorlib]System.String' -> className
#)
You can then instantiate
String
objects in BETA using these patterns, and
subsequently access methods and fields in these objects.
It may seem confusing that the className
specification
resembles a statement, and a future version of the BETA compiler may
support an improved way of specifying this.
Notice, that two tools have been
provided, that can be used to convert an external class to corresponding BETA
declarations instead of writing these by hand.
In a future version of the compiler, this may be handled
automatically.
Specializations of ExternalClasses
In BETA you can declare a subpattern of a pattern with prefix
ExternalClass
. This may mean two different things: Either
you are just declaring an interface to another external class, which
happens to be a subclass of the first external class you declared,
or you want to implement a specialization of the external
class in BETA.
To distinguish between these two situations, a subtle solution is
currently supported by the compiler:
JVM Interfaces
The Java virtual machine use different calling conventions when
calling interface-methods and class-methods. To inform jbeta
about
this, the pipe character '|' should be used as the first character when
specifying the className
for :
do '|.....' -> className;
CLR value types
The .NET CLR use different calling conventions when
calling methods on reference types and valuetypes. To inform nbeta
about
this, the ad character '@' should be used as the first character when
specifying the className
for a value type:
do '@...' -> className
There are currently four ways to declare a constructor in BETA code:
_init
Specifying a pattern with the special pattern name _init
(one underscore) is a rudimentary way of declaring one
constructor in a BETA pattern. It is now deprecated, as it only allows
for the declaration of one constructor. Use the
cons prefix instead.
cons
The special prefix cons
was described
above, and is the recommended way to specify an
instance constructor in a BETA pattern or ExternalClass
.
static_cons
The special prefix static_cons
was described
above, and is the recommended way to specify an
static constructor in an ExternalClass
declaration.
__init
Specifying a pattern with the special pattern name __init
(two underscores) is a way of declaring one constructor,
which does not require a surrounding object as argument, when called
from outside BETA. Normal constructors have a hidden (synthetic)
first argument being the surrounding BETA object. This must be
supplied when the constructor is invoked.
The surrounding object is still needed, though, and to set up this, a
special low-level primitive is suplied, that must be called
inside the do-part of the __init
pattern, preferably as
the first thing done:
This special statement will make the BETA compiler do two things:
- Create a
betaenv
object
- Set up the surrounding object reference of the object being
created to be this
betaenv
object.
There are a number of problems and limitations with the current
implementation of parameterless constructors:
- The name
__init
does not very well signal that this
is a special pattern. Should probably be changed to, e.g. a prefix
default_cons
.
- The compiler ought to set up the
betaenv
object
automatically
- You should only specify an
__init
in a BETA library
to be called from Java/.NET, not as part of an
ExternalClass
declaration
- If you specify an
__init
you should not
specify any _init
and/or cons
patterns. If
you do so, currently the parameterles constructor will not be
generated. As a side effect, a pattern containing an
__init
cannot be instantiated using standard
BETA syntax &Foo[] -> ...
. See
Instantiation below.
- You should only specify
__init
in an outer-most
pattern, i.e. one that is declared in LIB:attributes
. For
inner classes, the surrounding object is automatically set up. If you
specify an __init
for an inner pattern, illegal bytecode
will result.
- Using multiple BETA patterns each with an
__init
constructor may lead to multiple betaenv
instances. This
should not be a problem.
- You should not specify an
__init
constructor
for a BETA pattern, that has another BETA pattern as prefix. This will
currently cause illegal byte code to be generated. Instead, make a
dynamic part object containing an instantiation of the pattern, you
would have liked to use a prefix, and delegate calls for the prefix
into this local object.
- You should not declare any static references ("static"
here being in the BETA meaning, e.g.
X: @P
, not to
be confused with static
variables in Java/.NET) in a
pattern having an __init
constructor. The problem is that
the compiler will currently try to instantiate the static references
before the betaenv
is set up. This only pertains to
non-simple patterns; basic types like integer
,
char
, etc. can be specified statically.
There are a number of ways to instantiate objects when using
constructors:
- Use
&Foo[] -> ...
This is the normal BETA instantiation mechanism. For a BETA pattern,
this creates the object, and sets up the surrounding object in the
usual BETA way. This means that the normal BETA constructor (either
implicit or a declared _init
(one underscore) or
cons
without declared arguments) is called.
If Foo
is a specialization of an
ExternalClass
, this instantiation will lead to a call of
a parameterless constructor in the external class.
- Use
(arg1, arg2, ..., argN) -> &Foo -> ...
This is an extension of the normal BETA instantiation mechanism. The
effect is like the one described above, except that a constructor with
declared arguments (arg1, arg2, ..., argN)
is called. If
Foo
is a normal BETA pattern, it must have a
declared _init
(one underscore) or cons
with
the specified parameter list for this to work.
- Call method declared as
cons
on object
This is the prefered method for instantiating objects via an
instance constructor in an ExternalClass
.
However, it can be used internally in BETA too, see
cons above.
- Call method declared as
static_cons
on
ExternalClass
This is the prefered method for instantiating objects via a static
constructor in an ExternalClass
.
It can not be used internally in BETA, see
static_cons above.
Overloaded Methods
In external classes, method overloading is commonly
used. This means that a number of methods in a class may have the same
name, but different parameter lists and possibly return values
(neither Java nor .NET allows for overloaded methods to be
distinguished by different return values only).
BETA does not have overloaded pattern names. To declare interface to
an ExternalClass
with two or more methods with identical
names, in BETA just make corresponding proc
(or
static_proc
) declarations, where you specify the actual
(identical) external name as a string argument to an attribute called
procname
in proc
/static_proc
. E.g.
foo: ExternalClass
(# bar_I: proc
(# i: @integer
enter i
do 'bar' -> procname;
#);
bar_C: proc
(# c: @char
enter c
do 'bar' -> procname;
#);
#);
It may seem confusing that the procname
specification
resembles a statement, and a future version of the BETA compiler may
support an improved way of specifying this.
Not Yet Specifiable
The following do not yet have textual BETA representations, and
thus cannot be expressed directly in BETA. To access such entities,
you will currently have to make wrapper classes in Java/C#.
- Static fields
- .NET enumerations