Wednesday, October 22, 2008

Gödel, Escher, Bach

I'm a Yegge fan-boy, and his most recent post mentioned Gödel, Escher, Bach - the Pulitzer Prize-winning book by Douglas Hofstadter. Which got me to thinking...

A couple of programmers/bloggers I respect have the book on their must-have lists: Joel, Stevey. And most programming bloggers refer to it reverently.

I tried to read the book shortly after graduating college. I didn't finish it, because it was incredibly boring and repetitive and boring ... and repetitive. Turns out many don't finish the book, no surprise to me.

I'll repeat myself (in the spirit of GEB I should probably recurse), GEB was a complete snoozer. It reminded me much of Ayn Rand's Atlas Shrugged - another snoozer. There's only so much repetition I can stand.

I'm sure I missed all the puzzles and word-play - I certainly didn't get to the end where Hofstadter's characters discuss books that end before the final page (a joke that took 700 pages to set up).

Perhaps the book provides a path to enlightenment to people who are not familiar with recursion, self-reference, and the incompleteness theorem. Or, maybe there is enough wordplay and "charming" dialog to get you to wade through all 800 pages (there is that one nearly at the end).

I'd have been happier if the book were condensed to 150 pages.

Friday, October 10, 2008

Emacs Tip #26: CUA mode (specifically rectangle editing)

I'd heard of CUA mode, but generally dismiss it because I don't want the "windows" bindings for cut/copy/paste/undo. But when I saw this video of CUA's rectangle support, I knew this was the way to edit rectangles.


Emacs Column Editing from Mark Mansour on Vimeo.

To activate in emacs 22.1 - with minimal intrusion (I don't like transient mark mode):
(setq cua-enable-cua-keys nil)
(setq cua-highlight-region-shift-only t) ;; no transient mark mode
(setq cua-toggle-set-mark nil) ;; original set-mark behavior, i.e. no transient-mark-mode
(cua-mode)


The *info* page doesn't have the rectangle bindings (as far as I can see), so here is the documentation from the code:


;; CUA rectangle support
;; ---------------------
;; Emacs' normal rectangle support is based on interpreting the region
;; between the mark and point as a "virtual rectangle", and using a
;; completely separate set of "rectangle commands" [C-x r ...] on the
;; region to copy, kill, fill a.s.o. the virtual rectangle.
;;
;; cua-mode's superior rectangle support uses a true visual
;; representation of the selected rectangle, i.e. it highlights the
;; actual part of the buffer that is currently selected as part of the
;; rectangle. Unlike emacs' traditional rectangle commands, the
;; selected rectangle always as straight left and right edges, even
;; when those are in the middle of a TAB character or beyond the end
;; of the current line. And it does this without actually modifying
;; the buffer contents (it uses display overlays to visualize the
;; virtual dimensions of the rectangle).
;;
;; This means that cua-mode's rectangles are not limited to the actual
;; contents of the buffer, so if the cursor is currently at the end of a
;; short line, you can still extend the rectangle to include more columns
;; of longer lines in the same rectangle. And you can also have the
;; left edge of a rectangle start in the middle of a TAB character.
;; Sounds strange? Try it!
;;
;; To start a rectangle, use [C-return] and extend it using the normal
;; movement keys (up, down, left, right, home, end, C-home,
;; C-end). Once the rectangle has the desired size, you can cut or
;; copy it using C-x and C-c (or C-w and M-w), and you can
;; subsequently insert it - as a rectangle - using C-v (or C-y). So
;; the only new command you need to know to work with cua-mode
;; rectangles is C-return!
;;
;; Normally, when you paste a rectangle using C-v (C-y), each line of
;; the rectangle is inserted into the existing lines in the buffer.
;; If overwrite-mode is active when you paste a rectangle, it is
;; inserted as normal (multi-line) text.
;;
;; If you prefer the traditional rectangle marking (i.e. don't want
;; straight edges), [M-p] toggles this for the current rectangle,
;; or you can customize cua-virtual-rectangle-edges.

;; And there's more: If you want to extend or reduce the size of the
;; rectangle in one of the other corners of the rectangle, just use
;; [return] to move the cursor to the "next" corner. Or you can use
;; the [M-up], [M-down], [M-left], and [M-right] keys to move the
;; entire rectangle overlay (but not the contents) in the given
;; direction.
;;
;; [C-return] cancels the rectangle
;; [C-space] activates the region bounded by the rectangle

;; If you type a normal (self-inserting) character when the rectangle is
;; active, the character is inserted on the "current side" of every line
;; of the rectangle. The "current side" is the side on which the cursor
;; is currently located. If the rectangle is only 1 column wide,
;; insertion will be performed to the left when the cursor is at the
;; bottom of the rectangle. So, for example, to comment out an entire
;; paragraph like this one, just place the cursor on the first character
;; of the first line, and enter the following:
;; C-return M-} ; ; C-return

