TclOO Properties

This page describes an upcoming enhancement to TclOO: Property tracking.

The project is being developed in the "scgi" branch of tcllib

In the next release of tcllib, it will be available as the oo::meta package. Option handling (built on top of meta) will be provided by oo::option.

The concept: Adding information that is tracked by class that allows the developer to embed data inside of classes

New Definition Keywords

The following keywords will be added to oo::define:

property field ?field...? value

Set a property from the class definition.

The following method will be added to oo::class:

meta method field ?field...? value

This command is a passthrough to ::oo::meta::info (filling in the appropriate class).

The following method will be added to oo::object:

meta method field ?field...? value

This command is a re-implementation of ::oo::meta::info which combines the complete state of the class meta data combined with a local variable config which allows the object to extend/enhance/replace the class meta data with its own.

New Introspection Tools

::oo::meta::info

::oo::meta::info submethod class arguments...

This method allows access to this class. Arguments that follow determine exactly what's done.

::oo::meta::info class dump
Return the the complete meta data of a class in dict form
::oo::meta::info class getnull field ?field...?
Return a value for a property, or an empty list if the value does not exist.
::oo::meta::info class is true|false|integer... field ?field...?
Return true if a property exists and confirms to string is arg2 -strict
::oo::meta::info class set field ?field...? value
Add/modify a property
   Any other methods are passed to the '''dict''' command.

Usage

This system was originally intended to provide a Tk option-like database for TclOO objects.

# Dump the entire option dictionary
set option_dict [my meta get option]
# Access a list of options
set option_list [my meta keys option]
# Check if an option exists
set exists [my meta exists option]
# Get the default value for color
set color [my meta getnull option color default]
oo::define oo::class_withopts {
    constructor args {
        my InitializePublic {*}$args
    }

    method InitializePublic args {
        my variable config
        set optiondict [my meta get option]
        # Populate config() with defaults
        foreach {field info} $optiondict {
          if {[info exists config($field)]} continue
          if {[dict exists $optiondict $field]} {
            set config($field) [dict get $optiondict default]
           } else {
             set config($field) {}
           }
        }
        foreach {field value} $args {
          set key [string trimleft $key -]
          if {![dict exists $optiondict $key]} {
             error "Bad option: $key, valid: [lsort -dictionary [dict keys $optiondict]]"
          }
          set config($field) $value
        }
    }

    method configure args {
        my variable config
        set triggers {}
        set optiondict [my meta get option]
        foreach {key value} $args {
          set key [string trimleft $key -]
          if {![dict exists $optiondict $key]} {
             error "Bad option: $key, valid: [lsort -dictionary [dict keys $optiondict]]"
          }
        }
        foreach {key value} $args {
          set key [string trimleft $key -]
          if {$value != $config($key)} {
             set config($key) $value
             if {[dict exists $optiondict $field trigger]} {
               lappend triggers $field $value [dict get  $optiondict $field set-script]
             }
          }
        }
        foreach {field value script] $triggers {
           eval [string map [list %object% [self] %self% [self] %field% $field %value% $value] $script] 
        }
    }

    method cget field {
       set field [string trimleft $field -]
       if {![my meta exists option $field]} {
          error "Invalid option $field, Valid [info option property [self] list option]"
       }
       my variable config
       return $config($field)
    }
}

dkf - 2015-04-13 10:12:43

Thinking about this, I'm unhappy with an info subcommand being used to change the state. I know that info script does it, and that's pretty evil, but we don't need to do that elsewhere. Instead, properties should be editable or deletable via oo::define and oo::objdefine; that's how TclOO works for things that are considered to be “part of the definition”.

We also want an easier way to read a property inside a method. Perhaps a property method? (Name can be changed; I just had to pick something…)

    method foo {} {
        set value [my property bar]
        # Do stuff with it…
    }

That method should return the currently applicable value of the property, where that means following the inheritance hierarchy to determine the value, just as with normal method overriding (though there's no method chain in this case). The implementation might cache things for speed.

The name-space of properties is distinct from that of methods.

sdw - 2015-05-28 09:40:00

I have taken your suggestions to heart and simplified the concept a bit. In the new scheme, the "meta" method provide's an object's interface to several helper functions (and a global array) run from the oo::meta namespace.