Defining a New Message Class

Every user-defined message is derived from class Message. Certain virtual functions defined in that class must be overridden, others may optionally be overridden. Here is an example of a user-defined message type:


// This is a simple vector message object. It stores
// an array of integer values of arbitrary length.
// The length is specified by the constructor.

#include "kernel/Message.h"

class IntVecData : public Message
  int mLength;
  void init(int pLength, int* pSrcData)
    mLength = pLength;
    mData = new int[mLength];
    for (int i = 0; i < mLength; ++i)
      mData[i] = *pSrcData++;
  // the pointer is public for simplicity
  int* mData;

  int length() const { return mLength;}

  // functions for type-checking
  const char* dataType() const { return "IntVecData"; }

  // isA responds TRUE if given the name of the class or
  // of any baseclass.
  int isA(const char* typ) const
    if (strcmp(typ,"IntVecData") == 0) return TRUE;
    else return Message::isA(typ);

  // constructor: makes an uninitialized array
  IntVecData(int pLength):
    mData = new int[pLength];

  // constructor: makes an initialized array from a int array
  IntVecData(int pLength,int* pSrcData)
    init(pLength, pSrcData);

  // copy constructor
  IntVecData(const IntVecData& pSrc)
    init(pSrc.mLength, pSrc.mData);

  // clone: make a duplicate object
  Message* clone() const { return new IntVecData(*this);}

  // destructor
    delete [] mData;


This message object can contain a vector of integers of arbitrary length. Some functions in the class are arbitrary and the programmer may define them in the way that is most convenient. However, there are some requirements.

The class must redefine the dataType method from class Message. This function returns a string identifying the message type. This string should be identical to the name of the class. In addition, the isA method must be defined. The isA method responds with TRUE (or 1) if given the name of the class or of any base class. Otherwise, it returns FALSE (or 0). This mechanism permits primitives to handle any of a whole group of message types, even for classes that are defined after the primitive is written.

Because of the regular structure of isA function bodies, macros are provided to generate them. The ISA_INLINE macro expands to an inline definition of the function; for example,


could have been written like the example above, instead of the definition of isA to generate exactly the same code. Alternatively, to put the function body in a .cc file, the programmer can write

int isA(const char*) const;

in the class declaration and put


in the .cc file (or wherever the methods are defined).

The class must define a copy constructor, unless the default copy constructor, generated by the compiler which does member-wise copying, will do the job. The class must redefine the clone method of class Message. Given that the copy constructor is defined, the form shown in the example, where a new object is created with the new operator and the copy constructor, will suffice. 

In addition, the programmer may optionally define type conversions and printing functions if they make sense. If a primitive which produces messages is connected to a primitive which expects integers (or floating values, or complex values), the appropriate type conversion function is called. The base class, Message, defines the virtual conversion functions asInt(), asFloat() and asComplex() and the printing method print(), see the file $MLD/include/kernel/Message.h for their exact types. The base class conversion functions assert a run-time error, and the default print function returns a StringList saying

<type>: no print method

where type is whatever is returned by dataType(). By redefining these methods, the programmer can make it legal to connect a primitive that generates messages to a primitive that expects integer, float, or complex particles, or he can connect to a Printer or XMgraph primitive. For the XMgraph to work, you must define the asFloat function, for Printer to work, you must define the print method.