Next: , Previous: C data types, Up: C and Smalltalk


5.4 Manipulating Smalltalk data from C

gnu Smalltalk internally maps every object except Integers to a data structure named an OOP (which is not an acronym for anything, as far as I know). An OOP is a pointer to an internal data structure; this data structure basically adds a level of indirection in the representation of objects, since it contains

This additional level of indirection makes garbage collection very efficient, since the collector is free to move an object in memory without updating every reference to that object in the heap, thereby keeping the heap fully compact and allowing very fast allocation of new objects. However, it makes C code that wants to deal with objects even more messy than it would be without; if you want some examples, look at the hairy code in gnu Smalltalk that deals with processes.

To shield you as much as possible from the complications of doing object-oriented programming in a non-object-oriented environment like C, gnu Smalltalk provides friendly functions to map between common Smalltalk objects and C types. This way you can simply declare OOP variables and then use these functions to treat their contents like C data.

These functions are passed to a module via the VMProxy struct a pointer to which is passed to the module, as shown in Linking your libraries to the virtual machine. They can be divided in two groups, those that map from Smalltalk objects to C data types and those that map from C data types to Smalltalk objects.

Here are those in the former group (Smalltalk to C); you can see that they all begin with OOPTo:

— Function: long OOPToInt (OOP)

This function assumes that the passed OOP is an Integer and returns the C signed long for that integer.

— Function: long OOPToId (OOP)

This function returns an unique identifier for the given OOP, valid until the OOP is garbage-collected.

— Function: double OOPToFloat (OOP)

This function assumes that the passed OOP is an Integer or Float and returns the C double for that object.

— Function: long double OOPToLongDouble (OOP)

This function assumes that the passed OOP is an Integer or Float and returns the C long double for that object.

— Function: int OOPToBool (OOP)

This function returns a C integer which is true (i.e. != 0) if the given OOP is the true object, false (i.e. == 0) otherwise.

— Function: char OOPToChar (OOP)

This function assumes that the passed OOP is a Character and returns the C char for that integer.

— Function: wchar_t OOPToWChar (OOP)

This function assumes that the passed OOP is a Character or UnicodeCharacter and returns the C wchar_t for that integer.

— Function: char *OOPToString (OOP)

This function assumes that the passed OOP is a String or ByteArray and returns a C null-terminated char * with the same contents. It is the caller's responsibility to free the pointer and to handle possible `NUL' characters inside the Smalltalk object.

— Function: wchar_t *OOPToWString (OOP)

This function assumes that the passed OOP is a UnicodeString and returns a C null-terminated wchar_t * with the same contents. It is the caller's responsibility to free the pointer and to handle possible `NUL' characters inside the Smalltalk object.

— Function: char *OOPToByteArray (OOP)

This function assumes that the passed OOP is a String or ByteArray and returns a C char * with the same contents, without null-terminating it. It is the caller's responsibility to free the pointer.

— Function: PTR OOPToCObject (OOP)

This functions assumes that the passed OOP is a kind of CObject and returns a C PTR to the C data pointed to by the object. The caller should not free the pointer, nor assume anything about its size and contents, unless it exactly knows what it's doing. A PTR is a void * if supported, or otherwise a char *.

— Function: long OOPToC (OOP)

This functions assumes that the passed OOP is a String, a ByteArray, a CObject, or a built-in object (nil, true, false, character, integer). If the OOP is nil, it answers 0; else the mapping for each object is exactly the same as for the above functions. Note that, even though the function is declared as returning a long, you might need to cast it to either a char * or PTR.

