Posts Tagged ‘tcl’

Working with collections

Monday, September 25th, 2006

Steve Yegge wrote about the expressiveness of Ruby as compared to Java. He used this simple problem as an example:

How about if we write a program that will print out all the words in the dictionary starting with the letter ‘Q’ (case-insensitive), grouped by increasing length, and sorted alphabetically within each group.

The Ruby version was about 12 lines of code and Java version about 43. Of course, the point of the exercise wasn’t simply the difference in LOCs, but in the overall simplicity of dealing with collections of data. Still, I wanted to see how Tcl would deal with the same problem. Here’s the simplest version I could come up with:

 set f [open /usr/share/dict/words r] set words [read -nonewline $f] close $f  set qwords [lsearch -all -inline [split $words \n] {[Qq]*}]  proc compare_length {a b} {     if { [string length $a] <= [string length $b] } {         return -1     } else {         return 1     } }  set sorted_qwords [lsort -command compare_length [lsort $qwords]]  set max -1 foreach qword $sorted_qwords {     if { [string length $qword] > $max } {         set max [string length $qword]         puts "Words of length $max:"     }     puts "  $qword" } 

About 19 lines and pretty simple to write and read. Can this be improved?

Automated Testing Rules

Tuesday, May 16th, 2006

Automated testing is a good thing. For my running log application, I have a proc that creates a new log for a user, called rl::runner::new. If you happen to call it for a user who already has a log, it returns the already created log. When I created the proc way back when, I also created an automated test to make sure that creation worked and that redundant calls returned the orignal log.

Over time, I added some code to make sure that users are given proper permissions on their log. Anytime you make a change, you should run your tests, but of course, I didn’t :-) Well, today I did and my test now failed.

Here is the relevant (edited) code:

 set runner_id [db_nextval acs_object_id_seq] set ret_val [db_exec_plsql new_runner {}]  permission::grant -party_id $user_id -object_id $runner_id -privilege admin permission::grant -party_id $user_id -object_id $runner_id -privilege write 

The error was happening in permission::grant. It was complaining that $runner_id wasn’t a valid acs_object. What’s going on? It looks like it should work. The problem is that I should be granting the permission on ret_val, not on runner_id. (Probably a bad choice of variable names). The first time a log is created, db_exec_plsql returns a value which happens to be the same as runner_id. The second time it’s called, it returns a value which is different and permission::grant fails.

I would never have caught this error until I tried to call rl::runner::new the second time on the same user. Which would make it one of those very difficult to track bugs. Automated testing saved me a lot of annoying debugging.

That said, I wish OpenACS’s testing facilities were better. I worked on a couple other bugs today and I’m trying really hard to write tests to expose bugs before fixing them, but it’s really a strain. Especially when you need to do a combination of black box and white box testing. I’d like to make testing easier in OpenACS, but I’m not sure if I have the brainpower :-)

New Features coming in Tcl 8.5

Sunday, May 14th, 2006

I was looking at the Tcl 8.4 man page for ’split’ and saw this example code:

    ## Split into fields on colons    set fields [split $rec ":"]     ## Assign fields to variables and print some out...    lassign $fields \          userName password uid grp longName homeDir shell 

It shows how to split a string using ‘:’ as the delimiter. The interesting part is the ‘lassign’ statement. I’d never seen that before. I’ve always done something annoying like this:

    set fields [split $rec ":"]     set userName [lindex $fields 0]    set password [lindex $fields 1]    set uid [lindex $fields 2]    set grp [lindex $fields 3]    set longName [lindex $fields 4]    set homeDir [lindex $fields 5]    set shell [lindex $fields 6] 

How could I have overlooked ‘lassign’ all these years? After berating my idiocy for a few minutes, I tried ‘lassign’ out and Tcl replied ‘invalid command name’ . Turns out I’m not as stupid as I thought. :-) ‘lassign’ is new in Tcl 8.5 (but seems to have snuck in the backdoor of the 8.4 docs). I decided to see what else was coming in 8.5.

  • Dictionaries. These are associative arrays which reportedly are better than Tcl arrays, but I’m not sure why.
  • ** as an exponentiation operator
  • Instead of doing: if {[lsearch -exact $list $item] != -1}, the new ‘in’ operator lets you do if {$item in $list}. There’s also a ‘ni’ operator for ‘not in’.
  • Plenty of other stuff, none of which really caught my eye.

Tcl 8.5 is still alpha, so I’m sticking with 8.4 (and my annoying code) for the moment.

Hit The Wall (a running log)

Friday, April 21st, 2006

I built a web application to keep track of my running a couple years ago. I really began using it in earnest during my training for the New York Marathon last year. I’ve been meaning to make it available for others to use for a long time, but it always seemed like there was a little more work I needed to do on it. While working on it the other day, I noticed the original timestamp on one of the source files: September 21, 2003 Yikes! That’s 2 and a half years ago. Enough is enough — it’s time to let this baby free…

Hit The Wall is officially version 0.2 and available for free use by anyone who wants to keep track of their running. Feel free to look through my real log (read-only) or demorunner’s fake log (read-write) to try it out.

I’ve created a separate blog and a forum where I’ll post updates and respond to questions or comments.

Tcl, a short introduction

Thursday, March 9th, 2006

The scripting language used in most of OpenACS is Tcl. It doesn’t receive a lot of press. When people talk about scripting languages, they mean Perl or Python (and now Ruby). Tcl is not considered in the same category, but it should be. I’m not smart enough to explain why, but Salvatore Sanfilippo is and has written a gentle introduction to both the basic and powerful features of Tcl.