Ruby vs. Python (vs. Perl) (vs. Lisp)

I’ve recently been playing with Ruby, and I think I’ve finally found a replacement for my various uses of Perl.  For a while now, I’ve been using one of two languages for my at-home programming: Common Lisp for the more complex or interesting tasks; and Perl for the simpler tasks, standalone programs, and one-line text processing.

I’ve long had a love/hate relationship with Perl.  On the one hand, its DWIM approach to things make it easy to do simple things, especially one-off text munging.  perl -pe '<stuff>' has long been my friend.  It also has CPAN going for it; many of my problems have been solved with a CPAN module and a little glue code.  On the other hand, Perl tends towards extreme ugliness, especially when the code starts to get complicated.  I’ve never liked the OO interface for Perl, for example; not only does it feel very obviously bolted on to an existing infrastructure, it didn’t even get the sharp, pointy edges sanded down when they did it.

Thus it was that I was impressed with Python when I first met it.  It felt like a language designed with OO from the bottom up.  (But it wasn’t; the addition of OO stuff had just been done in a much better way than Perl’s.)  It had nice data introspection.  It had functions as first-class objects (so they got the benefit of introspection, as well as the other benefits of first-classness).  I figured I could live with the whitespace-as-syntax wart.  As I got to know it more, Python started falling down in a few places.  For one thing, Guido van Rossum apparently doesn’t like functional programming.  Python has some functional programming constructs, like map and filter, but Guido keeps threatening to remove them.  There’s no good way to create anonymous functions, because Python’s lambda is only useful for relatively trivial purposes.  Python is also not terribly useful from the command line, largely because of the whitespace-as-syntax thing.  Again, it works for some trivial cases, but is not general purpose enough.

So it was that I resisted bothering with Ruby for a while.  “Oh,” I said, “It’s just another fad, like Python.” But I kept hearing good things about it, even apart from all the buzz that Ruby on Rails has generated.  So I finally resolved to poke at it a bit, and I’m pretty impressed.  It’s a much cleaner language than Perl, but it’s better at functional and command-line usage than Python.  It’s enough to make me want to switch to Ruby for all my non-Lisp needs.

There are some things that feel like they might bother me, though.  While Ruby not only supports anonymous functions but uses anonymous-function-like blocks all over the place, functions in Ruby are not first class objects, which means that you can’t quite sling them around as easily as data.  The use of special characters to determine variable scope (globals, class variables, instance variables, etc.) seems a bit weird to me, but at least it’s not as bad as Perl’s variable special characters.

Basically, Python has too much insistence on doing things its own particular, sometimes convoluted way.  Ruby stole all the useful things from Perl while otherwise maintaining a very clean language that doesn’t spit on my Lisp-influenced thinking.


Terminal Function Key Escape Codes

I recently had the pleasure of trying to figure out a friend’s terminal woes.  His function keys weren’t behaving properly.  It turns out that his terminal was sending escape codes that differed from the terminfo definition his terminal was using.  I set out to find what the correct solution was.  These are my results.  (Note that I use Debian GNU/Linux.  Some of this may be Debian-specific.)

