NAME

docs/pdds/pdd02_vtables.pod - Common vtable format for all variables

ABSTRACT

This PDD presents the vtable entries, and their order, that all variables MUST provide.

DESCRIPTION

All parrot variables hide their guts behind a magic parrot structure generally referred to as a PMC, or Parrot Magic Cookie. Nothing outside the core of parrot (in fact, nothing outside the data type's vtable routines) should infer anything about a PMC (hence the Magic part).

The first parameter to any vtable routine should be the current interpreter. The second parameter should be the PMC itself.

vtables are neat because they decouple the interface and implementation of various object functions. This does mean, though, that you need to either know what functions are available and what they do, or have some method of finding out. It's faster if you know which vtable entry does what, so that's the method parrot's using.

The actual vtable structure contains pointers to functions that implement the methods for that particular vtable. All pointers must point to valid functions with appropriate prototypes.

IMPLEMENTATION

vtable functions

This is a list of each of the vtable methods, their prototypes, and a description of the method.

The following functions are singleton functions. (There are no keyed versions of these)

void init(INTERP, PMC* self)

The init vtable method takes an unused PMC as a parameter and turns it into a PMC appropriate for the class owning the vtable. Called as a class method. There is also a form that accepts a PMC initializer as a third argument.

void init_pmc(INTERP, PMC* self, PMC* initializer)

This form of the init method takes a single initializer parameter. The initializer is an array that contains keys and values. The meaning of the keys and their corresponding values is left up to the PMC.

Keys are either strings or integers. If strings, the PMC is responsible for figuring out what the string represents. If integers, it means the meaning has been pre-figured based on meta-information from the class.

For example, if a class has the known properties "Size", "Dimension" and "Color", they may be assigned the values 100, 101, and 102. If the creator of the PMC knows enough about the class to make the translation to numbers it may; otherwise, the raw strings may be used. So, for the declaration:

my @foo Size(12), Dimension(3), Color("Green");

the init array may be [100, 12, 101, 3, 102, "Green"] or ["Size", 12, "Dimension", 3, "Color", "Green"]. Note that, in all cases, the array is an array of PMCs. (So you get either an int PMC or a string PMC in the list of keys).

void init_pmc_props(INTERP, PMC* self, PMC* initializer, PMC* properties)

XXX: what does this do?

void morph(INTERP, PMC* self, INTVAL type)

Turn the PMC into a PMC of type type. If the morphing can't be done in any reasonable way -- for instance if an integer is asked to turn into an Array -- then the PMC is first destroyed, then recreated as an empty PMC of the new type.

This method is primarily used when the interpreter has need of coercing a PMC to a particular type, and isn't meant as a general purpose casting tool. Compilers should only emit valid transformations.

void mark(INTERP, PMC* self)

Called by the DOD when it is sweeping through the PMCs and has detected that this PMC is both alive and has a custom mark routine (as indicated by the custom mark PMC flag).

If a PMC has this flag set, then it is responsible for marking all buffers and PMCs under its control as alive. If it does not, those PMCs or buffers may be collected later. This method does not have to call the mark method on any PMCs it marks--the DOD system takes care of that. (So no need to recurse into aggregate PMCs or anything of the sort).

This method may allocate no memory from Parrot, nor may it alter Parrot's internal structures. It should have no side-effects from the C level either.

This routine may not throw an exception.

void destroy(INTERP, PMC* self)

This method is called by the DOD when it determines that a PMC is dead and that the PMC has marked itself as having a destroy method.

When this method finishes, the PMC will be marked as dead. As such you should make sure that you do not leave any references to it in any parrot structure by the end of the method.

This method may not throw an exception. It will be ignored if it does.

PMC* getprop(INTERP, PMC* self, STRING* key)

Return the value from the property hash of self keyed by key. The key should not be NULL.

void setprop(INTERP, PMC* self, STRING* key, PMC* value)

Set the value in the property hash of self that is keyed by key to the value of value. The key should not be NULL.

void delprop(INTERP, PMC* self, STRING* key)

Delete the value from the property hash of self keyed by key. The key should not be NULL.

PMC* getprops(INTERP, PMC* self)

Return the entire property hash for self.

The following functions have a plain form, a _keyed form, and a _keyed_int form. The keyed forms take a PMC* or INTVAL for each PMC parameter. The PMC* parameter for each PMC is NULL if there is no key for that PMC; this means that that argument is unkeyed.

In some cases, the caller must provide a non-NULL key. Those cases are explicitly stated below. In the other cases, you may have to implement the keyed vtable methods and check for a NULL self key even if you are implementing a non-aggregate type. If the self key is non-NULL and the PMC class is a non-aggregate type, the _keyed_* methods should throw an exception.

If you do not implement the _keyed_int methods, the default will convert the INTVAL into a key PMC* and call the corresponding _keyed method.

The keyed methods should NOT assume that the key pointer will be valid after the method exits. The pointer may be to a stack variable in the calling function.

INTVAL type(INTERP, PMC* self)

Return the type of the PMC. Type is a unique tag associated with the PMC when the PMC's class is loaded. Negative numbers are considered interpreter-specific, non-public types.

INTVAL type_keyed(INTERP, PMC* self, PMC* key)
INTVAL type_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL type_keyed_str(INTERP, PMC* self, STRING* key)

Return the type of the PMC indexed by key. The key parameter is guaranteed not to be NULL for this method.

UINTVAL subtype(INTERP, PMC* self, INTVAL type)

Return the subtype of a PMC. (Note that this may be unimplemented, and may go away). This is intended to return information about the PMC--what type of number or string it is, whether it's a scalar, hash, array, or list, and suchlike things.

STRING* name(INTERP, PMC* self)

Return the name of the class for the PMC.

PMC* clone(INTERP, PMC* self)

Return a clone of yourself.

PMC* find_method(INTERP, PMC* self, STRING* method_name)

Return a subroutine PMC for the passed method name. This subroutine PMC may be cached, so the method must return an equivalent sub PMC each time, or be capable of dealing with the returned sub PMCs being reused.

INTVAL get_integer(INTERP, PMC* self)

Return the native integer value of the PMC.

INTVAL get_integer_keyed(INTERP, PMC* self, PMC* key)
INTVAL get_integer_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL get_integer_keyed_str(INTERP, PMC* self, STRING* key)

Return the native integer value of the PMC indexed by key. The key parameter is guaranteed not to be NULL for this method.

FLOATVAL get_number(INTERP, PMC* self)

Return the native floating-point value of the PMC.

FLOATVAL get_number_keyed(INTERP, PMC* self, PMC* key)
FLOATVAL get_number_keyed_int(INTERP, PMC* self, INTVAL key)
FLOATVAL get_number_keyed_str(INTERP, PMC* self, STRING* key)

Return the native floating-point value of the PMC indexed by key. The key parameter is guaranteed not to be NULL for this method.

PMC* get_bignum(INTERP, PMC* self)

Return the value of the PMC as a new bignum PMC.

STRING* get_string(INTERP, PMC* self)

Return the native string value of the PMC. This may be in the encoding of the PMC's choice.

STRING* get_string_keyed(INTERP, PMC* self, PMC* key)
STRING* get_string_keyed_int(INTERP, PMC* self, INTVAL key)
STRING* get_string_keyed_str(INTERP, PMC* self, STRING* key)

Return the string value of the PMC indexed by key. The key parameter is guaranteed not to be NULL for this method.

INTVAL get_bool(INTERP, PMC* self)

Return the constant TRUE if the PMC is true, or FALSE if the PMC is false. The definition of truth for a given PMC will depend on the type of the PMC: for a scalar, it may be as simple as 0 or "" being false, and any other value being true.

PMC* get_pmc(INTERP, PMC* self)

Return the PMC for this PMC. While this may seem nonsensical, it's useful in several circumstances. If the thing being accessed may return something odd, for example a reference, it may return a value different from the PMC that get_pmc is being called on.

PMC* get_pmc_keyed(INTERP, PMC* self, PMC* key)
PMC* get_pmc_keyed_int(INTERP, PMC* self, INTVAL key)
PMC* get_pmc_keyed_str(INTERP, PMC* self, STRING* key)

Return the PMC indexed by key. The key parameter is guaranteed not to be NULL for this method.

void* get_pointer(INTERP, PMC* self)
void* get_pointer_keyed(INTERP, PMC* self, PMC* key)
void* get_pointer_keyed_int(INTERP, PMC* self, INTVAL key)
void* get_pointer_keyed_str(INTERP, PMC* self, STRING* key)

Return a pointer to some data. The details of the data (type, location etc.) depend on the PMC.

void set_integer_native(INTERP, PMC* self, INTVAL value)

Sets the PMC to the integer value passed.

void set_integer_same(INTERP, PMC* self, PMC* value)

Sets the PMC to the integer value of the PMC in value. In this case, value is guaranteed to be of the same type as self so optimizations may be made.

void set_integer_keyed(INTERP, PMC* self, PMC* key, INTVAL value)
void set_integer_keyed_int(INTERP, PMC* self, INTVAL key, INTVAL value)
void set_integer_keyed_str(INTERP, PMC* self, STRING* key, INTVAL value)

Sets the PMC indexed by key to the integer value passed in value. The key parameter is guaranteed not to be NULL for this method.

void set_number_native(INTERP, PMC* self, FLOATVAL value)

Sets the PMC to the floating-point value passed.

void set_number_same(INTERP, PMC* self, PMC* value)

Sets the PMC to the floating-point value of the PMC in value. In this case, value is guaranteed to be of the same type as self so optimizations may be made.

void set_number_keyed(INTERP, PMC* self, PMC* key, FLOATVAL value)
void set_number_keyed_int(INTERP, PMC* self, INTVAL key, FLOATVAL value)
void set_number_keyed_str(INTERP, PMC* self, STRING* key, FLOATVAL value)

Sets the PMC indexed by key to the floating-point value passed in value. The key parameter is guaranteed not to be NULL for this method.

void set_bignum_int(INTERP, PMC* self, INTVAL value)

Morph the PMC to a BIGNUM PMC with value being the passed in value.

void set_string_native(INTERP, PMC* self, STRING* value)

Sets the PMC to the passed in string value.

void assign_string_native(INTERP, PMC* self, STRING* value)

Sets the PMC to the copied string value.

void set_string_same(INTERP, PMC* self, PMC* value)

Sets the PMC to the string value of value. In this case, value is guaranteed to be of the same type as self so optimizations may be made.

void set_string_keyed(INTERP, PMC* self, PMC* key, STRING* value)
void set_string_keyed_int(INTERP, PMC* self, INTVAL key, STRING* value)
void set_string_keyed_str(INTERP, PMC* self, STRING* key, STRING* value)

Sets the PMC indexed by key to the string value passed in value. The key parameter is guaranteed not to be NULL for this method.

void set_bool(INTERP, PMC* self, INTVAL value)

Sets the boolean state of the PMC to TRUE if value is TRUE, or FALSE if value is FALSE.

void set_pmc(INTERP, PMC* self, PMC* value)

Make the PMC self refer to the PMC value.

void assign_pmc(INTERP, PMC* self, PMC* value)

Sets the value of the PMC in self to the value of the PMC in value by copying the value.

void set_pmc_keyed(INTERP, PMC* self, PMC* key, PMC* value)
void set_pmc_keyed_int(INTERP, PMC* self, INTVAL key, PMC* value)
void set_pmc_keyed_str(INTERP, PMC* self, STRING* key, PMC* value)

Sets the value of the PMC keyed by key to the value of the PMC in value.

void set_pointer(INTERP, PMC* self, void* value)
void set_pointer_keyed(INTERP, PMC* self, PMC* key, void* value)
void set_pointer_keyed_int(INTERP, PMC* self, INTVAL key, void* value)
void set_pointer_keyed_str(INTERP, PMC* self, STRING* key, void* value)

Sets a pointer inside the PMC. The details depend on the PMC.

INTVAL elements(INTERP, PMC* self)

Return the number of elements in the PMC.

INTVAL pop_integer(INTERP, PMC* self)

Return the integer value of the last item on the list, removing that item.

FLOATVAL pop_float(INTERP, PMC* self)

Return the floating-point value of the last item on the list, removing that item.

STRING* pop_string(INTERP, PMC* self)

Return the string value of the last item on the list, removing that item.

PMC* pop_pmc(INTERP, PMC* self)

Return the PMC value of the last item on the list, removing that item.

void push_integer(INTERP, PMC* self, INTVAL value)

Add the passed in integer value to the end of the list.

void push_float(INTERP, PMC* self, FLOATVAL value)

Add the passed in floating-point number to the end of the list.

void push_string(INTERP, PMC* self, STRING* value)

Add the passed in string to the end of the list.

void push_pmc(INTERP, PMC* self, PMC* value)

Add the passed in PMC to the end of the list.

INTVAL shift_integer(INTERP, PMC* self)

Return the integer value of the first item on the list, removing that item.

FLOATVAL shift_float(INTERP, PMC* self)

Return the floating-point value of the first item on the list, removing that item.

STRING* shift_string(INTERP, PMC* self)

Return the string value of the first item on the list, removing that item.

PMC* shift_pmc(INTERP, PMC* self)

Return the PMC value of the first item on the list, removing that item.

void unshift_integer(INTERP, PMC* self, INTVAL value)

Add the passed in integer value to the beginning of the list.

void unshift_float(INTERP, PMC* self, FLOATVAL value)

Add the passed in floating-point number to the beginning of the list.

void unshift_string(INTERP, PMC* self, STRING* value)

Add the passed in string to the beginning of the list.

void splice(INTERP, PMC* self, PMC* value, INTVAL offset, INTVAL count)

Replace the count PMCs at offset offset from the beginning of self with the PMCs in the aggregate value.

void add(INTERP, PMC* self, PMC* value, PMC* dest)
void add_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void add_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)

