33

Interface

The functional interface of So-o en C consists of 3 functions: defclass which defines a new class, sendmsg which is systematically used to send a message to a class or an instance, and supersend which runs a method inherited from a superclass.

All the code for the So-o interface is in the file So-o.c.

  1. #ifndef _SOO_H
  2. #define _SOO_H
  3.  
  4. #include "Object.h"
  5.  
  6. #ifdef __STDC__
  7. extern class defclass( const char *name, class superclass, unsigned revision, property *class_properties, property *instance_properties, selector *class_messages, selector *instance_messages );
  8. extern value sendmsg( void *rcv, message msg, ... );
  9. extern value applymsg( void *rcv, message msg, va_list va);
  10. extern value supersend( class c, void *rcv, message msg, ... );
  11. extern value superapply( class c, void *rcv, message msg, va_list va );
  12. #else
  13. extern class defclass();
  14. extern value sendmsg();
  15. extern value applymsg();
  16. extern value supersend();
  17. extern value superapply();
  18. #endif
  19. #endif

The file So-o.h declares the functions of the interface of So-o. It includes the file Object.h which includes the file OL.h.

defclass
SYNOPSIS

class defclass( const char *name, class superclass, unsigned revision, property *class_properties, property *instance_properties, selector *class_messages, selector *instance_messages )

DESCRIPTION

defclass defines a class.

name specifies the name of the class. name must be a valid C variable name.

superclass is the global reference of the superclass of the new class. If superclass is 0, the new class inherits by default from the Object class defined by the global variable Object. defclass automatically builds the class Object if necessary.

revision gives the revision number of the class. revision is an int > 0 which can be used to differentiate successive versions of the class.

class_properties and instance_properties list the properties of the class and instances of the class. A property is a character string terminated by a '\0'. A list of properties is an array terminated by a NULL pointer. A NULL array defines an empty list.

class_messages and instance_messages are associative lists of messages and methods of the class and instances of the class. A message is a character string terminated by a '\0'. A method is a function pointer cast with the macro METHOD defined in OL.h. A selector associates a method to a message. A list of messages and methods is an array terminated by two NULL pointers. A NULL array defines an empty list.

defclass returns a pointer to an allocated struct _class which must be assigned to the global variable name. Notice that a class can be redefined.

A new class automatically receives the message initialize. NOTE: The initialize class method defined by the Object class does nothing.

EXAMPLE
  1. #include "So-o.h"

Includes the declarations of the So-o functions and the class Object.

  1. class Hello;

Defines the class Hello, a global variable.

  1. static instance i_hello(instance self) {
  2.     printf( "Hello from So-o!\n" );
  3.  
  4.     return self;
  5. }

Defines the code of the instance message hello. Conventionally, a method is a function whose name is the instance message prefixed by i_ for an instance method and by c_ for a class method. A class or an instance method is static. The first argument of a method is always the class or the instance which receives the message. Conventionally, this argument is called self. A method which has nothing in particular to return generally returns self.

  1. void defclassHello() {
  2.     selector _i_messages[] = {
  3.         "hello",    METHOD(i_hello),
  4.         0, 0
  5.     };
  6.  
  7.     Hello = defclass("Hello", 0, 1, 0, 0, 0, _i_messages);
  8. }

Builds the class Hello and associates it to the global variable Hello. The Hello class inherits by default from the Object class. Its revision number is 1. It doesn't have any class properties, class messages or instance properties. It has an instance message: hello.

  1. #include "So-o.h"
  2.  
  3. #include <stdlib.h>
  4.  
  5. extern class Hello;
  6.  
  7. extern void defclassHello();
  8.  
  9. int main( int argc, char *argv[] ) {
  10.     instance hello;
  11.  
  12.     defclassHello();
  13.  
  14.     hello = (instance)sendmsg(Hello, "new").p;
  15.  
  16.     sendmsg(hello, "hello");
  17.  
  18.     sendmsg(hello, "free");
  19.  
  20.     exit( 0 );
  21. }