Most terminal emulators these days emulate some superset of a DEC VT100.  (Not all of them emulate a VT100 exactly, though.  cf.  vttest.)  The VT100 didn’t have function keys in the sense that it didn’t have keys labeled F1, F2, F3, etc.  It did, however, have four keys over the numeric keypad labeled PF1 through PF4.  These keys are generally regarded as analogous to F1 through F4 on a modern keyboard.  They generated escape codes ^[OP through ^[OS.  The appropriate $TERM type for a VT100 is vt100.

One of the best well known terminal emulators around, xterm, actually emulates (or strives to emulate) a DEC VT220.  I’ll get to xterm in a bit, but the VT220 was a more advanced terminal than the VT100.  Among other things, it had twenty function keys, labeled F1 through F20.  The first five were strictly for local terminal functions; the host never saw any escape codes from them.  The remainder (F6 through F20) sent escape codes ^[[17~ to ^[[21~, ^[[23~ to ^[[26~, ^[[28~, ^[[29~, and ^[[31~ to ^[[34~.  The appropriate $TERM type for a VT220 is vt220.  (Note that, on my system, the vt220 $TERM type actually defines VT100 escape codes for F1 through F4.  There’s no definition for F5.)

This brings me to xterm.  xterm has a long history, and the function key definitions have changed over time.  The original xterm from the X Consortium (even before they became the Open Group) used escape codes based on the VT220, but extended to cover the range from F1 to F48.  F1 through F12 generated, respectively, codes ^[[11~ to ^[[15~, ^[[17~ to ^[[21~, ^[[23~, and ^[[24~.  Shift-F1 through Shift-F12 were used for F13 through F24, and generated codes from ^[[11;2~ to ^[[24;2~.  Similarly Ctrl-F1 through Ctrl-F12 were used for F25 through F36 and generated codes ^[[11;5~ to ^[[24;5~, and Ctrl-Shift-F1 through Ctrl-Shift-F12 were used for F37 through F48 and generated codes ^[[11;6~ to ^[[24;6~.  None of the base xterm $TERM types on my system correspond to this series of escape codes, though you can still get xterm to exhibit the old behavior by setting the OldXtermFKeys resource to ‘true’.

The current XFree86 xterm mixes VT100 and VT220.  Since the original VT220 didn’t have F1 through F5, the XFree86 xterm uses the escape sequences from the VT100’s PF1 through PF4 for F1 through F4 while retaining the VT220-based escape sequences from the X Consortium xterm for F5 through F12.  So the differences from the earlier xterms are: F1 through F4 generate escape codes ^[OP through ^[OS, F13 to F16 generate ^[O2P to ^[O2S, F25 to F28 generate ^[O5P to ^[O5S, and F37 to F40 generate ^[O6P to ^[O6S.  On my system, the $TERM types that have the appropriate function key definitions are xterm, xterm-debian, xterm-mono, and xterm-xfree86.

The GNOME project’s terminal emulator is gnome-terminal.  It generates the exact same escape codes as the XFree86 xterm and will work with the same $TERM settings.  Note, however, that some function keys are bound to gnome-terminal actions and will not be passed through to applications running in the terminal.  (For example, F1 calls up the GNOME help browser to view the gnome-terminal documentation.)

multi-gnome-terminal is based on gnome-terminal, but it implements multiple tabbed terminal sessions in a single window.  It also does the function keys a little differently, though it’s a bit more like the original VT220.  F1 through F12 behave exactly the same as the XFree86 xterm.  Shift-F1 through Shift-F10 function as F11 through F20 and generate escape codes from ^[[23~ to ^[[34~, just like the VT220.  Note that this means there are two ways to get F11 and F12. (Actually, there are three, since Shift-F11 and Shift-F12 are also equivalent to F11 and F12.)  On my system, the $TERM types with the appropriate function key definitions are xterm-color, xterm-r6, and xterm-vt220.  xterm can be made to behave like this by setting the SunKeyboard resource to ‘true’.  Note that, like gnome-terminal, multi-gnome-terminal binds some function keys for its own use and may not pass then through to the programs in the terminal.

rxvt is a very popular xterm replacement.  It uses the same escape sequences at the X11R6 xterm for F1 through F12.  Shift-F1 through Shift-F12 work similarly to multi-gnome-terminal; they add ten to the number on the key (so there are again two ways to get F11 and F12).  rxvt generates the same escape sequences as multi-gnome-terminal for F11 through F20, and uses ^[[23$ and ^[[24$ for F21 and F22, respectively.  The sequence continues with Ctrl-F1 through Ctrl-F12 generating ^[[11^ through ^[[24^ for F23 through F34 (no overlap with previous sequences), Ctrl-Shift-F1 through Ctrl-Shift-F10 generating ^[[23^ through ^[[34^ for F33 through F42 (two-key overlap), and Ctrl-Shift-F11 and Ctrl-Shift-F12 generating ^[[23@ and ^[[24@ for F43 and F44.  The base $TERM type for rxvt is rxvt, though it ships with several types for different circumstances, including rxvt-basic and rxvt-m.  It also comes with rxvt-unicode, but on my system that definition only lists function keys up to F20.

GNU screen is also a terminal emulator, though it expects to run within another terminal environment (as opposed to displaying text in a graphical environment like xterm or displaying text on physical hardware like an actual terminal).  As such, it translates many escape sequences from its containing terminal environment to the VT100-like environment it provides.  It will recognize and translate the sequences for F1 through F12.  For those, it will generate the same escape codes as the XFree86 xterm.  It does not recognize F13 and above; those escape codes will pass through unchanged to the programs running within screen.  (Note that the screen ‘bindkey’ command has a -k option that uses termcap capabilities to represent keys.  It understands k1 through FA, which correspond to F1 through F20.)  The $TERM type for screen is screen.

key VT100 VT220 X11R6 xterm XFree86 xterm rxvt MGT screen
F1 ^[OP ^[[11~ ^[OP ^[[11~ ^[OP ^[OP
F2 ^[OQ ^[[12~ ^[OQ ^[[12~ ^[OQ ^[OQ
F3 ^[OR ^[[13~ ^[OR ^[[13~ ^[OR ^[OR
F4 ^[OS ^[[14~ ^[OS ^[[14~ ^[OS ^[OS
F5 ^[[15~ ^[[15~ ^[[15~ ^[[15~ ^[[15~
F6 ^[[17~ ^[[17~ ^[[17~ ^[[17~ ^[[17~ ^[[17~
F7 ^[[18~ ^[[18~ ^[[18~ ^[[18~ ^[[18~ ^[[18~
F8 ^[[19~ ^[[19~ ^[[19~ ^[[19~ ^[[19~ ^[[19~
F9 ^[[20~ ^[[20~ ^[[20~ ^[[20~ ^[[20~ ^[[20~
F10 ^[[21~ ^[[21~ ^[[21~ ^[[21~ ^[[21~ ^[[21~
F11 ^[[23~ ^[[23~ ^[[23~ ^[[23~ ^[[23~ ^[[23~
F12 ^[[24~ ^[[24~ ^[[24~ ^[[24~ ^[[24~ ^[[24~
F13 ^[[25~ ^[[11;2~ ^[O2P ^[[25~ ^[[25~
F14 ^[[26~ ^[[12;2~ ^[O2Q ^[[26~ ^[[26~
F15 ^[[28~ ^[[13;2~ ^[O2R ^[[28~ ^[[28~
F16 ^[[29~ ^[[14;2~ ^[O2S ^[[29~ ^[[29~
F17 ^[[31~ ^[[15;2~ ^[[15;2~ ^[[31~ ^[[31~
F18 ^[[32~ ^[[17;2~ ^[[17;2~ ^[[32~ ^[[32~
F19 ^[[33~ ^[[18;2~ ^[[18;2~ ^[[33~ ^[[33~
F20 ^[[34~ ^[[19;2~ ^[[19;2~ ^[[34~ ^[[34~
F21 ^[[20;2~ ^[[20;2~ ^[[23$
F22 ^[[21;2~ ^[[21;2~ ^[[24$
F23 ^[[23;2~ ^[[23;2~ ^[[11^
F24 ^[[24;2~ ^[[24;2~ ^[[12^
F25 ^[[11;5~ ^[O5P ^[[13^
F26 ^[[12;5~ ^[O5Q ^[[14^
F27 ^[[13;5~ ^[O5R ^[[15^
F28 ^[[14;5~ ^[O5S ^[[17^
F29 ^[[15;5~ ^[[15;5~ ^[[18^
F30 ^[[17;5~ ^[[17;5~ ^[[19^
F31 ^[[18;5~ ^[[18;5~ ^[[20^
F32 ^[[19;5~ ^[[19;5~ ^[[21^
F33 ^[[20;5~ ^[[20;5~ ^[[23^
F34 ^[[21;5~ ^[[21;5~ ^[[24^
F35 ^[[23;5~ ^[[23;5~ ^[[25^
F36 ^[[24;5~ ^[[24;5~ ^[[26^
F37 ^[[11;6~ ^[O6P ^[[28^
F38 ^[[12;6~ ^[O6Q ^[[29^
F39 ^[[13;6~ ^[O6R ^[[31^
F40 ^[[14;6~ ^[O6S ^[[32^
F41 ^[[15;6~ ^[[15;6~ ^[[33^
F42 ^[[17;6~ ^[[17;6~ ^[[34^
F43 ^[[18;6~ ^[[18;6~ ^[[23@
F44 ^[[19;6~ ^[[19;6~ ^[[24@
F45 ^[[20;6~ ^[[20;6~
F46 ^[[21;6~ ^[[21;6~
F47 ^[[23;6~ ^[[23;6~
F48 ^[[24;6~ ^[[24;6~

The Greater Baltimore Bus Initiative

The MTA recently announced a Greater Baltimore Bus Initiative.  They are planning to restructure most of the bus routes in the Baltimore system, in what I believe is that first major overhaul the system has ever undergone.

On looking at the proposal for the first time, the initial impression I got was one of reduction.  Four lines will be added (the 9, 28, 40, and 41) while 18 will be discontinued (the 2, 7, 10, 27, 31, 36, 61, 65, 86, 91, 98 (Hampden Neighborhood Shuttle), 102, 103, 104, 105, 150, 160, M6, and M12).  (In most cases, each of the areas served by the discontinued lines will be served by a different line after the reorganization.)  The reduction has both good and bad aspects.  On the good side, it will simplify the routes significantly.  As I’ve written before, the current routes are somewhat baroque, with lots of branches and optional sections.  The new plan looks like it eliminates most of those, leading to simpler and more understandable routes, at the cost of convenience—many places will be farther from the buses than they are now, though the limit seems to be between four and eight city blocks.

On the other hand, there are several places where the MTA is simply cutting service completely, largely to the north and northeast of the city.  The 83 corridor will remain accessible, but that service will stop at Hunt Valley Mall.  Along the rest of the north and northeast portion of the current service area, service will stop at or barely outside the Beltway.  The 8 will no longer go to Stella Maris; the 15 will stop short of the Beltway, no longer going to Rutherford Business Park, Windsor Hills, Ingleside Avenue, and Forest Park Avenue; the 19 will no longer go to Cub Hill or Joppa Heights; the 23 will not go to Hawthorne and Wilson Point; the M10’s entire route north of Smith Road, which currently goes up to Greenspring Station, will be removed; and the M12’s service will be dropped completely, eliminating access outside the Beltway along Stevenson Road, Park Heights Avenue, and Greenspring Valley Road, the latter of which renders Villa Julie College inaccessible.  I know people who use some of those removed routes, and I have occasionally made use of some of them myself.  Losing them makes Baltimore’s public transit system much worse.

I’d say that the changes proposed are more bad than good.  The “good” parts are mostly that the bus routes have been simplified and bus frequency increased in heavily-used areas.  The simplification is not without its downside, though, since it leaves many people walking much farther to get to a bus.  The bad part is that large sections of service are simply being removed, causing serious problems for anyone who uses those sections.

The MTA is holding community meetings this week and public hearings next week to solicit feedback on the proposal.  (I have no idea what the difference between a “community meeting” and “public hearing” is.)  The public hearings all start at 4pm on weekdays, with the exception of the one that starts at noon on a weekday.  Needless to say, they’re not terribly convenient for people who work.  The community meetings, at least, all start at 6pm.

The Baltimore Sun has an article about the proposed changes.


Config Files

I’ve been quiet here for a while, mostly because I haven’t been doing too much that fits the focus of my blog.  One ongoing project, though, has been the process of putting much of my home directory into a subversion repository.  I’ll write more about that when I’m done, but as part of the process I’ve split out my public config files and synchronized them with my web-accessible config files.  There’s still stuff that I should comment for clarity, but now you, too, can see how I configure the programs I use.


Light Rail Double Tracking

According to a recent announcement, the southern portion of the Light Rail will open completely on December 5th.  No more shuttles, at least in that direction.

On the other hand, they’re closing the northern portion (everything north of North Avenue) on January 3rd.  And the shuttle bus system they have set up is confusing, to put it mildly.

From what I can tell, there will be three shuttle routes, designated ‘A’, ‘B’, and ‘C’.  ‘A’ shuttles will go to Falls Road.  ‘B’ shuttles will go to Timonium Fairgrounds and Warren Road.  ‘C’ shuttles will go to Lutherville, Timonium Fairgrounds, Gilroy Road, McCormick Road, Pepper Road, and Hunt Valley.  No shuttles will go to Timonium Business Park, Mount Washington, Cold Spring, or Woodberry.  Users of any of those latter stops are expected to use buses that run nearby.  (Light Rail riders often use the trains to avoid those buses.)  The Light-Rail-served terminus of the shuttle routes is not North Avenue (as one might expect), but the Cultural Center stop.

Confused yet?  There’s more.  The ‘C’ route is a general service route that will run roughly the same hours as the Light Rails does: 5am to midnight on Monday through Saturday and 10am to 8pm on Sunday.  The ‘A’ and ‘B’ routes are limited-time express routes: the ‘A’ will run from 6am to 10am and 2:30pm to 6:30pm; the ‘B’ will run from 6am to 9:30am and 2:30pm to 6:30pm.  Both express routes will only run on weekdays.

They don’t say what the more specific time constraints are.  (Does “to 10am” mean that the last bus will start its last run at 10:00, or that the last bus will arrive at its final destination at 10:00?)  They don’t say how often the buses will be running.  (Probably because there’s either no set schedule or because the schedule won’t be enforced at all; either would fit the behavior of the southward-running buses this year.)

Neither the MTA’s website nor the Double Track Project’s website has any mention yet of these changes.