5.4.1 Dynamic Types

Scheme is a dynamically-typed language; this means that the system cannot, in general, determine the type of a given expression at compile time. Types only become apparent at run time. Variables do not have fixed types; a variable may hold a pair at one point, an integer at the next, and a thousand-element vector later. Instead, values, not variables, have fixed types.

In order to implement standard Scheme functions like pair? and string? and provide garbage collection, the representation of every value must contain enough information to accurately determine its type at run time. Often, Scheme systems also use this information to determine whether a program has attempted to apply an operation to an inappropriately typed value (such as taking the car of a string).

Because variables, pairs, and vectors may hold values of any type, Scheme implementations use a uniform representation for values — a single type large enough to hold either a complete value or a pointer to a complete value, along with the necessary typing information.

In Guile, this uniform representation of all Scheme values is the C type SCM. This is an opaque type and its size is typically equivalent to that of a pointer to void. Thus, SCM values can be passed around efficiently and they take up reasonably little storage on their own.

The most important rule is: You never access a SCM value directly; you only pass it to functions or macros defined in libguile.

As an obvious example, although a SCM variable can contain integers, you can of course not compute the sum of two SCM values by adding them with the C + operator. You must use the libguile function scm_sum.

Less obvious and therefore more important to keep in mind is that you also cannot directly test SCM values for trueness. In Scheme, the value #f is considered false and of course a SCM variable can represent that value. But there is no guarantee that the SCM representation of #f looks false to C code as well. You need to use scm_is_true or scm_is_false to test a SCM value for trueness or falseness, respectively.

You also can not directly compare two SCM values to find out whether they are identical (that is, whether they are eq? in Scheme terms). You need to use scm_is_eq for this.

The one exception is that you can directly assign a SCM value to a SCM variable by using the C = operator.

The following (contrived) example shows how to do it right. It implements a function of two arguments (a and flag) that returns a+1 if flag is true, else it returns a unchanged.

SCM
my_incrementing_function (SCM a, SCM flag)
{
  SCM result;

  if (scm_is_true (flag))
    result = scm_sum (a, scm_from_int (1));
  else
    result = a;

  return result;
}

Often, you need to convert between SCM values and appropriate C values. For example, we needed to convert the integer 1 to its SCM representation in order to add it to a. Libguile provides many function to do these conversions, both from C to SCM and from SCM to C.

The conversion functions follow a common naming pattern: those that make a SCM value from a C value have names of the form scm_from_type (…) and those that convert a SCM value to a C value use the form scm_to_type (…).

However, it is best to avoid converting values when you can. When you must combine C values and SCM values in a computation, it is often better to convert the C values to SCM values and do the computation by using libguile functions than to the other way around (converting SCM to C and doing the computation some other way).

As a simple example, consider this version of my_incrementing_function from above:

SCM
my_other_incrementing_function (SCM a, SCM flag)
{
  int result;

  if (scm_is_true (flag))
    result = scm_to_int (a) + 1;
  else
    result = scm_to_int (a);

  return scm_from_int (result);
}

This version is much less general than the original one: it will only work for values A that can fit into a int. The original function will work for all values that Guile can represent and that scm_sum can understand, including integers bigger than long long, floating point numbers, complex numbers, and new numerical types that have been added to Guile by third-party libraries.

Also, computing with SCM is not necessarily inefficient. Small integers will be encoded directly in the SCM value, for example, and do not need any additional memory on the heap. See Data Representation to find out the details.

Some special SCM values are available to C code without needing to convert them from C values:

Scheme valueC representation
#fSCM_BOOL_F
#tSCM_BOOL_T
()SCM_EOL

In addition to SCM, Guile also defines the related type scm_t_bits. This is an unsigned integral type of sufficient size to hold all information that is directly contained in a SCM value. The scm_t_bits type is used internally by Guile to do all the bit twiddling explained in Data Representation, but you will encounter it occasionally in low-level user code as well.