C/Tcl Interface - Hierarchical Objects

In Janus you can use a dot or a colon to descend in an object hierarchy. For example ob1.ob2:ob3.ob4:ob5:ob6 refers to an object ob6 which is a subobject of an object ob5, which itself is a subobject of ... etc.

The colon is used to descend into a list element that is referenced by name. In the above example cb3, cb5 and cb6 are names of list elements, and ob2 and ob4 are singular subobjects objects (like structure fields in C).

Examples:

Imagine you have a distributions set (DistribSet) object, named dss. Every distribution set object must have exactly one codebook set (CodebookSetCodebookSet is named cbs, then the distribution set was most likely created with the command DistribSet dss cbs. Now you can access the codebook set in two ways, first you can simply use the name cbs, and the second option is the name dss.codebookSet. Here the dot means, "Give me the codebook of the distribution set dss.

A distribution set usually has some distributions (Distrib) as its subobjects. These are stored in a generic list. Each distribution has a name, and can be acessed using the colon construct. Say, you want to access the distribution named SIL-m(0) of the distribution set dss then you can type dss:SIL-m(0). Here you don't have the alternative to access the single distribution directly, because it only exists within the senone set object. If you don't know the name of the distribution which you want to access, but you do know its index, say 123, (e.g. from the configuration output of a senone), then you can also access it by dss.item(123).

You can use colon or dot constructs wherever an existing object is expected. You can run methods for hierarchically named objects and you can use them as arguments for methods and procedures that expect an object.

Theoretically, there is no limit to the nesting depth. You could, for example, do:

dss.codebookSet.featureSet:LDA.data
for accessing the matrix of the LDA feature of the feature set of the codebook set of the distribution set dss.

How Is It Done

Every implementation of an object class that can have subobjects should have an access function in its type information structure. Whenever the interface module has to analyse a hierarchical object it parses the name til the next colon or dot, finds out what object type the first name belongs to, calls this object class's access function with the next name in the hierarchy, receiving a pointer to the subobject and a pointer to the subobject's type information structure. Every descend step is stored, such that C function that need to know not only a pointer to the object on which they should work, but also its full name as entered by the user, can access that full name by calling itfCommandName(), a string-valued parameterless function in the interface module.