VISH  0.2
Creating VISH Objects

Object Management

Vish Objects are stored in a data base, or "registry". Such a registry is used for various categories of objects, VObjects just one of them. Another important category of objects are creator objects, i.e. objects which allow creation of Vish objects. Creator objects are derived from class VCreatorBase and typically are instantiations of the VCreator template.

In contrast to VObjects, creator objects usually are static objects. When provided by a shared library or dynamically loaded library, they exist throughout the load time of this library as static objects. However, an application may also create and destroy VCreator objects at runtime, if it desires to do so.

The VISH database identifies managed objects through two parameters: a type information (called the database domain) and a textual description, the object name.

Note that reading further requires knowledge of Memory Management and Iterator Concept .

Generic Object Registration, Lookup and Deletion

The general database management is implemented via class VManagedObject. This base class VManagedObject allows identifies objects via the Domain type (type_info) and a textual description. The same textual description may occur for multiple domain types, but must be unique per domain type. The child template class VManagedDomainObject reduces the degree of freedom to a specific domain type and leaves only the textual description to be specified. In other words, within one domain type a string is sufficient to uniquely identify an object. The template class VManagedDomainObject provides such a reduction of the general VManagedObject class for a certain domain type.

This object database may be queried for which objects are referenced in it. Following the coding concepts of Iterator Concept , it is required to derive from class VManagedObjectIterator and implement a virtual callback function:

struct  FindAllObjects : VManagedObjectIterator
{
        override   bool apply(int priority,
                              const RefPtr<VManagedObject>&TheObject,
                              const std::string&ModulePath, int&Id)
        {
                if (TheObject) 
                {
                        // ... HAVE an object ...
                }
                return true;
        }
};

FindAllObjects MyObjectFinder;
        VManagedDomainObject<VObject>::traverse( MyObjectFinder );

If a specific name of an object is known, it can be queried by name:

RefPtr<VManagedObject> MyObject = VManagedDomainObject<VObject>::find("MyObjectName");

In general, one would want assign the result of the find() function to a pointer to a child class of VManagedObject, which is easiest done using RefPtr class from Memory Management . Objects are stored in the database via reference pointers. They are kept alive as long as at least a pointer from the databse function refers to them. The may be deleted from the database via the static remove() function;

Note that this will not deleted the object as long as it is reference by other means, like a reference pointer somewhere else. However, in this case it will vanish as soon as the last such pointer reference has vanished. This may be the case if an object is used locally within some function that makes use of this object. The mechanism ensures that the object is still alive when it is used, even though it is already scheduled for removal.

Creating VObjects

The VInputCreatorBase database domain handles objects which allow creation of VObjects. Simple code to create an object, whose name is known, with a specific name is as follows:

RefPtr<VObject> CreateObject(const string&CreatorName, 
                             const string&ObjectName)
{

        if (RefPtr<VCreatorBase> MyCreator = VCreatorBase::find( CreatorName ) )
        {
        RefPtr<VObject> = MyCreator->create( ObjectName);
        }
}

Note: This VCreatorBase database domain is expanded by each instance of an object derived from VCreatorBase , such as VCreators. Vish comes with a plugin mechanism that loads shared libraries or DLL's and automatically adds all VCreators in those plugins to the database. To make use of this plugin mechanism, The function LoadVModule() must be called on a specific plugin file, or the function openModules() for an entire path. For instance, an application using Vish may start like this:

#include <ocean/plankton/VModules.hpp>

static  bool InitCallback(const char*n, bool)
{
        printf("Loading %s...", n);
        fflush(stdout);
        return true;
}

int main( int argc, char **argv )
{
        openModules(argv[0], InitCallback );
        ...
}

Vish objects will not be available if no modules are loaded and it is the responsibility of the application to provide appropriate paths here. Vish does not have an internal list of paths. However, the openModules() function can be called multiple times, with another path argument. It may also point to a file, in which case it will load all modules that reside in the same directory as this file.

The abstract class VCreatorBase is the base class for VObject creators, its type is the database domain. In this domain, a textual description is the only degree of freedom. Child classes of VCreatorBase provide means to create (abstract) VObjects. Template class VCreator implements creation of concrete VObject child classes. Elements of this domain will usually be static objects residing in a dynamically loaded module. Typical application code, based on a user-defined class MyObject, is as follows

