Currently the code produced by asdlGen
uses the standard memory management
facilities of the output language. However, asdlGen
, assumes a garbage
collect environment and does not automatically provided deallocation
functions in languages without garbage collection. For languages like C and
C++ that do not have garbage collection there exist freely
available packages such as the
Boehm-Weiser Conservative Collector.
Future plans are to provide interfaces to allow for finer grain
control over aspects of allocation and deallocation for languages
without garbage collection.
The code that pickles data assumes that the data structures are acyclic. If
a cyclic data structure is pickled the pickler will not terminate. asdlGen
does not enforce this acyclic property in C, C++, and Java. It is the
responsibility of the programmer to do so. The lack of enforcement gives the
programmer greater flexibility when manipulating data structures. In future
there will be an option to produce code that enforces acyclic data
structures for those who would rather avoid the dangers associated with the
extra flexibility.
By default all languages produce constructor functions for each type mentioned in the descriptions. For languages that support overloading (Java and C++) two constructors are produced for sum type constructors that contain attributes. One constructor contains attribute fields the other omits them. In languages that do not support overloading attribute fields are included in the arguments to the constructor functions. Some languages like C support different options for generating constructors. (See Language Specific Options)
In ML an expression to create a sexpr
described in
The Rosetta Stone for Sum Types
which represents the integer one would look like
M.Int(1)
in C it would be
M_Int(1)
and in Java
new M.Int(1)
Constructors that are that are treated specially as enumerations Sum Types as Enumerations are globally defined constant integers or objects of the appropriate name. So these constructors can be "called" without any arguments. For instance
Op_PLUS
rather than
Op_PLUS() /* Incorrect use */
Because Java does not have a name space where one can place
globally visible constants. There is a special class named g
which
contains all constant objects/constructors for the package. The call in Java
would be
import ast.*;
Op.op x = Op.g.PLUS;
Here are some common idioms for De-constructing sum types based on the examples in The Rosetta Stone for Sum Types, for languages that do not support pattern matching. Languages such as ML can simply use pattern matching.
In C the common idiom should look something like this
M_sexpr_ty sexpr;
switch(sexpr->kind) {
case M_Int_kind: {
struct M_Int_s x = sexpr->v.M_Int;
/* access the fields through x */
} break;
case M_String_kind: {
struct M_String_s x = sexpr->v.M_String;
/* access fields through x */
} break;
....
case M_Cons_kind: {
struct M_Cons_s x = sexpr->v.M_Cons;
/* access the fields through x */
} break;
}
This approach introduces an extra structure copy which isn't necessary, but
has the advantage of enforcing a read only discipline on the
value. Alternatively nothing prevents you from accessing the fields directly
and mutating them as or making x
a pointer to a structure. A
carefully crafted set of macros could make this more readable.
In Java the idiom is much the same
import ast.*;
...
M.sexpr sexpr;
switch(M.sexpr.kind()) {
case M.sexpr.Int_kind: {
M.Int x = (M.Int) sexpr;
/* access the fields through x */
} break;
case M.sexpr.String_kind: {
M.String x = (M.String) sexpr;
/* access the fields through x */
} break;
...
case M.sexpr.Cons_kind: {
M.Cons x = (M.Cons) sexpr;
/* access the fields through x */
} break;
}
A series of instanceof
's in a chain if then else's would work also, but
this switch statement is likely to be faster. Unlike the C version this
idiom does not enforce a read only discipline since all object types are
reference types in Java.
For sum types which have been treated as enumerations
Sum Types as Enumerations the idioms are a bit different for C code. In
particular rather than switching on var->kind
in one would
switch on var
.