Wednesday, March 10, 2010

Don't Give Variables Negative Names

Sometimes programmers get caught up in the absence of something. Don't let that leak over into the name of a variable or data member:
bool Job::acceptable(const JobCandidate &applicant) const
{
  bool noFelonyConvictions = findFelonyConvictions(applicant);
  return noFelonyConvictions && qualified(applicant);
}
The noFelonyConvictions variable documents the code in a readable way, but it gets silly if the code ever changes so that you have to initialize it, or if someone ever wants to know if there are felony convictions. Things become less readable:
  bool noFelonyConvictions = true;
  if (applicant.findRecords(FELONY)) {
    noFelonyConvictions = false;
  }
  return applicant.qualified(!noFelonyConvictions);
It all makes more sense if you name the variable felonyConvictions, which initializes naturally enough to false, can be set to true if one is found, and can be negated to show absence. Also, if you later become interested in the number of convictions, there will be fewer code changes if the variable changes from a bool to an int.

Whenever you notice yourself putting a "no" into a variable name, get rid of it.

Thursday, February 4, 2010

How to Undeclare a bash Function

It took me a few minutes to figure this out, so I thought I might as well pass it along.

If you've declared a bash function, and then decided you don't really want it, either because you went ahead and implemented it as a script somewhere, or you gave it a bad name or something, you undeclare it like this:

  $ unset -f myfunc

Monday, February 1, 2010

Nice Code Structure

Here's a brilliant one I just ran across at work (variables changed to protect the... to protect someone):

  for (i = 0; i < lim; i++) {
    if (someCondition(n[i])) {
      warn("you can't do that");
      continue;
    }
    switch (n[i].type()) {
      default:
        nn = 0;
        warn("we're ignoring this");
        break;
    }
    orig->doSomethingWith(nn);
    delete nn;
  }

How do you like that switch with only a default branch? Pretty cool, huh? Almost is nice is the delete that only ever sees a NULL. Then when I realized doSomethingWith() is a no-op if it gets a NULL, I felt even luckier.

Look, if you're making such a big change to some code that you take out all the branches of a switch, isn't it worth a couple minutes to clean this up and show what is really happening? After all, the code really does this:

  for (i = 0; i < lim; i++) {
    if (someCondition(n[i])) {
      warn("you can't do that");
    }
    else {
      warn("we're ignoring this");
    }
  }
It probably makes sense to only give the second warning, since who cares if you can't do it, when really it would only be ignored anyway. And at that point you might wonder why you need to give the same warning lim times.

Ugly code kills. Kill ugly code.

Friday, December 11, 2009

Emacs vs. Nicer dirs

In the last post I described a nicer version of the shell dirs command that labels each directory with its position, so that you can pushd directly to the one you want.

One problem with it is that emacs shell-mode generally uses dirs to track which directory you're in. And you do want it to track directories for you. Our nicer version of dirs produces output that isn't readable to emacs.

Of course the natural solution is:

(setq shell-dirstack-query "command dirs")

to pick up the shell's builtin dirs. Sadly, you can't just throw that line into your .emacs file, because shell-mode sets shell-dirstack-query every time you start a new shell. It sets it unconditionally and globally, which is a ridiculous design flaw, but that's how it goes. There is no hook that runs after it sets the value, either.

So you're stuck with needing a workaround:
  1. Name your command something other than dirs .
  2. Use a flag on your new dirs to get the nicer behavior.
  3. Write your own emacs function to start a shell:

(defun engisneering-shell ()
(interactive)
(shell)
(setq shell-dirstack-query "command dirs"))

Tuesday, November 17, 2009

Nicer pushd, popd, and dirs

Writing up the safer, friendlier bash which command reminded me of another wrapper function that's handy to have. If you use pushd/popd to keep a stack of directories in your shell window, sometimes you want to switch to a directory far down the stack. If you want to switch to the third directory down, you do pushd +3.

The problem is, you have to count along the list of directories, since dirs, pushd, and popd all just spit out a one-line list of the stack, like this:

$ dirs
/usr/local/share ~ ~/work ~/tmp
Not an impossible task, but it can get annoying if you have some long paths in there, especially once your stack gets past two or three deep. Why not have dirs print one directory per line, and label them with their depths? To do so, add this function to your .bashrc file:

