Wednesday, September 23, 2009
A Professional Technical Conversation
Old Sk00l Unix Guru #1: Right.
Old Sk00l Unix Guru #2: Right.
Me: But I need to do it from a script, so I'm checking the exit code....
OSUG #1: Right.
OSUG #2: Right.
Me: And that works great on Linux. But on Solaris, it's 0 on both success and failure.
OSUG #1: Can't you just put it in backticks and grep the output?
Me: Well sure, I can. But it seems like such an old utility should have a way to return 'yes' or 'no'. What's the Old Sk00l UNIX Way to do this?
*all three characters pore over Solaris man page, which was last updated in 1992*
Me: I guess I'll do that. I just wanted to be sure that if I did the backtick and grep thing, someone isn't going to look at that later and say "what a n00b".
OSUG #1: You can write a comment that says "let me know if you have a better way".
OSUG #2: Or "to overcome braindead Solaris return code values".
Me: I guess leaving a comment about someone being braindead IS the Old Sk00l UNIX Way.
Sunday, August 30, 2009
Invention Idea #6
Many cans are unlabeled, but some have a name scrawled on them, or some tape, or a business card stuck under the tab. However, these solutions have a couple problems. First, they only provide identification, not security. Second, some of these are kind of time-consuming. The tape, for instance, can't take less than 60-90 precious seconds during which you could be reading some hilarious emails forwarded from the secretary.
Thus my invention, which I call "Club Soda". You slip it on, snap it shut and club it with a tiny key. It would be personalized with your name via a tag or engraving or something. Security and identification in under 10 seconds. MSRP $4.99.
Wednesday, September 10, 2008
New Control Structure Considered Useful
The problem is finding those 3-5 items. Choosing every possible combination of 5 would take too long. Choosing every combination of 3 is fast enough, but leaves a lot of extras. The simple solution is to first try all the combos of 3, then try all the combos of 4 on the remainder, then try all the combos of 5 on the remainder of that. The smaller and smaller pile makes the larger and larger choices feasible.
My boss, who is a competent practical programmer, suggests we have 3 procedures: One that does a 3 nested loop, one that does a 4, and one that does a 5. Like this (in Tcl):
set items {apple orange banana grape strawberry}
set count 5
for {set i 0} {$i < $count} {incr i} {
for {set j [expr $i + 1]} {$j < $count} {incr j} {
for {set k [expr $j + 1]} {$k < $count} {incr k} {
set string [lindex $items $i]
lappend string [lindex $items $j]
lappend string [lindex $items $k]
puts $string
}
}
}
That's just the 3 level loop because the other two look almost the same. The 4 and 5 level loops are identical except for having additional levels. As a programmer who values elegance over readability, the phrase "identical except for" is a red flag. Why have 3 separate procedures when all you are adjusting is a single parameter? What I need is a new control structure that is basically a for loop but lets me control how many nested fors there are.
Tcl makes it easy to create new control structures. Here's the control structure definition:
# Usage:
# indexcount - how many items are being chosen
# itemcount - how many items are being chosen from
# indexvar - variable to hold current combination of indexes
# body - code to execute for each combination
proc chooseloop {indexcount itemcount indexvar body} {
if {$indexcount > $itemcount} {
error "More indexes than items"
}
if {$indexcount == 0} { return }
set indexes {}
for {set i 0} {$i < $indexcount} {incr i} {
lappend indexes $i
}
set maxindexval [expr $itemcount - 1]
while {1} {
# make new body that sets indexvar first
set newbody "set $indexvar {$indexes}\n$body"
# do this iteration
uplevel 1 [list eval $newbody]
# find incrementable index
set found no
for {set i 0} {$i < $indexcount} {incr i} {
set index [lindex $indexes end-$i]
set thismax [expr $maxindexval - $i]
if {$index < $thismax} {
set found yes
break
}
}
if {!$found} { break }
# increment this index and set all following ones
set incrindex [expr ($indexcount - 1) - $i]
set precedingval [lindex $indexes $incrindex]
for {set j $incrindex} {$j < $indexcount} {incr j} {
lset indexes $j [expr $precedingval + 1]
set precedingval [lindex $indexes $j]
}
}
}
Now to get my 3 level loop, I can call like this:
chooseloop 3 5 indexes {
set str ""
foreach index $indexes {
append str "[lindex $items $index] "
}
puts $str
}In order to do 3, then 4, then 5, I can call like this:
for {set i 3} {$i < 6} {incr i} {
chooseloop $i 5 indexes {
set str ""
foreach index $indexes {
append str "[lindex $items $index] "
}
puts $str
}
puts "--"
}
The output of that last one is:
apple orange banana apple orange grape apple orange strawberry apple banana grape apple banana strawberry apple grape strawberry orange banana grape orange banana strawberry orange grape strawberry banana grape strawberry -- apple orange banana grape apple orange banana strawberry apple orange grape strawberry apple banana grape strawberry orange banana grape strawberry -- apple orange banana grape strawberry --
