Version 3 of Experiment with data manipulation and Snit

Updated 2008-10-24 10:02:33 by arjen

Arjen Markus (17 october 2008) Normally I do not use any (formal) OO system to create my Tcl programs or libraries. But yesterday I bit the bullet - here is a small experiment to make a Snit type to store and manipulate data. Nothing fancy and certainly not something actually useful, I just wanted to get a feel for Snit (or any other kind of Tcl OO system).

Some remarks (see also the code):

  • I do not know if it is (easily) possible to extend or modify a Snit object with new methods or fields. Such a facility would be handly : have a type that represents a mathematical function (with integration and root finding methods for instance) and different objects that each define their own function.
  • I have no idea how to make an expression like {$x > $y} behave correctly, that is: x is a local variable in the filter, but y is passed on from the caller. [apply] should do the trick I guess or [subst] ... Anyway I was too lazy to examine that.
  • Creating a new object within a method seems to misbehave a bit - or rather: not behave as I wanted. Probably should add some [namespace] wizardry.

NEM 18Oct08: I've changed the code below to fix some of these problems and use some more snit features. Hope the changes are useful!


# wrap_stat.tcl --
#     Small experiment with Snit and wrapping some of the
#     numerical functions in Tcllib, to get a more object-oriented
#     approach.
#
#     Some remarks:
#     - dataset is a new command inside the mySnitExperiment, but it
#       is not imported into the filter method.
#     - without the global namespace in the call to filter (main code),
#       the new object will reside in the mySnitExperiment namespace.
#     - because I was too lazy to try and do it the more elegant way,
#       the expression is not surrounded by braces, but explicitly
#       escapes the $ before x. (y gets substituted, x not).
#
#     Question:
#     Can I define new methods on the fly for a particular object or
#     redefine existing ones?
#

package require snit
package require math::statistics

namespace eval mySnitExperiment {
    namespace import ::math::statistics::*

# dataset --
#     Define a simple Snit type that contains data and can deal with
#     statistical operations on these data. Could be extended to
#     include plotting functionality.
#
    ::snit::type dataset {
	option -data   -default {} -configuremethod ChangeData

	variable mean {}
	variable cached 0
	
	constructor args { $self configurelist $args }
	
	method ChangeData {option value} {
	    set options($option) $value ;# commit change
	    set cached 0
	}
	
	method setdata {data} {
	    $self configure -data $data
	}

	method get {} {
	    return $options(-data)
	}
	
	method mean {} {
	    if { ! $cached } {
		set mean [::math::statistics::mean $options(-data)]
		set cached 1
	    }
	    return $mean
	}

	#
	# Filter creates a new object with data that conform to
	# some predicate, p.
	#
	method filter {name p} {
	    set newData {}
	    foreach x $options(-data) {
		if {[{*}$p $x]} { lappend newData $x }
	    }
	    return [$type create $name -data $newData]
	}
    }
}

# Separate construction of functions/predicates from application
proc func {params body args} {
    list ::apply [list $params [list expr $body]] {*}$args
}

# main --
#     Test this very basic data type
#
::mySnitExperiment::dataset create series1

series1 setdata {1 2 3 4 5 6}
puts "Data: [series1 get]"
puts "Mean: [series1 mean]"

set y 4
series1 filter ::series2 [func {y x} {$x > $y} $y]
puts "Filtered data: [series2 get]" 

AM I ran into a few difficulties with Snit or, rather, my understanding of it, and I posted them on comp.lang.tcl. The replies made me wonder about XOTcl - so, here is an Experiment with numerical methods and XOTcl.