Includes the declarations of the functions and data types of So-o. Declares the class Hello and its constructor. Initializes the class Hello. Sends the message new to the class Hello to create the instance hello assigning to it the pointer of the union returned by sendmsg. Sends the message hello to the instance hello to display the welcome message. Sends the message free to the instance hello to free the space allocated by this instance.

$ gcc -O -c test-Hello.c
$ gcc -O -c Hello.c
$ gcc test-Hello.o Hello.o libso-o.a -o test-Hello
$ test-Hello
Hello from So-o!
CODE
  1. class defclass( const char *name, class superclass, unsigned revision, property *class_properties, property *instance_properties, selector *class_messages, selector *instance_messages ) {

defclass takes 7 arguments. name specifies the name of the class. superclass is the global reference of the superclass of the new class. revision gives the revision number of the class. class_properties, instance_properties, class_messages and instance_messages list the properties and the selectors of the class and the instances of the class.

  1.     if (!Object)
  2.         defclassObject();

Builds the class Object if the global variable Object is 0.

  1.     class c = class_new(name, superclass, revision, class_properties, instance_properties, class_messages, instance_messages);

Creates a struct _class with the function class_new defined by the Object Layer with the parameters of the call to defclass.

  1.     class_send_message(c, "initialize");

Sends the message initialize to the new class.

  1.     return c;
  2. }

Returns the class.

sendmsg
SYNOPSIS

value sendmsg( void *rcv, message msg, ... )

DESCRIPTION

sendmsg returns the result of sending the message msg and its parameters to the instance or the class rcv.

The return type of sendmsg is value, a union.

CODE
  1. value sendmsg( void *rcv, message msg, ... ) {
  2.     va_list va;
  3.  
  4.     va_start(va, msg);
  5.  
  6.     value ret = applymsg(rcv, msg, va);
  7.  
  8.     va_end(va);
  9.  
  10.     return ret;
  11. }

sendmsg builds the variable va of type va_list with the parameters following msg and calls applymsg with rcv, msg and va in argument.

applymsg
SYNOPSIS

value applymsg( void *rcv, message msg, va_list va)

DESCRIPTION

applymsg returns the result of sending the message msg with the parameters in va to the class or the instance rcv.

Calling applymsg directly is an option which can be vital when a code must pass arguments between methods.

CODE
  1. value applymsg( void *rcv, message msg, va_list va ) {
  2. #ifdef TRYCATCH
  3.     static jmp_buf toplevel;
  4.     static unsigned calldepth = 0;
  5.  
  6.     if (calldepth == 0) {
  7.         if (setjmp(toplevel) != 0) {
  8.             calldepth = 0;
  9.  
  10.             fprintf(stderr, BadReceiver, "sendmsg", msg, rcv);
  11.             fprintf(stderr, "\n");
  12.  
  13.             return (value)0;
  14.         }
  15.     }
  16.  
  17.     if (!rcv)
  18.         longjmp(toplevel, 1);
  19.  
  20.     ++calldepth;
  21. #endif
  22.  
  23.     value ret;
  24.  
  25.     switch (((instance)rcv)->type) {
  26.         case INSTANCE:
  27.             ret = object_send_message_va(rcv, msg, va);
  28.             break;
  29.         case CLASS:
  30.             ret = class_send_message_va(rcv, msg, va);
  31.             break;
  32.         default:
  33. #ifdef TRYCATCH
  34.             longjmp(toplevel, 1);
  35. #else
  36.             ret = (value)0;
  37.             break;
  38. #endif
  39.     }
  40.  
  41. #ifdef TRYCATCH
  42.     --calldepth;
  43. #endif
  44.  
  45.     return ret;
  46. }

applymsg calls either class_send_message or object_send_message depending on the type of rcv, CLASS or INSTANCE, with rcv, msg and va in argument. applymsg returns the value returned class_send_message or object_send_message.

When compiled with TRYCATCH, applymsg detects if rcv is NULL or is not a class nor an instance and makes the code jump back to a safe point just before the first call to applymsg in the stack. This mode is useful to analyze a program which craches because of a memory fault probably caused by a faulty reference to a class or an instance.