namespace // anon namespace
{

class   MyObject : public VObject
{
        // implementation
};

static  Ref<VCreator<MyObject> > MyObjectCreator("Experimental/MyObject");
} // end anon namespace

The name of the VCreator object is completely irrelevant. The VCreator object will never be referenced by its name in C++, and can thus be static (visible only in the C++ file of its definition). Once its constructor is called - which is the case once the shared/dynamic library is loaded - it will register itself into the VCreatorBase database domain. It is then accessible through the string "Experimental/MyObject" (in this example). It is moreover advisable to put all class definitions that are only used within one C++ file / Vish plugin into an anonymous namespace. Otherwise, there might be (very hard to detect!) name space clashes at runtime if another object type is named the same.

The object domain

Vish objects itself are stored within a database of domain VObject. In general, application code using VISH will only have to deal with VObjects.

A VObject is created by first finding a VCreatorBase object via the (static member) VCreatorBase::find() and then calling its (virtual) VCreatorBase::create() function as in

if (RefPtr<VCreatorBase> vc = VCreatorBase::find("ObjectType") )
{
RefPtr<VObject> = vc->create("ObjectName");
}

See Input/Output of VISH Objects on how to query the properties of VObjects, and how to connect them.

Input Objects

VObject may implement one or more input types. Also, many VObjects may implement the same input type. See Input/Output of VISH Objects for more detailed information. In short, an existing VObject may be queried if it supports a certain input by calling its VObject::getImplementation() function. It may return a valid VInputBase object for more than one type. Member function VObject::iterateOutputs() allows to inspect all possible outputs, VObject::getOutputs() returns this information as a StringList, and VObject::getOutput() provides information about output of a given name. Similarly, function VObject::iterateInputs() allows to query which inputs are required by some object. The function VObject::attach() allows to connect inputs and outputs among different objects (referring to the global function VObject::attachParameter() at the end).

Without an already existing VObject, the VInput database may be employed to find creators for objects that implement a certain input type (see also VISH Input Object Management). For this to work, the function registerVInput() has to be called for each creator. The template class VInputCreator provides a convenient implementation for VObjects that provide a single input type. Class VMultipleInputCreator is a generalization allowing registration of arbitrary VManagedObjects. Via template nesting it may also be employed for multiple input types.

Still, the name of each VObject must be unique, but the associated input type does not necessarily be unique. To select a certain input type implemention, VCreationPreferences are used. However, they are not strongly enforced and may only be partially accomplished.

Loading Vish Objects

Besides creating Vish Objects in memory within the application as described in Creating VObjects, they can also be created by loading from a file. The class VLoader provides a static member function to do just this:

RefPtr<VObject> MyObject = VLoader::Load("MyData.f5");

More specific information about the loading capabilities is provided via the class VLoader. It defines a domain type for Generic Object Registration, Lookup and Deletion , all such domain-type specific functions like iteration and find by name are available on the template specialization VManagedDomainObject<VLoader>. A specific VLoader may be queried if it can handle a certain URL, or can be asked to load data from a certain URL.

A new loading routine is implemented by deriving a class from base class VLoader, and creating an object of this type:

struct  VDocObject : struct VObject
{
        // implementation
};

struct  MyDocLoader : struct VLoader
{
        bool loadable(const string&url)
        {
                return extname(url) == "doc";
        }

        RefPtr<VManagedObject> load(const string&url)
        {
                // do something with url and possibly create an object
                return new VDocObject();
        }
};

Using Vish Script

The vscript library provides a rudimentary interface to perform most Vish operations via a a simple script. This functionality is provided via class VScriptParser and is available as well to applications. The constructor of this class parses some text, the member function VScriptParser::exec() performs the actual evaluation:

VScriptParser MyParser("Backgrounds/Monochrome MonochromeBackground");
        MyParser.exec();

Note that the VScriptParser "language" is very rudimentary and not as advanced as a real programming language, such as tcl/tk or python. It mostly exists as quick proof-of-concept, demonstrating how to implement scripting for Vish as a plugin. Someday someone will implement a full programming language instead. Therefore, one should not rely too much on the vscript library as preferred solution to create and connect objects. The error handling is pretty bad, and the syntax of vscript may well change over time, which both makes his approach problematic. Direct interfacing of the Vish C++ is preferable, as any change in syntax will be obvious at compile time.