Add self to value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

PMC* subtract(INTERP, PMC* self, PMC* value, PMC* dest)
PMC* subtract_int(INTERP, PMC* self, INTVAL value, PMC* dest)
PMC* subtract_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)

If dest is NULL create a result PMC of an appropriate type. Subtract value from self and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void i_subtract(INTERP, PMC* self, PMC* value)
void i_subtract_int(INTERP, PMC* self, INTVAL value)
void i_subtract_float(INTERP, PMC* self, FLOATVAL value)

Inplace operation self -= value.

void multiply(INTERP, PMC* self, PMC* value, PMC* dest)
void multiply_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void multiply_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)

Multiply value by self and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void divide(INTERP, PMC* self, PMC* value, PMC* dest)
void divide_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void divide_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)

Divide self by value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void modulus(INTERP, PMC* self, PMC* value, PMC* dest)
void modulus_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void modulus_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)

Divide self by value and store the remainder in dest. Note that dest may be equal to self; in that case optimizations may be made.

void cmodulus(INTERP, PMC* self, PMC* value, PMC* dest)
void cmodulus_int(INTERP, PMC* self, INTVAL value, PMC* dest)
void cmodulus_float(INTERP, PMC* self, FLOATVAL value, PMC* dest)

Divide self by value and store the remainder in dest. Note that dest may be equal to self; in that case optimizations may be made.