function dirs {
ds=(`command dirs`)
i=0
while [ "${ds[$i]}" != "" ]; do
echo $i: ${ds[$i]};
i=$((i+1));
done
}
Now you get more readable output:

$ dirs
0: /usr/local/share
1: ~
2: ~/work
3: ~/tmp
If you want to remove ~/work from the stack, just do popd +2.

Since pushd and popd also print the directory stack, let's add the same style of output to them:

function pushd {
if command pushd $@ > /dev/null; then
dirs
fi
}

function popd {
if command popd $@ > /dev/null; then
dirs
fi
}
One final note. In case some wacky systemwide file has aliased these commands to something else, add the following unaliasing code to the top of your .bashrc:

for func in dirs pushd popd; do
if alias $func > /dev/null 2>&1 ; then unalias $func; fi
done
Otherwise, your functions will be hidden (aliases take precedence).

PS: emacs shell-mode has a conflict with this dirs: here's how to fix it.

Monday, November 2, 2009

Keep from Killing Emacs Shell Buffers

If you're someone who lives in emacs like I do, then you probably rely on shell buffers (M-x shell) to interact with the operating system. That way you can search through output and edit history commands in a natural way that a mere terminal doesn't allow.

But occasionally I've been left kicking the wall after accidentally killing a shell buffer that had lots of work in it that I still needed. It really hurts when you accidentally kill a buffer where you're waiting for a long-running process to finish. To prevent industrial accidents like that, add a guard to kill-buffer-hook in your .emacs file:


(add-hook 'kill-buffer-hook
'(lambda()
(and
(string= "Shell" mode-name)
(or
(yes-or-no-p
(format "Kill buffer `%s'? " (buffer-name)))
(error "Aborted")))))


If you really do want to kill the shell buffer, type "yes", and you're done. But it will save you some grief if you just hit C-x k in the wrong buffer.

What's more common for me is that my eyes are on a file that I want to refresh or replace with C-x C-v (find-alternate-file), but the cursor is in a shell buffer. In that case, emacs will indeed load the alternate file, and you'll be asked "Kill buffer ` **lose**'?" Say no, then you'll have C-x b to " **lose**" (note the leading space), and rename the shell buffer to "*shell*" or whatever you had previously named it.

Monday, October 26, 2009

Bash vs. Which

The Unix which command is useful for searching your $PATH to find which version of an executable is going to run. But did you know that it doesn't always tell you the truth? For instance, it doesn't tell you when the command you're asking about is hidden by a shell builtin (or function, keyword, or alias):


$ which echo
/usr/bin/echo


which found /usr/bin/echo on your path, but echo is a shell builtin (at least in bash), so that's what will get run, not the one on the path. The GNU man page for which presents workarounds that will pick up functions and aliases, but shell builtins still slip through the cracks. The situation is even weirder on Solaris, where which is a csh shell-script, that sources your .cshrc file as part of its operation -- very strange if your shell is bash.

Clearly, which is not to be trusted. The easiest workaround, if you use bash, is the type builtin:


$ type -a echo
echo is a shell builtin
echo is /bin/echo


A slightly nicer workaround is to make a bash function for which, that uses type to do the right thing. I also like which to do an ls -l where applicable. Here's what I have in my .bashrc:


if alias which > /dev/null 2>&1; then unalias which; fi

function which {
hash -r
t=`type -t $@`

if [ -z "${t%%file*}" ]; then
for p in `type -p $@`; do
ls -l ${p};
done
else
type $@;
fi
}


Now which gives you much more information:


$ which -a wish
lrwxrwxrwx 1 root root 13 Dec 23 2008 /usr/local/bin/wish -> /usr/bin/wish*
lrwxrwxrwx 1 root root 7 Jan 8 2007 /usr/bin/wish -> wish8.3*


The unalias protects you in case some systemwide .bashrc or .profile aliases which in some way (unlikely, but good hygiene anyway). The call to hash clears the hashed function list, so that any changes to your PATH are reflected. The reason for the if statement in the function, is that we certainly want to report builtins, functions, etc., but if there are none, we can use type -p to make it easier to pass the filenames to ls -l. If there are builtins or such, we just punt and give the unaltered type output.

You can pass -a to this which if you want to see all the matches for the command, in order of precedence.

Note that this has to be a function, not a script, because running the script will source your .bashrc, which might change the PATH (all PATH changes should be in .profile, but sometimes people do it in .bashrc).