logo
Tutorial - Part IV: Extension Modules
previous table of contents

Convenience Classes and Functions

Caius provides a number of convenience classes and functions, that are meant to make object-oriented programming in [incr Tcl] more fun and more efficient.

Exception Handling

Import the Error package to gain access to Caius' advanced error handling facilities. Code blocks that may raise an error are wrapped in an except clause, as shown below.

package require Error

except {
    raise RuntimeError "something bad happened."
} e {
    RuntimeError {
        puts "Caught a runtime error: [$e msg]"
    }
    TimeoutError {
        puts "Caught a timeout exception!"

        # reraise the exception
        reraise $e
    }
}

The example demonstrates how you can anticipate and respond to different types of exceptions. If you want to re-raise an exception from a handler, make sure to use the reraise keyword and not raise.

Using an except clause, you can also catch standard Tcl errors raised with the error command:

package require Error

except {
    error "this is a Tcl error."
} e {
    TclError {
        puts "Caught a Tcl error: [$e msg]"
    }
}

A word of caution: the third argument to except is actually interpreted as a list. That's why you cannot put comments there:

except {
    # Comments as usual...
} e {
    # You cannot put a comment here!
    TclError {
        # But you can put a comment here.
    }
}

Caius' sub-modules define and may raise their own exception types. To create a new exception Type, simply inhert from base type Exception. For example, RuntimeError is declared as follows:

::itcl::class RuntimeError {
    inherit ::Exception

    constructor {msg} { ::Exception::constructor $msg } {}
    destructor {}
}

Serialization to JSON

Caius allows you to create objects, which can by serizalized to and later restored from JSON. Let's say we have a Vertex class to represent a point in 3D space. This could look roughly like this:

package require Itcl
package require OOSupport

::itcl::class Vertex {

    common attributes {
        {number x null rw}
        {number y null rw}
        {number z null rw}
    }

    method constructor {x y z} {
        OOSupport::init_attributes

        set _x $x
        set _y $y
        set _z $z
    }

    OOSupport::bless_attributes -json_support
}

At the top of the class definition, we created a class variable attributes, which is a list of 4-tuples {type name default access}. This way, we declared the attributes x, y and z, as the Vertex coordinates in space. Available attribute types are

  • number
  • string
  • bool
  • or a class name (must be recognized by itcl::is class)

Additionally you can declare arrays of either type by wrapping the type specifier in square brackets. You cannot have mixed-type arrays.

In the constructor the call to init_attributes implicitely creates the corresponding member variables _x, _y, _z. This seems to be a bit awkward at first sight. But then at the bottom of the class definition, the call to bless_attributes creates accessor functions for each attribute according to the attribute's permissions.

Attributes can be marked as

  • rw (read-write),
  • ro (read-only),
  • wo (write-only) or
  • - (no access).

Since all our attributes are marked as rw, both an accessor and a mutator are created. You can now modify the properties of a Vertex as follows:

set vertex [Vertex #auto 1.2 3.3 9.7]

# prints "1.2"
puts [$vertex x]

$vertex set_x 11.1

# prints "11.1"
puts [$vertex x]

The additional argument -json_support causes your Vertex objects to be blessed with methods to_json and from_json. Calling the first will dump all attributes declared in common attributes as JSON, calling the latter will restore the object state from JSON input.

puts [$vertex to_json]

The above prints the object's state in JSON notation to standard output:

{
        "x": 11.1,
        "y": 3.3,
        "z": 9.7
}

Concerning restoration of an object from JSON consider the following example:

set new_vertex [Vertex #auto 1.0 1.0 1.0]
puts [$new_vertex to_json]

$new_vertex from_json [$vertex to_json]
puts [$new_vertex to_json]