Intrinsic Classes

Note: most authors will not need to know anything about intrinsic classes in general; rather, authors will simply want to know about particular intrinsic classes, such as Dictionary.  This section is included for the curious.

 

The T3 VM has an extensibility mechanism that allows object classes to be implemented using native code.  The VM documentation refers to these native classes as "metaclasses," but we refer to them here as intrinsic classes.

 

An intrinsic class is implemented as native code (sometimes called "machine code"), but it is not built in to the VM in the sense that it is an essential part of the VM design.  Instead, T3 lets the VM implementation include a chosen set of intrinsic classes; like the intrinsic functions, the set of intrinsic classes that a particular VM implementation provides is up to host application.  The host application is to some extent defined by the set of intrinsic functions and classes that it provides.

 

The compiler is not pre-configured with a particular set of intrinsic classes.  Instead, the compiler accepts syntax that defines the intrinsic classes that the program uses; the compiler stores this information in the image file, and the VM "dynamically links" the image file to the intrinsic classes when the VM loads the image file at run-time.  If the image file depends upon intrinsic classes that are not included in the VM implementation, an error occurs when the image is loaded.

 

You will probably not need to write your own intrinsic class definitions, because you will normally get these definitions from header files that are provided with the VM implementation you're using.  However, for the sake of completeness, here's what the syntax for an intrinsic class definition looks like:

 

    intrinsic class class_name 'global_name' optional_superclass
    {
        optional_static first_prop_name optional_parameter_list ;
        optional­_static second_prop_name optional_parameter_list ;
        ...
        optional­_static last_prop_name optional_parameter_list ;
    }

 

The class_name is the name of the intrinsic class, as used in the source code; this can be any valid symbol, and exists at global scope in the source code (at the same level as object, property, and function names).  The global_name is the name that the VM uses to dynamically link to the class when loading the image file.  The global_name is defined by the person who created the intrinsic class; a list of known metaclass names is part of the T3 VM specification.   The property names listed are ordinary property names, and define the symbols that your source code uses to access the methods and properties of the intrinsic class.  The order of these names is important, because the dynamic linking to the intrinsic class's methods is done on the basis of the positions of these property names: the first property listed links to the first intrinsic class function, and so on.

 

The optional_superclass clause consists of a colon followed by the name of another intrinsic class, previously declared through the intrinsic class statement.  If included, this provides the compiler with information on the inheritance relationship between this class and its superclass.

 

You can optionally provide a formal parameter list for each property defined.  The compiler completely ignores these definitions, but you can include them for documentary purposes.  (The compiler ignores any formal parameter lists defined here because the TADS language has no compile-time type declarations for local variables, properties, return values, or other expression elements.  If you invoke one of the named methods on, say, a local variable, the compiler has no way of knowing what type of object the local variable will contain at run-time, so the compiler cannot assume that the method's parameter list should be the same as that defined for an intrinsic class.)

 

In addition, each property name can be immediately preceded by the keyword "static," which indicates that the property being defined is a static method.  A static method is a method that can be invoked directly on the class itself, without needing an instance.  If the "static" keyword is provided, the compiler accepts it but otherwise ignores it; the keyword is allowed to allow for documentary purposes, to make it plain to someone reading the intrinsic class definition that the method is static.

Creating an Instance of an Intrinsic Class

The TADS compiler provides special syntax to define instances of certain intrinsic classes, so in many cases a program instantiates an intrinsic class implicitly.  For example, the "dictionary" statement implicitly defines an object of intrinsic class Dictionary, which the compiler initializes with dictionary property data defined in the program.  In addition, the compiler automatically creates BigNumber objects when a program contains floating-point numbers.

 

Most intrinsic classes also let you create instances explicitly using the "new" operator.  The syntax to create an instance of an intrinsic class is the same as for a regular object, and uses the class name defined in the "intrinsic class" statement.  For example, to create an instance of a BigNumber, you would write something like this:

 

  x = new BigNumber('3.14159265');

 

Testing for Class Membership

You can determine if an object is an instance of an intrinsic class using the ofKind() method.  Simply use the intrinsic class name as the argument:

 

  if (x.ofKind(BigNumber)) // etc

Reflection Behavior

The property reflection methods have some special behavior when used with intrinsic class objects.

 

getPropParams(), propDefined(), and propType() will all indicate that a property is undefined when called with a non-static property on an intrinsic class object.  For example, File.propDefined(&closeFile) will return nil, because closeFile() is not a static property of File.  This might be a little surprising at first, but there's a good reason: calling File.closeFile() isn't meaningful.  It's only meaningful to call closeFile() on instances of File, not on File itself.

 

getPropList(), on the other hand, does include non-static methods in its return value.  The reason is that getPropList(), when called on an intrinsic class, returns the properties that can be used with instances of the class.  So, File.getPropList() includes &closeFile in its return value, because closeFile() can be called on any instance of File.

 

A "static method" of an intrinsic class is one that you can call directly on the intrinsic class object.  Non-static methods are only meaningful when called on instances of the class.  getPropList() returns both kinds of methods, because you can also call static methods on instances of an intrinsic class.  To determine which is which, you can use propDefined(): if x is an intrinsic class, and x.getPropList() returns a particular property p, then call x.propDefined(p) to determine if p is static or non-static.  If propDefined() returns true, then p is static, because it's defined directly on the intrinsic class object; if propDefined() returns nil, then p is non-static.

Extending Intrinsic Classes

It is possible to extend intrinsic classes by adding new methods.  Refer to the section on intrinsic class extensions for details.

Restrictions on Intrinsic Classes

The TADS compiler does not allow arbitrary intrinsic class names to be used interchangeably with regular objects and classes.  Some of the specific restrictions on when you may use intrinsic classes are: