TypeAccess (TA) is a sophisticated meta-type information system for C++ programs. The header files of the application are scanned by a program called maketa which builds a comprehensive description of all the classes (
TypeDef) and their methods (
MethodDef), members (
MemberDef), etc. This information is then available at runtime, which enables things like:
- Programmatic access to members and methods
- Automatic streaming of complex object hierarchies
- Automated building of property edit dialogs
- Dynamic creation of object instances based on dynamic runtime typing
- Dynamic generic runtime manipulation of objects, such as querying its members, methods, class type, whether it inherits from a particular class, etc.
- Full API docs avail in Help Browser and on this wiki.
TA basically provides the same kinds of services as "reflection" in systems like Java and C#. A set of directives can be applied to comments in the header files to control runtime behavior, such as visibility of member variables, etc.
Compiling Issues for Maketa
maketa is called automatically during the build process, and generates TA_FileName.cxx files which contain all the type information for that file.
Anything you might want to hide from maketa during the generation of these files, surround as follows:
#ifndef __MAKETA__ // stuff you want to hide here #endif
and likewise for anything that is for maketa only -- for example you can redefine the comment directives for members or methods of derived classes by including them only in the maketa pass.
The TA_FileName.cxx files are generated with this definition at the top, before any headers are included:
Thus, if there is anything you need to do differently in the scanned header when the TA_ file is being compiled, adding an #ifdef on this will allow you to do that.
These files may potentially need to be regenerated in ways that the make system can't automatically detect. If you get an error with compiling a TA_xx file, or the type information in the file (viewable in the Help Browser for that type) is not accurate, you can remove the file -- it is located in:
build/src/[temt | network]/lib/__/[ta | network | leabra..]/TA_*
If many files seem to be out of date, you can type:
make clean_ta_[ta | network | leabra | bp | cs | so] make clean_ta_all # clean all of the above make clean_ta_emergent # clean network, leabra, bp, cs, so
to clean the files for that specific directory.
Version 6.2 Major Overhaul
As of version 6.2 of emergent, maketa now generates separate TA_ClassName.cxx files for each separate file that is processed, much like the Qt moc system. There is no longer any global _TA_types.h file, and associated bottleneck in dependencies that often required a complete recompile of the software for seemingly minor changes. Instead, each header file must define its own TypeDef_Of(MyClass); type access handle for each class that is going to be processed. This can be used in other source files as needed to provide access to the global TA_MyClass handle -- of course a linker error will occur if the corresponding type is not actually processed by maketa.
This release also fixed a large number of previous limitations of the maketa system for parsing various C++ syntax -- there is now much less need for #ifndef __MAKETA__ guards in the code -- only in a few very specialized cases, and also to generally speed things up by preventing the inclusion of Qt and other such classes, which do not otherwise need to be scanned.
- The TypeAccess/CSS Manual, Section 5 "Programming with TypeAccess"
- PDP++ (TypeAccess and CSS)
- Comment directives
- maketa gotchas
At startup, the TypeAccess system instantiates various types. These global instances, one per type, are named using the convention
TAI_ClassName. They are declared and defined in the
*_TA.cpp files as pointer types. They get initialized in those files'
ta_Init_*() functions by calling
new. Each type must have a default constructor.
Whether a type gets an instance created is determined by a few factors:
- If a class has an
#INSTANCEobject directive, or one of its base classes has an
##INSTANCEdirective, an instance will be made of this class.
- Note: Using two hashes means the directive applies to all subclasses as well.
- If a class is marked
#NO_INSTANCE, then an instance will not be made.
- If not marked either way, and the class inherits from
taBase, then the default is INSTANCE (see
- Otherwise, if the class is not marked and does not inherit from
taBase, then the default is NO_INSTANCE.
An abstract base class could legitimately be marked
##INSTANCE #NO_INSTANCE to signify that any classes deriving from it should have instances created, but it itself should not (since it's an ABC, it can't be instantiated).
If a type has an instance created, that type's
TypeDef will contain a pointer to the instance pointer. The instance of a type can be accessed by calling
GetInstance() on a
TypeDef object, and casting the result to the expected type.