VISH  0.2
Input/Output of VISH Objects

VISH objects have inputs and outputs.

Both can be understands as "slots" where data flow in or out, even though in practice there might be no data actually be flowing and everything is done via referencing the same memory location. The in/out concept is thus more a semantical description than an actual operation.

Both input and output slots are bound to a specific type. By "type" we mean a native C++ type, such as int, double or as well any user-defined structure. It must be defined in C++ source code and this type definition must be available to all objects who actually operate on this type.

An input slot is a value which is requested by a certain object. The value of this input may be provided by another VISH object (derived from VObject) or an input object (derived from VInput). A VObject may request an arbitrary number of inputs, each of these is bound to a specific type and is accessed from the VObject through a name.

Creating Output Objects

An output slot refers to the types that a VISH object provides to other objects to be used. A VObject that does not provide any output but requests only inputs is called a "data sink", while a VObject that provides output without input is called a "data source". A VObject may provide an arbitrary number of outputs, each of them associated with a specific type and name. To to check whether a certain VObject provides a specific type as output, call

        bool VObject::implements(const type_info&what) const;

To find out which outputs are provided at all by a VObject, call

        void VObject::iterateOutputs(VOutputIterator&VOut, const type_info&just_these = typeid(void) );

The output iterate will provide a more detailed information about the output available by some VObject. The actual output is then available as a VParameter and can be retrieved by calling

        RefPtr<VParameter> VObject::getImplementation(const type_info&what, 
                                                      const string&name = "",
                                                      const string&member = "");

Note that the name parameter is only required if a VObject provides multiple outputs of a certain type, and the member parameter is required only if a member of an output type is requested (advanced issue, will be explained elsewhere).

All the output objects bound to a certain VObject are called the dependencies of this object. If a VObject is changed, then all dependencies will need to be changed as well (this is the data flow graph). Given a specific VObject, we may be interested what can be done with its output. Two possibilities exist here:

While the second possibility is just a matter of changing the data flow graph, the first one requires object creation. Finding which objects are appropriate is then a matter of VCreator objects. These are static objects that always reside in memory. They are created when a plugin is loaded and deleted when the plugin is unloaded (usually - in theory they could as well be created dynamically). Thus, VCreator of a certain VObject (i.e. the static object that may create a VObject) must be equipped with the information which inputs the to-be-created VObject will accept. This is done through the AcceptList<> template parameter. While a standard VCreator for an VObject type "DataFilter" looks like

static VCreator<DataFilter>  VDataFilterCreator("Examples/DataFilter");

To equip this VCreator with a set of types that the DataFiler VObject will accept once created, it needs a list of types provided by an AcceptList, here we will accept a type "Alpha":

static VCreator<DataFilter, AcceptList<Alpha> >  VDataFilterCreator("Examples/DataFilter");

Multiple types are given in the type list, e.g. lets add an int type:

static VCreator<DataFilter, AcceptList<Alpha, AcceptList<int> > >  VDataFilterCreator("Examples/DataFilter");

The order of the given types is not relevant. Note that this mechanism is just to make static object creation easy. Alternatively one can also implement a derived VCreator object and then overload the virtual function

        RefPtr<VAcceptInfo> VCreator::accept(const RefPtr<VObject>&vobj) const;

to implement any dynamic mechanisms.

Querying for Output Objects

Alternatively to creating a new VObject, we can also query existing VObjects whether they may accept a certain output of a VObject as an input type. To do so, we would need to find out whether the VObject, that might possible serve as an dependency, hosts a parameter of compatible type. This is to be done by iterating over this object's parameters:

        void VObject::iterateParameters(int expertLevel, VObjectInputIterator&VIIt);

Once a type match is found, then the various

        AttachErrorCode VObject::attach()

member functions can be used to set the input parameter of the dependency to the output parameter of the source object.