Wandering Thoughts archives

2005-11-30

An advantage to introspection and an interactive interpreter

I spent part of today writing a very simple network server in Perl. While most of my problems were due to my ignorance, the experience did give me a new appreciation for introspection and interactive interpreters.

The problem is that without introspection, things are opaque when something goes wrong. What do you have? Certainly not what you expected, but it's hard to tell much more than that. With introspection, you can find out type information, maybe a printable representation of the thing (this gives you some idea if you're on the right track), and perhaps even lets you find out some of what you can do with it.

Perl has some introspection support, but it also has a tendency to make a lot of the socket things I was interested in into typeless, opaque strings. It was startling how different working in such a 'bare' environment felt.

An interactive interpreter taps introspection's power, because you can experiment without having to edit and restart programs. You grab the thing you're having trouble with, then fiddle around with it and see what happens; this gives you rapid feedback, so you can quickly refine and focus your fiddling and work out how to do what you want.

(Exceptions are also an advantage in this sort of exploration because they let you know immediately when you've done something wrong, and often give you specific details about what you screwed up.)

To answer the question 'why Perl (instead of, say, Python)': Solaris 9 has Perl has part of a relatively standard install, but not Python et al. And I would rather write simple networking programs in Perl than C.

Sidebar: introspection et al in Perl

Perl does have some addons for introspective and interactive interpreter features. The ones I've found and want to save for later reference:

  • Perl's debugger ('perl -d') can be used the introspect a number of things in a program, although not with straightforward syntax. You can sort of use it as an interactive 'interpreter' with something like 'perl -de 42', which starts Perl on a simple do-nothing expression. (Mentioned here.)
  • psh, a simple interactive interpreter.
  • This rather more complicated Perl shell thing, which seems to be at least partly an attempt at a Unix style shell as well as an interactive perl environment.

I'm honestly surprised that psh or something like it isn't shipped with Perl by now. (It's not as if psh is very big or complicated.)

(Additional suggestions welcome.)

AnIntrospectionAdvantage written at 01:55:34; Add Comment

2005-11-29

A little gotcha in shell scripts

I have a script called 'nsaddrs', which lists the IP addresses of the nameservers for a given domain. It is basically:

addr `dig +short ns $1`

addr is one of my utility programs; it does IP address lookups for hostnames. Normally you give it hostnames on the command line, but for bulk lookups you can give it no arguments and it will read hostnames from standard input, one per line.

Then one day I used nsaddr on a domain that didn't exist and it 'hung'. After I stopped thinking that the nameservers were being really slow, I worked out the bug: when dig couldn't find any nameservers it didn't produce any output, and when that happened addr had no arguments, so it was trying to read hostnames from the terminal. (Naturally I wasn't supplying any.)

The solution is simple:

addr `dig +short ns $1` </dev/null

There's a fair number of Unix utilities that have this 'process arguments or standard input' behavior. Any time a shell script uses one of these program in this pattern, this little gotcha can be waiting in the wings.

AShellScriptGotcha written at 01:42:56; Add Comment

2005-11-23

A quick outline of Firefox extension structure

Yesterday I mentioned Firefox extensions in passing. Let's fill in the blanks.

Firefox extensions come as .xpi files, which are just yet another extension for ZIP archives. Unpacked, extensions live in their own directory in the extensions/ subdirectory in your Firefox profile directory. Firefox profile directories live under ~/.mozilla/firefox; the default profile is in <something>.default. (Firefox randomizes the name of the profile directory, I believe due to security concerns.)

The actual name of an extension's directory is mostly opaque; it is '{<ID>}', where <ID> bit is the UUID (nee GUID) for the extension. The easiest way to find out which is which is to skim the install.rdf file from each directory, looking for the em:description or em:name attributes.

(Alternately, you can look at 'ls -lt' and remember the order in which you installed extensions.)

Most extensions stick their .jar files in their own chrome/ subdirectory. Using .jar files is not mandatory, and some extensions ship with their files fully exploded. (This is simpler on the developer but takes more space.)

The em:maxVersion field in appropriate bits of install.rdf control what the highest version of Firefox the extension can be installed on. However, if this matters to you you probably want to install the Nightly Tester Tools which let you just override it when necessary.

(For more information on the code structure of extensions and how they work, see the knowledge base.)

FirefoxExtensionsQuickIntro written at 00:32:51; Add Comment

2005-11-22

How to fiddle with Firefox .jar files relatively easily

A lot of Firefox's code is actually written in various interpreted languages, especially JavaScript, and Firefox extensions are pretty much all interpreted. This means that you can do a lot of Firefox and extension hacking without ever having to rebuild from source; you just zap the interpreted files in place in your installed copy.

Firefox doesn't leave all of these files sitting around for you to edit; it bundles them up in various .jar files (pretty much all in the chrome/ subdirectory). Fortunately .jar files are just ZIP archives. The easy way to modify files in them is:

  1. unzip the relevant jarfile somewhere (I usually use chrome/ itself, but I live dangerously)
  2. edit the unpacked files to taste
  3. run 'zip -f .../<whatever>.jar' in the root of where you unpacked the jarfile to 'freshen' it with your changes
  4. restart Firefox to test things.

(There are recipes for running Firefox from unpacked versions of the .jar files, but they require some black magic.)

(Figuring out which is the relevant jarfile (and the relevant source files) is beyond the scope of this entry; I suggest unpacking jarfiles and poking around. Also, see the Mozilla knowledge base at http://kb.mozillazine.org/.)

FiddlingFirefoxFiles written at 02:27:23; Add Comment

2005-11-21

Why I don't write 'if (NULL == foo)' in C code

One of the infamous trivial bugs in C code is accidentally writing '=' instead of '==' in conditional expressions; you get assignment instead of equality checking. One common piece of advice for avoiding this is to reverse the order of the check, putting the constant first. This way, if you accidentally write 'NULL = foo' instead of the == version, you'll get a compile time error.

I can't stand to write this version, because it looks wrong to me. I recently figured out why it looks so wrong: because it doesn't match my mental narrative of the code.

I write code by thinking 'if foo is NULL ...' and typing 'if (foo == NULL)', a pretty direct mapping. Similarly, if I am reading code I scan the 'if (..)' and go to the narrative version. When I try to reverse the condition the narrative comes to a jarring stall; I am thinking 'if foo is NULL' but writing something that looks like 'if NULL is foo'.

For me, the benefits of reversed conditionals just aren't worth putting up with code that looks wrong but isn't. (We already know that ugly code is confusing code.)

ACIdiomIAvoid written at 00:50:18; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.