;; cua-mode's rectangle support also includes all the normal rectangle
;; functions with easy access:
;;
;; [M-a] aligns all words at the left edge of the rectangle
;; [M-b] fills the rectangle with blanks (tabs and spaces)
;; [M-c] closes the rectangle by removing all blanks at the left edge
;; of the rectangle
;; [M-f] fills the rectangle with a single character (prompt)
;; [M-i] increases the first number found on each line of the rectangle
;; by the amount given by the numeric prefix argument (default 1)
;; It recognizes 0x... as hexadecimal numbers
;; [M-k] kills the rectangle as normal multi-line text (for paste)
;; [M-l] downcases the rectangle
;; [M-m] copies the rectangle as normal multi-line text (for paste)
;; [M-n] fills each line of the rectangle with increasing numbers using
;; a supplied format string (prompt)
;; [M-o] opens the rectangle by moving the highlighted text to the
;; right of the rectangle and filling the rectangle with blanks.
;; [M-p] toggles virtual straight rectangle edges
;; [M-P] inserts tabs and spaces (padding) to make real straight edges
;; [M-q] performs text filling on the rectangle
;; [M-r] replaces REGEXP (prompt) by STRING (prompt) in rectangle
;; [M-R] reverse the lines in the rectangle
;; [M-s] fills each line of the rectangle with the same STRING (prompt)
;; [M-t] performs text fill of the rectangle with TEXT (prompt)
;; [M-u] upcases the rectangle
;; [M-|] runs shell command on rectangle
;; [M-'] restricts rectangle to lines with CHAR (prompt) at left column
;; [M-/] restricts rectangle to lines matching REGEXP (prompt)
;; [C-?] Shows a brief list of the above commands.

;; [M-C-up] and [M-C-down] scrolls the lines INSIDE the rectangle up
;; and down; lines scrolled outside the top or bottom of the rectangle
;; are lost, but can be recovered using [C-z].

Wednesday, September 3, 2008

The Web Interface Is Morphing Into Emacs

A while back, Steve Yegge wrote a post on Emacs and its future. My executive summary of his post is that Emacs needs to compete or die - and the competition is the browser.

This got a little thread started on the Emacs development list, but not much activity. If Steve's line of reasoning is correct, then I surmise Emacs is dead b/c the Emacs development team is not at all interested in competing with the browser. Heck, they recently had a discussion on moving from CVS to a modern (distributed) version control system - and while there appears to be a tentative decision to move to Bazaar for version control, main development is still on CVS.

I personally think Emacs is a niche product. Like Unix, it has a dedicated fan base and will be around for the foreseeable future. But, it is never going to grow a large base of end-users. It has got a lot of ... baggagehistory that turns some people off: GPL, RMS, lisp, (lack of) speed, text-based, carpal tunnel, etc.

I love Emacs and do most everything inside Emacs, but it is not and probably will never be hip, exciting, new, or perceived as leading edge technology.

What was my point? Oh, right, Ubiquity was recently announced at Mozilla Labs.

I watched the 6 minute video demo. And my first impression? It is Emacs, only instead of M-x you use C-SPC. Soon, people will tire of typing things out and come up with shortcuts based on various key combinations, and it'll turn into Emacs.

Of course, if Ubiquity does that, it'll be cool/hip, and people won't complain about the key-bindings.

It's just like XML over Lisp. The reaction to Lisp is, "OMG! Parentheses! Run!" On the other hand, XML (with twice the number of parenthesis</>) is cool/hip and folks have flocked to it.

Steve was right about the competition, the browser has fired the first salvo, and it looks a lot like Emacs.

Mozilla Labs » Introducing Ubiquity

Tuesday, August 19, 2008

Emacs Tip #25: Shell Dirtrack By Prompt

Note: I've since been notified of this problem already being solved by a package provided with Emacs. I looked at it and prefer the implementation in this post, only because it modifies the prompt so I don't have to see the full path in my prompt.

I'd been butting my head against this issue for a while now, but wasn't quite annoyed enough to come up with a solution. Luckily for me (and you), ccthomas wrote this little snippet which parses your shell prompt to determine the current directory.

Other than having to modify your shell prompt (no big deal), it's super clean and easy.

I modified the code slightly because I didn't see the need/purpose for/of the "%300<.<" in the prompt. So here' s my slightly modified version:


(add-hook 'shell-mode-hook
#'(lambda ()
(shell-dirtrack-mode nil)
(add-hook 'comint-preoutput-filter-functions
'shell-sync-dir-with-prompt nil t)))

(defun shell-sync-dir-with-prompt (string)
"A preoutput filter function (see `comint-preoutput-filter-functions')
which sets the shell buffer's path to the path embedded in a prompt string.
This is a more reliable way of keeping the shell buffer's path in sync
with the shell, without trying to pattern match against all
potential directory-changing commands, ala `shell-dirtrack-mode'.

In order to work, your shell must be configured to embed its current
working directory into the prompt. Here is an example .zshrc
snippet which turns this behavior on when running as an inferior Emacs shell:

if [ $EMACS ]; then
prompt='|Pr0mPT|%~|[%n@%m]%~%# '
fi

The part that Emacs cares about is the '|Pr0mPT|%~|'
Everything past that can be tailored to your liking.
"
(if (string-match "|Pr0mPT|\\([^|]*\\)|" string)
(let ((cwd (match-string 1 string)))
(setq default-directory
(if (string-equal "/" (substring cwd -1))
cwd
(setq cwd (concat cwd "/"))))
(replace-match "" t t string 0))
string))


The original can be found on the Emacs Wiki: Shell Dirtrack By Prompt

Wednesday, July 30, 2008

Forcing Abstraction

I just read the post: Rail Spikes: Functional programming and looping by Jon. It's a nice post, and I completely agree - you should never write for/while/do-while loops.

My gripe here is that this post has to exist at all. Everyone should know this, it is fundamental to have collections and operate on the collection - not using indices into collections1. IMO, this should be taught from day 1 in programming courses. Kudos to Ruby for getting the syntax clean - the left to right parsing is easier on (English reading) programmers than Lisp's inside-out parsing.

It seems to me that "abstraction" is generally applied to only classes people write, and not much thought is given to the lower-level usages. In this case: looping constructs.

I find it interesting that many people won't move away from for/while/do-while loops. In my previous job, people actively resisted such efforts. I remember introducing BOOST_FOREACH into our C++ development (a poor replacement for map, but a step in the right direction), and I had to pull teeth to get folks to use it. And, as awkward as the STL algorithms may be to use, they're still easier than rolling your own loop to remove elements.

I think Jon has taken a (permanent) step up the abstraction layer, he's moved away from thinking about the mechanics of iteration to focusing on what he wants to get done. Isn't that what we're taught in our first class on abstraction?

The main reasons people seem to give for not taking the step Jon has are:

  1. language doesn't support it (Java/C++/C/whatever)
  2. need for speed
  3. for loops are easy

Language. The first is legitimate, and I don't see an easy way around this. I find it sad when languages do not allow this, but my whining doesn't make the problem go away. Let's move on.

Speed. Funny how most everyone thinks their code just needs to be fast and they just know the code they're writing is fast. We should all trust Knuth when he said "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." If you really think you're smarter than Knuth, there's nothing I can say that will ever help you.

Easy. The third point, in my opinion, boils down to short-sightedness. People can be too narrow-minded (lazy) to want to learn something new. They might not see the fact they could remove an entire class of bugs from their code, forever. Folks don't realize the visual/mental clutter for loops add to their code. And, most importantly, for loops focus on the wrong thing (the indices, as opposed to the transformation) - see abstraction.

On a related abstraction tangent, a colleague of mine at Intel started writing a geometric template library for C++. One of the guiding ideas (not novel, but perhaps pushed to the extreme) was to remove 'if' statements from the code, as well as to remove all references to X/Y/Z. As an example, you might want to know whether the points a,b,c form a concave right angle2. One way is to have four different checks looking like:
if(
a.x == b.x &&
a.y < b.y &&
b.y == c.y &&
b.x < c.x
) || ...

repeated 3 more times with slight variation. Or, you could write a one-liner like so:

bool concave = (a.towards(b).left() == b.towards(c));

Teams of people were shown this example, contrasting 20 lines of code against the one-liner, and the response was almost universally, "so? what's the problem?"

I am truly stunned and left speechless when people cannot comprehend the difference in readability/maintainability of 20 lines of (mind-numbingly-repetitive-and-error-prone) code versus one line. We can debate whether the single line is simply readable or more elegant, but surely the 20 lines can be agreed as horrific.

After finally bridging that gap, people immediately ask why the GTL library does not provide direct access to the X/Y/Z coordinates. The question is usually phrased as, "Ok, ok, the one-liner is better. But what if I want to use the X/Y version?" Nobody has given an example where the isotropic (aka coordinate-free) code fails to provide something the X/Y interface provides. Yet people still cling to wanting that interface3.

I'm of the opinion we should force the level of abstraction up.

New languages should not have for/while/do-while loops, and (in this example), a geometric library should not provide an interface to X/Y/Z coordinates.

Personally, I'd rather not work with you if you can't wrap your mind around a higher level of abstraction4.

Footnotes:

  1. Sure, there are occasions in high-performance code where you might need to deal directly with indices, or write a for loop, but 97% of the time you don't, so give it up.

  2. This example assumes manhattan geometry, a common assumption in the EDA world.

  3. Yes, when you draw a rectangle, it might be clearer to access the X/Y coordinates directly. However, you'd better write that code in only one location. And why isn't your graphics library providing this for you in the first place?

  4. Interestingly, the GTL library provides significant speed improvement over other libraries because its isotropic bent allowed it to get rid of if statements which kill performance. I also found this post on high level optimization interesting, as well as Yegge's talk on dynamic languages (specifically on optimizations they can make).

Wednesday, June 4, 2008

A guided tour of Emacs

I recently came across the GNU page: A guided tour of Emacs. It is a gem of an introduction to Emacs. Unlike the help distributed with Emacs (tutorial, FAQ, *info* pages), this tour does a good job illustrating the wide variety of Emacs capabilities, and I think it is much more motivating for a newbie than anything else I've seen.

Monday, June 2, 2008

Emacs Tip #24: view-emacs-problems

M-x view-emacs-problems

Like any good tool, Emacs can tell you about problems about which it knows. I just learned something myself (see 'Emacs pauses for several seconds when changing the default font').

To see the problems file, use the keybinding:
   C-h C-e
[edited to correct binding, thanks rodrigo]