Broadcasting

Broadcasting is an example how powerful method delegation can be. It allows to write elegant code in common situations, where you otherwise would need a for-loop. Objects can define a forward handler. This handler then has the possibility to forward a message to more than one object. An example of such an object is the Set container from /obclib. It can be configured to forward all messages, it doesn't know to all the objects it contains. Here is the same vehicle example using broadcasting instead of for-loops.

main.c

    #include "../obc/obc.h"
    #include "../obclib/obclib.h"
    #include "vehicleI.h"
    #include "car.h"
    #include "tunedcar.h"
    #include "boat.h"
    
    int main(){
        Set    allVehicles = set_create();
        set_config(allVehicles, SET_ISOWNER | SET_DOFORWARD);
        
        /* create objects */
        set_add(allVehicles, car_create());
        set_add(allVehicles, tunedcar_create());
        set_add(allVehicles, boat_create());
        
        /* use objects */	    
        vehicle_accelerate(allVehicles);
        obj_print(allVehicles, stdout);
        
        /* free objects */
        obj_destroy(allVehicles);   
    
        return 0;
    }
  

Since allVehicles doesn't understand the message vehicle_accelerate(), it is forwarded to car, tunedcar and boat. Similar things happen with obj_print(). Because we configured allVehicles to be owner of its elements, obj_destroy() does free them as well.

Set has a build in forward handling. How can you implement this for your own object? Here is the same example using a pointer string. A pointer string is simply a NULL terminated pointer array. The method obj_setForwardHandler() is used to register pstr_forwardHandler() to the pointer string object pstr.

main.c

    #include "../obc/obc.h"
    #include "vehicleI.h"
    #include "car.h"
    #include "tunedcar.h"
    #include "boat.h"
    
    static Obj pstr_forwardHandler(void** self, ForwardIterator it) {
        return self[it->counter++];
    }
    
    int main(){
        Obj    pstr[4];    
    
        obj_setForwardHandler(pstr,    (ObjForwardHandler)pstr_forwardHandler);
        obj_config(pstr, "Pstr", 0);
        
        /* create objects */
        pstr[0] = car_create();
        pstr[1] = tunedcar_create();
        pstr[2] = boat_create();
        pstr[3] = NULL;
        
        /* use objects */
        vehicle_accelerate(pstr);
        for(i=0; i < 3; i++) {
            obj_print(pstr[i], stdout);
        }
        
        /* free objects */
        obj_destroy(pstr);   
        obj_destroyInfo(pstr);   
    
        return 0;
    }
  

The methods vehicle_accelerate() and obj_destroy() are now forwarded to all objects returned by pstr_forwardHandler(). But obj_print() isn't because obj_print(), like obj_getHashCode() and obj_compare(), does implement a default behavior for each object. If you need to delegate this methods, you must implement this behavior explicitly (like Set does for obj_print).
ATTENTION: don't forget to call obj_destroyInfo(pstr) at the end to free the object resources for pstr!

The forward handler itself is easily implemented. It is called as long as it doesn't return NULL and must return objects where the method is forwarded to. The ForwardIterator offers the following fields to help you iterating:
methodName, counter, counterPtr, data, dataPtr