supersend
SYNOPSIS

value supersend( class c, void *rcv, message msg, ... )

DESCRIPTION

supersend returns the result of sending the message msg and its parameters to the instance or the class rcv in the context of the superclass of the class c.

The return type of sendmsg is value, a union.

supersend is generally used to call the inherited version of a method which is redefined by a subclass. In this case, c is the class of the method which redefines msg and calls supersend.

CODE
  1. value supersend( class c, void *rcv, message msg, ... ) {
  2.     va_list va;
  3.  
  4.     va_start(va, msg);
  5.  
  6.     value ret = superapply( c, rcv, msg, va );
  7.  
  8.     va_end(va);
  9.  
  10.     return ret;
  11. }

supersend builds the variable va of type va_list with the parameters following msg and calls superapply with c, rcv, msg and va in argument.

superapply
SYNOPSIS

value superapply( class c, void *rcv, message msg, va_list va)

DESCRIPTION

superapply returns the result of sending the message msg with the parameters in va to the class or the instance rcv in the context of the superclass of the class c.

Calling superapply directly is an option which can be vital when a code must pass arguments between methods.

CODE
  1. value superapply( class c, void *rcv, message msg, va_list va ) {
  2. #ifdef TRYCATCH
  3.     static jmp_buf toplevel;
  4.     static unsigned calldepth = 0;
  5.  
  6.     if (calldepth == 0) {
  7.         if (setjmp(toplevel) != 0) {
  8.             calldepth = 0;
  9.  
  10.             fprintf(stderr, BadReceiver, "supersend", msg, rcv);
  11.             fprintf(stderr, "\n");
  12.  
  13.             return (value)0;
  14.         }
  15.     }
  16.  
  17.     if (!c)
  18.         longjmp(toplevel, 1);
  19.  
  20.     if (!rcv)
  21.         longjmp(toplevel, 1);
  22.  
  23.     ++calldepth;
  24. #endif
  25.  
  26.     value ret;
  27.  
  28.     switch (((instance)rcv)->type) {
  29.         case INSTANCE:
  30.             ret = object_super_send_message_va(c, rcv, msg, va);
  31.             break;
  32.         case CLASS:
  33.             ret = class_super_send_message_va(c, rcv, msg, va);
  34.             break;
  35.         default:
  36. #ifdef TRYCATCH
  37.             longjmp(toplevel, 1);
  38. #else
  39.             ret = (value)0;
  40.             break;
  41. #endif
  42.     }
  43.  
  44. #ifdef TRYCATCH
  45.     --calldepth;
  46. #endif
  47.  
  48.     return ret;
  49. }

superapply calls either class_super_send_message or object_super_send_message depending on the type of rcv, CLASS or INSTANCE, with c, rcv, msg and va in argument. applymsg returns the value returned class_send_message or object_send_message.

When compiled with TRYCATCH, applymsg detects if c is NULL or if rcv is NULL or is not a class nor an instance and makes the code jump back to a safe point just before the first call to superapply in the stack. This mode is useful to analyze a program which craches because of a memory fault probably caused by a faulty reference to a class or an instance.

EXAMPLE

The first argument of a method is always the class or the instance which receives the message. If a method expects parameters, it must extract them from the va_list which the Object Layer receives from applymsg or superapply and passes to a method as a second argument.

A method can return one of the data types which is a member of the union value defined in OL.h. To assign to a variable or directly pass the value returned by the processing of a message, the code must access the member of the union corresponding to the expected data type.

typedef union _value {
    int i;
    long l;
    float f;
    double d;
    void *p;
} value;
X.c
  1. #include "So-o.h"
  2.  
  3. class X;

Includes the declarations of the functions and data types of So-o. Defines the class X, a global variable.

  1. static class c_initialize(class self) {
  2.     return sendmsg(self, "set", "count", 0).p;
  3. }