Note: modulus uses the Knuth's "corrected mod" algorithm, as implemented in src/utils.c, while cmodulus uses the C-style fmod function.

void neg(INTERP, PMC* self, PMC* dest)

Negate the sign of self and store the result in dest. Note that self and dest may refer to the same PMC, in which case optimizations may be made.

void bitwise_or(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_or_int(INTERP, PMC* self, INTVAL value, PMC* dest)

Calculate the bitwise-OR of self and value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void bitwise_and(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_and_int(INTERP, PMC* self, INTVAL value, PMC* dest)

Calculate the bitwise-AND of self and value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void bitwise_xor(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_xor_int(INTERP, PMC* self, INTVAL value, PMC* dest)

Calculate the bitwise-XOR of self and value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void bitwise_ors(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_ors_str(INTERP, PMC* self, STRING* value, PMC* dest)

Calculate the bitwise-OR of the strings in self and value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void bitwise_ands(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_ands_str(INTERP, PMC* self, STRING* value, PMC* dest)

Calculate the bitwise-AND of the strings in self and value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void bitwise_xors(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_xors_str(INTERP, PMC* self, STRING* value, PMC* dest)

Calculate the bitwise-XOR of the strings in self and value and store the result in dest. Note that dest may be equal to self; in that case optimizations may be made.

void bitwise_not(INTERP, PMC* self, PMC* dest)

Apply a bitwise negation to self and store the result in dest. Note that self and dest may refer to the same PMC; in that case optimizations may be made.

void bitwise_shl(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_shl_int(INTERP, PMC* self, INTVAL value, PMC* dest)

Apply a leftward shift of value bits to the number stored in self, and place the resulting value in dest. Note that self and dest may refer to the same PMC; in that case optimizations may be made.

void bitwise_shr(INTERP, PMC* self, PMC* value, PMC* dest)
void bitwise_shr_int(INTERP, PMC* self, INTVAL value, PMC* dest)

Applies a rightward shift of value bits to the number stored in self, and places the resulting value in dest. Note that self and dest may refer to the same PMC; in that case optimizations may be made.

void concatenate(INTERP, PMC* self, PMC* value, PMC* dest)
void concatenate_str(INTERP, PMC* self, STRING* value, PMC* dest)

Concatenate the strings in self and value and store the result in dest. Note that self and dest may refer to the same PMC; in that case optimizations may be made.

INTVAL is_equal(INTERP, PMC* self, PMC* value)

Return TRUE if the two PMCs are generically equivalent, or FALSE if they aren't.

INTVAL is_same(INTERP, PMC* self, PMC* value)

Return TRUE if the PMCs are the same, and FALSE if they're not. In this case, "the same" means identical at a low level. For plain equality, use the is_equal method.

INTVAL cmp(INTERP, PMC* self, PMC* value)

Compare the two PMCs as PMCs (whatever that means for the class). Return -1 if self is smaller, 0 if the two are equal, and 1 if value is smaller.

INTVAL cmp_num(INTERP, PMC* self, PMC* value)

Compare the two PMCs numerically. Return -1 if self is smaller, 0 if the two are equal, and 1 if value is smaller.

INTVAL cmp_string(INTERP, PMC* self, PMC* value)

Compare the two PMCs as strings. Return -1 if self is smaller, 0 if the two are equal, and 1 if value is smaller.

void logical_or(INTERP, PMC* self, PMC* value, PMC* dest)

Do a short-circuiting logical-OR of self and value, storing the winner in dest.

void logical_and(INTERP, PMC* self, PMC* value, PMC* dest)

Do a short-circuiting logical-AND of self and value, storing the winner in dest.

void logical_xor(INTERP, PMC* self, PMC* value, PMC* dest)

If exactly one of self or value is true, store it in dest. Else set dest to be false.

void logical_not(INTERP, PMC* self, PMC* dest)

Do a logical-NOT on self and stores the result in dest.

void repeat(INTERP, PMC* self, PMC* value, PMC* dest)
void repeat_int(INTERP, PMC* self, INTVAL value, PMC* dest)

Repeat the string value of self value times and store the resultant string in dest.

void increment(INTERP, PMC* self)

Auto-increment the PMC.

void decrement(INTERP, PMC* self)

Auto-decrement the PMC.

void abs(INTERP, PMC* self, PMC* dest)

Set dest to the absolute value of SELF. Note: dest may be SELF.

INTVAL exists_keyed(INTERP, PMC* self, PMC* key)
INTVAL exists_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL exists_keyed_str(INTERP, PMC* self, STRING* key)

Only valid for keyed access.

Returns TRUE if the key exists in the aggregate being queried; otherwise, return FALSE.

The key is guaranteed to be non-NULL.

INTVAL defined(INTERP, PMC* self)

Check to see if the PMC is defined. Return TRUE if it is; otherwise, return FALSE.

INTVAL defined_keyed(INTERP, PMC* self, PMC* key)
INTVAL defined_keyed_int(INTERP, PMC* self, INTVAL key)
INTVAL defined_keyed_str(INTERP, PMC* self, STRING* key)

Return TRUE if the value of self keyed by key is defined; otherwise, return FALSE.

The key is guaranteed to be non-NULL.

void delete_keyed(INTERP, PMC* self, PMC* key)
void delete_keyed_int(INTERP, PMC* self, INTVAL key)
void delete_keyed_str(INTERP, PMC* self, STRING* key)

Delete the specified entry from the aggregate.

The key is guaranteed to be non-NULL.

PMC* nextkey_keyed(INTERP, PMC* self, PMC* key)
PMC* nextkey_keyed_int(INTERP, PMC* self, INTVAL key)
PMC* nextkey_keyed_str(INTERP, PMC* self, STRING* key, INTVAL what)

Given the passed in key for the PMC, return the next key.

The key is guaranteed to be non-NULL.

PMC* get_iter(INTERP, PMC* self)

Return a new iterator for this aggregate. The iterator should be initialized so that iterations starts at the first element of the aggregate. If the aggregate is empty, set PMC_int_val() of the iterator key to -1.

PMC* slice(INTERP, PMC* self, PMC* key)

Return a new iterator for this aggregate and the given Slice key.

void substr(INTERP, PMC* self, INTVAL offset, INTVAL length, PMC* dest)

Place the value of the substring of self at offset offset and with length length into dest.

STRING* substr_str(INTERP, PMC* self, INTVAL offset, INTVAL length)

Return the substring of self at offset offset and with length length.

void* invoke(INTERP, PMC* self, void* next)

Invoke the subroutine/method in the given PMC.

It should set up the environment for the sub, and should return the location at which operation flow should continue after the subroutine returns. (Note that this will generally be the address of the next instruction).

It is NOT responsible for preserving any of the current context; the caller should have preserved anything that they want preserved before calling this method.

See pdd03_calling_conventions.pod for more details.

next* is passed in from the run loop and is the program counter of the next instruction.

INTVAL can(INTERP, PMC* self, STRING* method)

Determine whether the PMC can perform the method specified by name in method. Returns TRUE if it can; otherwise, returns FALSE.

INTVAL does(INTERP, PMC* self, STRING* method)

Determine whether the PMC implements the interface specified by name in method. Returns TRUE if it can; otherwise, returns FALSE.

INTVAL isa(INTERP, PMC* self, STRING* _class)

Is the PMC a member of _class or one of its subclasses.

See also pdd15_objects.pod.

PMC* subclass(STRING* name)

Creates a subclass, optionally with a given name.

void freeze(INTERP, PMC* self, visit_info* info)
void thaw(INTERP, PMC* self, visit_info* info)
void thawfinish(INTERP, PMC* self, visit_info* info)
void visit(INTERP, PMC* self, visit_info* info)

Serialization functions.

XXX: these need documenting by somebody who understands them.

void share(INTERP, PMC* self)

XXX: needs documenting

VERSION

CURRENT

Maintainer: Dan Sugalski <dan@sidhe.org>
Class: Internals
PDD Number: 2
Version: 1.5
Status: Developing
Last Modified: 27 July 2003
PDD Format: 1
Language: English

HISTORY

1.5

18 May 2004

1.4

1 Nov 2003

1.3

27 July 2003

1.2

22 June 2002

1.1

13 May 2002

1.0

None. First version

CHANGES

1.5
* Remove obsolete _keyed vtables.
* s/concat_native/concat_str/
1.4
* Add set/get_pointer vtables.
* Change s/KEY/PMC/ and s/INTVAL* key/INTVAL key/
1.3

Added a number of missing method definitions. Many other minor cleanups.

1.2

Many cleanups and clarifications. Much detail added. Many missing methods added.

1.1

Cleaned up the definition. It was a mess.

1.0

None. First version