While special care is needed to use the functions above (you will probably want to know at least the type of the Smalltalk object you're converting), the functions below, which convert C data to Smalltalk objects, are easier to use and also put objects in the incubator so that they are not swept by a garbage collection (see Incubator). These functions all end with ToOOP, except cObjectToTypedOOP:

— Function: OOP intToOOP (long)

This object returns a Smalltalk Integer which contains the same value as the passed C long. Note that Smalltalk integers are always signed and have a bit less of precision with respect to C longs. On 32 bit machines, their precision is 30 bits (if unsigned) or 31 bits (if signed); on 64 bit machines, their precision is 62 bits (if unsigned) or 63 bits (if signed).

— Function: OOP idToOOP (OOP)

This function returns an OOP from a unique identifier returned by OOPToId. The OOP will be the same that was passed to OOPToId only if the original OOP has not been garbage-collected since the call to OOPToId.

— Function: OOP floatToOOP (double)

This object returns a Smalltalk FloatD which contains the same value as the passed double. Unlike Integers, FloatDs have exactly the same precision as C doubles.

— Function: OOP longDoubleToOOP (long double)

This object returns a Smalltalk FloatQ which contains the same value as the passed long double. Unlike Integers, FloatQs have exactly the same precision as C long doubles.

— Function: OOP boolToOOP (int)

This object returns a Smalltalk Boolean which contains the same boolean value as the passed C int. That is, the returned OOP is the sole instance of either False or True, depending on where the parameter is zero or not.

— Function: OOP charToOOP (char)

This object returns a Smalltalk Character which represents the same char as the passed C char.

— Function: OOP charToOOP (wchar_t)

This object returns a Smalltalk Character or UnicodeCharacter which represents the same char as the passed C wchar_t.

— Function: OOP classNameToOOP (char *)

This method returns the Smalltalk class (i.e. an instance of a subclass of Class) whose name is the given parameter. This method is slow; you can safely cache its result.

— Function: OOP stringToOOP (char *)

This method returns a String which maps to the given null-terminated C string, or the builtin object nil if the parameter points to address 0 (zero).

— Function: OOP wstringToOOP (wchar_t *)

This method returns a UnicodeString which maps to the given null-terminated C wide string, or the builtin object nil if the parameter points to address 0 (zero).

— Function: OOP byteArrayToOOP (char *, int)

This method returns a ByteArray which maps to the bytes that the first parameters points to; the second parameter gives the size of the ByteArray. The builtin object nil is returned if the first parameter points to address 0 (zero).

— Function: OOP symbolToOOP (char *)

This method returns a String which maps to the given null-terminated C string, or the builtin object nil if the parameter points to address 0 (zero).

— Function: OOP cObjectToOOP (PTR)

This method returns a CObject which maps to the given C pointer, or the builtin object nil if the parameter points to address 0 (zero). The returned value has no precise CType assigned. To assign one, use cObjectToTypedOOP.

— Function: OOP cObjectToTypedOOP (PTR, OOP)

This method returns a CObject which maps to the given C pointer, or the builtin object nil if the parameter points to address 0 (zero). The returned value has the second parameter as its type; to get possible types you can use typeNameToOOP.

— Function: OOP typeNameToOOP (char *)

All this method actually does is evaluating its parameter as Smalltalk code; so you can, for example, use it in any of these ways:

          cIntType = typeNameToOOP("CIntType");
          myOwnCStructType = typeNameToOOP("MyOwnCStruct type");
     

This method is primarily used by msgSendf (see Smalltalk callin), but it can be useful if you use lower level call-in methods. This method is slow too; you can safely cache its result.

As said above, the C to Smalltalk layer automatically puts the objects it creates in the incubator which prevents objects from being collected as garbage. A plugin, however, has limited control on the incubator, and the incubator itself is not at all useful when objects should be kept registered for a relatively long time, and whose lives in the registry typically overlap.

To avoid garbage collection of such object, you can use these functions, which access a separate registry:

— Function: void registerOOP (OOP)

Puts the given OOP in the registry. If you register an object multiple times, you will need to unregister it the same number of times. You may want to register objects returned by Smalltalk call-ins.

— Function: void unregisterOOP (OOP)

Removes an occurrence of the given OOP from the registry.

— Function: void registerOOPArray (OOP **, OOP **)

Tells the garbage collector that an array of objects must be made part of the root set. The two parameters point indirectly to the base and the top of the array; that is, they are pointers to variables holding the base and the top of the array: having indirect pointers allows you to dynamically change the size of the array and even to relocate it in memory without having to unregister and re-register it every time you modify it. If you register an array multiple times, you will need to unregister it the same number of times.

— Function: void unregisterOOPArray (OOP **)

Removes the array with the given base from the registry.