c_initialize initializes the property count of the class to 0 when the class is constructed. NOTE: The initialize message is automatically sent to a new class by defclass.

  1. static instance c_new(class self, va_list va) {
  2.     instance i = superapply(X, self, "new", va).p;
  3.  
  4.     sendmsg(self, "set", "count", sendmsg(self, "get", "count").i + 1);
  5.  
  6.     return i;
  7. }

c_new creates an instance of X by sending the message new in the context of the Object class, the superclass of the X class, then increments count before returning the new instance. Notice how the class which implements the method and the argument list are passed to superapply.

  1. static int c_count(class self) {
  2.     return sendmsg(self, "get", "count").i;
  3. }

c_count returns the number of instances of X.

  1. static void i_free(instance self) {
  2.     class c = sendmsg(self, "class").p;
  3.  
  4.     sendmsg(c, "set", "count", sendmsg(c, "count").i - 1);
  5.  
  6.     supersend(X, self, "free");
  7. }

i_free decrements count then executes the message in the context of the Object class. Notice how an instance method sends a message to its class.

  1. static instance i_init(instance self, va_list va) {
  2.     int value = va_arg(va, int);
  3.  
  4.     supersend(X, self, "init");
  5.  
  6.     sendmsg(self, "set", "value", value);
  7.  
  8.     return self;
  9. }

i_init executes the init message in the context of the Object class then initializes value with the parameter value of the message. The parameters of a method are always passed in a va_list. NOTE: The init message is automatically sent to a new instance by new.

  1. static value i_value(instance self) {
  2.     return sendmsg(self, "get", "value");
  3. }

i_value returns the value of an instance of X.

  1. void defclassX() {
  2.     property _c_properties[] = {
  3.         "count",
  4.         0
  5.     };
  6.     property _i_properties[] = {
  7.         "value",
  8.         0
  9.     };
  10.     selector _c_messages[] = {
  11.         "initialize",   METHOD(c_initialize),
  12.         "new",          METHOD(c_new),
  13.         "count",        METHOD(c_count),
  14.         0, 0
  15.     };
  16.     selector _i_messages[] = {
  17.         "free",     METHOD(i_free),
  18.         "init",     METHOD(i_init),
  19.         "value",    METHOD(i_value),
  20.         0, 0
  21.     };
  22.  
  23.     X = defclass("X", 0, 1, _c_properties, _i_properties, _c_messages, _i_messages);
  24. }

Initializes the class X. The class X inherits from the class Object. It has 1 property: count, the number of instances it has created. An instance has 1 property: value, its value. The class X redefines the messages initialize and new. It implements the message count. An instance redefines the messages free and init. It implements the message value.

TEST
  1. #include "So-o.h"
  2.  
  3. #include <stdlib.h>
  4.  
  5. extern class X;
  6.  
  7. extern void defclassX();
  8.  
  9. int main( int argc, char *argv[] ) {
  10.     instance x1, x2;
  11.  
  12.     defclassX();
  13.  
  14.     printf("count=%d\n", sendmsg(X, "count").i);
  15.  
  16.     x1 = (instance)sendmsg(X, "new", 1).p;
  17.     printf("x1=%d\n", sendmsg(x1, "value").i);
  18.  
  19.     x2 = (instance)sendmsg(X, "new", 2).p;
  20.     printf("x2=%d\n", sendmsg(x2, "value").i);
  21.  
  22.     printf("count=%d\n", sendmsg(X, "count").i);
  23.     sendmsg(x1, "free");
  24.     printf("count=%d\n", sendmsg(X, "count").i);
  25.     sendmsg(x2, "free");
  26.     printf("count=%d\n", sendmsg(X, "count").i);
  27.  
  28.     exit( 0 );
  29. }

Initializes the class X. Displays the count of instances. Creates an instance of X with the value 1. Displays its value. Creates an instance of X with the value 2. Displays its value. Displays the count of instances. Frees the first instance. Displays the count of instances. Frees the second instance. Displays the count of instances.

$ gcc -I/usr/local/include/so-o X.c test-X.c -lso-o -o test-X
$ test-X
count=0
x1=1
x2=2
count=2
count=1
count=0
SEE ALSO

Installation, Object Layer, Object, A game of poker

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].