Back: Smalltalk types
Up: C and Smalltalk
Forward: Other C functions
 
Top: GNU Smalltalk User's Guide
Contents: Table of Contents
Index: Class index
About: About this document

4.5 Calls from C to Smalltalk

GNU Smalltalk provides seven different function calls that allow you to call Smalltalk methods in a different execution context than the current one. The priority in which the method will execute will be the same as the one of Smalltalk process which is currently active.

Four of these functions are more low level and are more suited when the Smalltalk program itself gave a receiver, a selector and maybe some parameters; the others, instead, are more versatile. One of them (msgSendf) automatically handles most conversions between C data types and Smalltalk objects, while the others takes care of compiling full snippets of Smalltalk code.

All these functions handle properly the case of specifying, say, 5 arguments for a 3-argument selector--see the description of the single functions for more information).

Function: OOP msgSend (OOP receiver, OOP selector, ...)
This function sends the given selector (should be a Symbol, otherwise nilOOP is returned) to the given receiver. The message arguments should also be OOPs (otherwise, an access violation exception is pretty likely) and are passed in a NULL-terminated list after the selector. The value returned from the method is passed back as an OOP to the C program as the result of msgSend, or nilOOP if the number of arguments is wrong. Example (same as 1 + 2):

 
    OOP shouldBeThreeOOP = msgSend(
        intToOOP(1),
        symbolToOOP("+"),
        intToOOP(2),
        nil);

Function: OOP strMsgSend (OOP receiver, char *selector, ...)
This function is the same as above, but the selector is passed as a C string and is automatically converted to a Smalltalk symbol.

Theoretically, this function is a bit slower than msgSend if your program has some way to cache the selector and avoiding a call to symbolToOOP on every call-in. However, this is not so apparent in "real" code because the time spent in the Smalltalk interpreter will usually be much higher than the time spent converting the selector to a Symbol object. Example:

 
    OOP shouldBeThreeOOP = strMsgSend(
        intToOOP(1),
        "+",
        intToOOP(2),
        nil);

Function: OOP vmsgSend (OOP receiver, OOP selector, OOP *args)
This function is the same as msgSend, but accepts a pointer to the NULL-terminated list of arguments, instead of being a variable-arguments functions. Example:

 
    OOP arguments[2], shouldBeThreeOOP;
    arguments[0] = intToOOP(2);
    arguments[1] = nil;
    /* ... some more code here ... */

    shouldBeThreeOOP = vmsgSend(
        intToOOP(1),
        symbolToOOP("+"),
        arguments);

Function: OOP nvmsgSend (OOP receiver, OOP selector, OOP *args, int nargs)
This function is the same as msgSend, but accepts an additional parameter containing the number of arguments to be passed to the Smalltalk method, instead of relying on the NULL-termination of args. Example:

 
    OOP argument, shouldBeThreeOOP;
    argument = intToOOP(2);
    /* ... some more code here ... */

    shouldBeThreeOOP = nvmsgSend(
        intToOOP(1),
        symbolToOOP("+"),
        &argument,
        1);

The two functions that directly accept Smalltalk code are named evalCode and evalExpr, and they're basically the same. They both accept a single parameter, a pointer to the code to be submitted to the parser. The main difference is that evalCode discards the result, while evalExpr returns it to the caller as an OOP.

msgSendf, instead, has a radically different syntax. Let's first look at some examples.

 
    /* 1 + 2 */
    int shouldBeThree;
    msgSend(&shouldBeThree, "%i %i + %i", 1, 2)

    /* aCollection includes: 'abc' */
    OOP aCollection;
    int aBoolean;
    msgSendf(&aBoolean, "%b %o includes: %s", aCollection, "abc")

    /* 'This is a test' printNl -- in two different ways */
    msgSendf(nil, "%v %s printNl", "This is a test");
    msgSendf(nil, "%s %s printNl", "This is a test");

    /* 'This is a test', ' ok?' */
    char *str;
    msgSendf(&str, "%s %s , %s", "This is a test", " ok?");

As you can see, the parameters to msgSendf are, in order:

  • A pointer to the variable which will contain the record. If this pointer is nil, it is discarded.

  • A description of the method's interface in this format (the object types, after percent signs, will be explained later in this section)

     
    %result_type %receiver_type selector %param1_type %param2_type
    

  • A C variable or Smalltalk object (depending on the type specifier) for the receiver

  • If needed, The C variables and/or Smalltalk object (depending on the type specifiers) for the arguments.

Note that the receiver and parameters are NOT registered in the object registry (see section 4.4 Manipulating Smalltalk data from C). receiver_type and paramX_type can be any of these characters, with these meanings:

 
      Specifier        C data type        equivalent Smalltalk class
          i                long           Integer (see intToOOP)
          f               double          Float (see floatToOOP)
          b                int            True or False (see boolToOOP)
          c                char           Character (see charToOOP)
          C               voidPtr         CObject (see cObjToOOP)
          s               char *          String (see stringToOOP)
          S               char *          Symbol (see symbolToOOP)
          o                OOP            any
          t            char *, voidPtr    CObject (see below)
          T              OOP, voidPtr     CObject (see below)

`%t' and `%T' are particular in the sense that you need to pass two additional arguments to msgSendf, not one. The first will be a description of the type of the CObject to be created, the second instead will be the CObject's address. If you specify `%t', the first of the two arguments will be converted to a Smalltalk CType via typeNameToOOP (see section 4.4 Manipulating Smalltalk data from C); instead, if you specify `%T', you will have to directly pass an OOP for the new CObject's type.

The type specifiers you can pass for result_type are a bit different:

 
            Result
Specifier   if nil    C data type      expected result
   i         0L          long          nil or an Integer
   f         0.0        double         nil or an Float
   b          0          int           nil or a Boolean
   c        '\0'         char          nil or a Character
   C        NULL        voidPtr        nil or a CObject
   s        NULL        char *         nil, a String, or a Symbol
   ?         0      char *, voidPtr    See oopToC
   o       nilOOP        OOP           any (result is not converted)
   v                      /            any (result is discarded)

Note that, if resultPtr is nil, the result_type is always treated as `%v'. If an error occurs, the value in the `result if nil' column is returned.




This document was generated on May, 12 2002 using texi2html