Octopodial Chrome

Stuff that Made Sense at the Time

The Personal Weblog of Bob Uhl


Wednesday, 20 August 2008

The Many Features of Lisp

Abhishek Reddy has written an excellent precis of the features of Common Lisp. If you’re at all interested in programming languages, here it all is: everything Lisp has which your favourite language very probably doesn’t.

For my money, conditions are just about the coolest things ever.

Friday, 15 August 2008

Thoughts on Up-or-Out

Bruce Webster has some interesting thoughts on modifying the Cravath model for the technical field. The Cravath model is the standard big-company practise of having partners, directors, senior managers, managers, senior associates & associates who are rated annually, with the lowest performers being asked to leave and the highest performers being promoted. In many ways the model is good, but one problem is that it doesn’t really work for technology because technologists generally don’t wish to manage and generally don’t do well in management; Webster proposes a parallel track of associate engineer, engineer, senior engineer, technical officer, senior technical officer, executive technical officer and chief technical officer.

It’s a pretty good idea, I think. I’m not certain how a technical officer would keep his skills current, but it’s probably very doable. And it certainly makes more sense than putting engineers into management.

Wednesday, 28 May 2008

Return of the Lisp Machine

Arto Bendiken notes that Lively Kernel is a reinvention of the Lisp Machine concept. For those who’ve not heard of them, Lisp Machines were really great pieces of work: at a time when command-lines and static software which crashed were the norm, they provided full GUIs, dynamic software and elegant error recovery. Perhaps Lively Kernel can bring some of that coolness into the 21st century.

Computing really is about continually reinventing the wheel.

Wednesday, 14 May 2008

No Dashes or Spaces

We’ve all seen those credit-card-entry (and other) forms which ask us to leave out dashes, spaces and other punctuations when entering our numbers. Never mind that credit card numbers are naturally written with spaces, that Social Security numbers use dashes and that phone numbers have a number of different representations involving dashes, parentheses, spaces, periods and plus signs. The really ridiculous thing is that removing extraneous punctuation is dead-simple for a computer to do. But these lazy programmers offload a single line of code’s worth of work onto the thousands or millions of visitors to their sites.

Well, Steve Friedl has decided to shame these morons. His well-intentioned attempt is probably doomed, but I wish him luck.

Wednesday, 23 April 2008

Lisp for the Web

Adam Petersen demonstrates how to create a simple polling web app in Common Lisp—in around 70 lines of code! It’s not perfect (as one reddit comment noted, he needs to escape his strings for HTML), but it’s a pretty cool demonstration of how Lisp can serve as a rapid development platform.

Lisp isn’t perfect, but it’s better than the alternatives out there.

Friday, 11 April 2008

Metcalfe's Law is Wrong

Metcalfe’s Law states that the value of a network of size n is proportional to n2. This follows from a simple observation: that the number of possible connections for each user in a network is n - 1; and since there are n users, then the total number of connections is n × (n - 1), which is roughly n2. This all seems reasonable and makes sense.

But it’s wrong. It begs one simple question: what is the value of a connection. Metcalfe’s Law assumes that each connection is equally worthwhile. This doesn’t really make sense: is my connection to a bushman in the Kalahari as useful to me as my connection to my brothers, or to my bank? Not very likely.

It turns out that there’s another law—Zipf’s Law—which addresses all sorts of distributions. The article goes into more detail, but basically the second-most-important item in a list is one half as valuable as the first; the third is one third as valuable; the fourth is one quarter as valuable; and so on an so forth. It turns out that adding up 1 + 1/2 + 1/3 + 1/4…1/n approximates log n reasonably closely. One might say that the value of a network of size n to any single user is proportional to log n (that is, the sum of the value of his most important link, his second most important link and so on until we get to his link to a squid-fishing boat in the Atlantic).

Thus Briscoe, Odlyzko & Tilly suggest their own network-value law: the value of a network is in proportion to n log n. They present some economic predictions based on this law, which seem to be borne out by the facts.

Anyway, read the article. It’s good and detailed and makes sense.

Tuesday, 25 March 2008

The Wodehouse Method of Refactoring

Refactoring is a vital process in the creation of beautiful programs; redrafting is a vital process in the creation of beautiful literature; Basildon Coder suggest adapting P.G. Wodehouse’s redrafting method to refactoring. It makes extremely good sense.

Friday, 21 March 2008

An Introduction to REST

My fellow web programming geeks will have heard a lot of buzz about Representational State Transfer (REST). It’s definitely an improvement on the Ozymandian Web Services stack. But what is it really? How is it used? How does one adapt a design to it? Stefan Tilkov has a top-notch brief introduction to rest. If you write or design web-consumed services, or plan to, or manage those who do, check it out.

Thursday, 13 March 2008

When All You Have is a Hammer...

…screws don’t make much sense.

We’re all familiar with the adage that says when all you have is a hammer, everything looks like a nail. That’s true enough as far as it goes. We tend to frame problems in terms of what we know. However, there’s an even more pernicious effect: we don’t recognise the utility of solutions outside our experience. If all you have is a hammer, screws seem like a distinctly sub-optimal type of nail: they require more force to hammer in, they damage the wood and they don’t hold as well. Once you have a screwdriver, you realise that screws are actually superior to nails for many tasks.

The article inheritance is evil and must be destroyed is written by someone who only knows about hammers. He uses the example of a class representing a ball; it’s further subclassed into bouncing balls and balls which fade in and out. But what if one wants to have a bouncing, fading ball? He writes using inheritance, the code that handles bouncing and fading is locked up in the BouncingBall and FadingBall classes and can’t be used elsewhere. Well, in a language which only allows single inheritance, sure: you can only inherit from one superclass, and so it’s not possible to have a bouncing fading ball which inherits from both bouncing and fading balls.

Fortunately, we’ve had a well-defined object system since the late 1980s. It allows multiple inheritance, and all one has to do is inherit behaviour from both superclasses and Everything Works. An example:

(defclass ball ()
  ((x
    :accessor x
    :initform 0
    :initarg :x)
   (y
    :accessor y
    :initform 0
    :initarg :y)
   (colour
    :accessor colour
    :initform 'white 
    :initarg :colour)))

(defclass bouncing-ball (ball)
  ((elasticity
    :accessor elasticity
    :initform 1
    :initarg :elasticity)
   vector))

(defclass fading-ball (ball)
  ((fade-rate
    :accessor fade-rate
    :initform 1
    :initarg :fade-rate)))

(defclass fading-bouncing-ball (fading-ball bouncing-ball) ())

(defgeneric draw (ball)
  (:documentation "Draw BALL at its position"))

(defmethod draw ((ball ball))
  "Draw BALL at its position, with the proper colour."
  (draw-circle (x ball) (y ball)) (colour ball))

(defmethod draw :before ((ball bouncing-ball))
  "Move BALL to the next position as it bounces."
  (with-slots (vector x y) ball
    (setf x (bounce-x x vector)
          y (bounce-y y vector))))

(defmethod colour :around ((ball fading-ball))
  "Return BALL’s colour faded for this point in time."
  (fade-colour (call-next-method ball) (fade-rate ball) (get-current-time)))

And yes, everything works exactly as expected. The DRAW method specialised on balls draws a circle wherever it needs to; the DRAW before-method specialised on bouncing balls runs before a bouncing ball is drawn; it updates its current position and then the primary DRAW method is called, drawing the ball at the new position. The COLOUR around-method specialised on fading balls calls the normal COLOUR method, figures out the faded colour and then returns it. Yes, an instance of FADING-BOUNCING-BALL inherits from both FADING-BALL and BOUNCING-BALL, and they both inherit from BALL. It all just works.

You can either keep on trying to hammer in screws, or you can learn how to use a screwdriver, or you can claim that screws are awful fasteners and that nails are always better. One of these is a better solution than the others.

Monday, 04 February 2008

Windows Games That Crash Vista But Work on Linux

We all know that Windows Vista breaks a lot of things. What’s surprising is that it breaks Windows software so badly that running that same software under Linux and Wine (a free Windows implementation) can be a better choice. Here’s a list of games which run better under Linux+Wine than under Vista. Microsoft sure have some egg on their face with this one.

Friday, 01 February 2008

Navigator Mortuus Est

Today AOl has killed Netscape Navigator. I remember using Mosaic on Solaris and Macs, and when Navigator came out I thought it was just a ripoff of Mosaic (which is was—in fact, IIRC the first version was called Mosaic…). But then it became extremely popular, setting several records (including buggiest software ever).

The best thing Netscape ever did was free its code, giving us Firefox. The rest is…well, it happened: that’s the best which can be said for it.

Monday, 28 January 2008

Emergency Elisp

Steve Yegge has prepared a simple emacs lisp primer. It’s by no means complete, but it introduces enough of the language that anyone with a small amount of programming knowledge should be able to start playing around.

Emacs, of course, is the best text editor, mail client, news client, web browser, database interface, Nethack interface and kitchen sink in the world.

Religion and Programming Languages

It’s often said that one’s choice of computer languages is at heart a religious matter (I tend to disagree, but that’s another matter): now there’s a survey of religions and programming languages which is attempting to see if there’s any connexion. It was difficult for me to choose the languages I prefer. Common Lisp was a no-brainer, as was Python. But what about C? I decided against it—while it was a neat & cool language once upon a time, it’s hardly a sane choice today. OTOH, what about SmallTalk? I’ve never used it for a serious project, but it’s an incredibly neat idea. I ended up choosing it, simply because it deserves it.

Saturday, 26 January 2008

Internet '96

A voyage back in time, to when the internet was in its infancy and web design’s parents hadn’t met yet.

Sunday, 20 January 2008

The Programmer's Pyramid

Oliver Steele proposes a programmer’s pyramid based on the ideas in the food pyramid from the Department of Agriculture. Basically, a programmer should spend most of his time reading code, particularly exemplary code, then his own code, then code that he’s using which other people wrote. He should spend somewhat less time revising code. He should spend a bit less time writing code. He should spend even less time reading about code. Finally, he should spend the least time of all writing about code.

I think that Steele is on to something.

Thursday, 17 January 2008

Quit Overloading Names!

Trademark law exists for a simple reason: to prevent confusion between similar product. It is a violation of Microsoft’s trademark to sell a word processor called Word; it is a violation of Ford’s trademark to sell a car called a Ford. It’s perfectly okay to sell a word processor called Ford or a car named Word, though: trademarks only apply to a certain field of endeavour.

The computer world can have name collisions too, sometimes imaginary and sometimes quite real. In the former category we have Sun’s Yellow Pages service (a bunch of yp-* commands like yppasswd); Bell forced them to change it, despite the fact that computers are a different field of endeavour.

In the category of real conflicts we have Apple’s iCal, which infringes on the name of the much older (and still in active use) ical. Then there’s Adobe’s Flex, which uses the name of the flex lexical analyser which dates back to around 1982 and is, again, still in active use.

How hard is it to just google a possible product name? Apple could have chosen another name for their product (iCalendar, iSchedule, iTime, iDates, whatever—or just sanely called it something without the i); Adobe could have called Flex FlexWeb, Flux, WebFlex, FX or any of a number of names. But no, they had to take another project’s name. Gosh, thanks guys.

Tuesday, 15 January 2008

How Three Guys Restaged D-Day

Technology has advanced to the point that three guys were able to re-enact the landings at Omaha Beach. Three guys, three uniforms, one rope, two rifles, a video camera and movie-editing software—that was enough. Over four days of filming they got lots of footage of the three of them on the beach; then they were able to clone themselves over and over again, finally resulting in a D-Day landing which is reminiscent of Spielberg’s in Saving Private Ryan.

Friday, 11 January 2008

The Genius of Donald Knuth

Mark Chu-Carroll explains just why Donald Knuth’s TeX is so cool. To this day, I write all my correspondence in LaTeX; it’s a wonderful tool (for one thing, the LaTeX logo actually looks good when properly typeset).

Wednesday, 02 January 2008

Ten Obscure Google Tricks

Lifehacker presents ten Google search tricks. Pretty good stuff to know.

Monday, 31 December 2007

Backup Tip

Way back in 1994, Rob Horn gave an excellent tip: randomly restore one file from backup every week. If you have data which you care about (and you do, whether you know it or not), it needs to be backed up. And if it’s being backed up, you need to test that backup system regularly to ensure that you’ve not forgotten something or been bitten somehow. Restoring one random file per week is a good practise to follow.

Wednesday, 26 December 2007

Predicting the Future

Back in 1989 Alan Kay (the creator of SmallTalk) gave a talk on predicting the future to the 20th anniversary meeting of the Stanford Computer Forum. It has many insights, but my favourite is that we predict evolutionary changes, not revolutionary ones.

Monday, 24 December 2007

Unix Makes Computer Science Easy

I just found an article which details how Unix took a lot of difficult computer science stuff and made it easy for an end-user. Even in 1979, Unix had a lot of great capabilities. There are two problems: first, Unix hasn’t progressed very much since then; second, no-one else has even gotten this far (or at least, hasn’t gotten this far and succeeded). By now we should all be using Lisp machines; instead we’re all using technology that’s older than I am.

Effective Emacs

Jacob Gabrielson wrote a nice blog post giving some tips for effective use of emacs. I’ve managed to reduce my emacs start-up time from six seconds to one, which ain’t too shabby.

Sunday, 23 December 2007

Why Macros Rock

A lot of people don’t really understand why Lisp’s macros are so useful. I spent some free time this past week rewriting my beer tasting notes site, and here’s an example of an instance where Common Lisp’s object system and macros really came in handy.

A common need when writing CRUD web apps is to display one of a given class: information about a particular model of car, or an employee—or in my case, a particular brewer, beer, bar, style or whatever. After writing my first function I had something that looked like this:

(defun display-brewer (name)
  (let ((brewer (select 'brewer :where [= [name] name] :flatp t)))
    (if brewer
        (with-template (format nil "~a @ Tasting Notes" (name brewer))
            (modification-date object)
          (:table
           (:tr (:th "Average rating")
                (:td (str (if (rating brewer)
                              (make-sequence 'string 
                                             (rating brewer) 
                                             :initial-element #\*)
                              (htm (:em "No beers"))))))
           (when (plusp (length (notes brewer)))
             (htm (:tr (:th "Notes") (:td (str (notes brewer))))))
           (when (plusp (length (address brewer)))
             (htm (:tr (:th "Address") (:td (str (address brewer))))))
           (when (plusp (length (url brewer)))
             (htm (:tr (:th "Website")
                       (:td (:a :href (url brewer) (str (url brewer))))))))
          (when (beers brewer)
            (htm (:h2 "Beers") (:ul (list-objects (beers brewer))))))
        (progn
          (setf (return-code) +http-not-found+)
          (with-template (format nil "Error: Brewer ~a not found" name)
              nil
            (:p (fmt "Could not find a brewer named ~a." name)))))))

This looks pretty ugly if you don’t understand Lisp, but basically I just defined a function DISPLAY-BREWER which displays some brewer identified by a name. It does this by looking up (selecting) the brewer in a database; if it finds the brewer, then it’s displayed, else an error message is displayed instead.

The thing is, every single display function will look similar, indeed almost identical: to display a bar (also identified by a name), I’ll look it up by name, then if it is found I’ll display it, otherwise I’ll display an error message. DISPLAY-BAR would be:

(defun display-bar (name)
  (let ((bar (select 'bar :where [= [name] name] :flatp t)))
    (if bar
	(with-template (format nil "~a @ Tasting Notes" (name bar))
	    (modification-date object)
	  (:table
	   (when (food-rating bar)
	     (htm (:tr (:th "Food rating")
		       (:td (str (make-sequence 'string 
                                                (round (food-rating bar))
                                                :initial-element #\*))))))
	   (when (owner bar) (htm (:tr (:th "Owner")
				       (:td (:a :href (link (owner bar)) 
                                                (str (name (owner bar))))))))
	   (when
	       (beer-rating bar)
	     (htm (:tr (:th "Drink rating")
		       (:td (str (make-sequence 'string
                                                (round (beer-rating bar))
						:initial-element #\*))))))
	   (when (address bar)
	     (htm (:tr (:th "Address")
		       (:td (str (address bar))))))
	   (when (notes bar)
	     (htm (:tr (:th "Notes")
		       (:td (str (notes bar))))))
	   (when (url bar)
	     (htm (:tr (:th "Website")
		       (:td (:a :href (url bar)))))))
	  (when (beers bar)
	    (htm (:h2 "Beers")
		 (str (list-objects (beers bar)))))
	  (when (foods bar)
	    (htm (:h2 "Foods")
		 (str (list-objects (foods bar))))))
	(progn
	  (setf (return-code) +http-not-found+)
	  (with-template (format nil "Error: Bar ~a not found" name)
	      nil
	    (:p (fmt "Could not find a bar named ~a." bar name)))))))

You notice something? There’s an awful lot of repeated code. For example, over the two functions I call (make-sequence ’string SOMETHING :initial-element #\*) three different times. What this is actually doing is taking a number and turning it into the same number of stars, e.g. turning 4 into ****. The obvious thing to do is to define a function STAR-RATING which does that, so I do (and I change it to use MAKE-STRING instead of MAKE-SEQUENCE, and to always call ROUND, which does nothing to integers but will turning real numbers into integers):

(defun star-rating (number)
  "Return a string consisting of NUMBER stars.  If NUMBER is a float,
  returns that number rounded off."
  (make-string (round number) :initial-element #\*))

This turns (make-sequence ’string (rating brewer) :initial-element #\*) into (star-rating (rating brewer)); (make-sequence ’string (round (food-rating bar)) :initial-element #\*) into (star-rating (food-rating bar)); and (make-sequence ’string (round (beer-rating bar)) :initial-element #\*) into (star-rating (beer-rating bar)). This is a nice savings on typing, and makes the code more readable, although it could be better (STAR-RATING isn’t the best name in the world, but it’ll do for now). Just about every programming language out there can refactor commonly-used code patterns into functions like this; indeed, it’s a major use for functions.

How about the rest of the code? There’s another pattern there: looking up an object, then either displaying it or an error message which refers to the type of the object being displayed. There are a number of ways to handle this, but the cleanest is to write a macro DEFINE-DISPLAY (which uses a function GET-OBJECT I’ve defined elsewhere; its use looks like (get-object ’bar "Falling Rock")):

(defmacro define-display (class function &body body)
  `(defun ,function (name)
     (let ((,class (get-object ',class name)))
       (if ,class
	   (with-template (format nil "~a @ Tasting Notes" (name ,class))
	       (modification-date ,class)
	     ,@body)
	   (progn
	     (setf (return-code) +http-not-found+)
	     (with-template (format nil "Error: ~a ~a not found" ',class name)
		 nil
	       (:p (fmt "Could not find a ~a named ~a."  
                        ',class name))))))))

This takes that pattern and turns it into a macro; I can then re-use the pattern like this:

(define-display brewer display-brewer
  (:table
   (:tr (:th "Average rating")
	(:td (str (if (rating brewer)
		      (make-sequence 'string 
				     (rating brewer) 
				     :initial-element #\*)
		      (htm (:em "No beers"))))))
   (when (plusp (length (notes brewer)))
     (htm (:tr (:th "Notes") (:td (str (notes brewer))))))
   (when (plusp (length (address brewer)))
     (htm (:tr (:th "Address") (:td (str (address brewer))))))
   (when (plusp (length (url brewer)))
     (htm (:tr (:th "Website")
	       (:td (:a :href (url brewer) (str (url brewer))))))))
  (when (beers brewer)
    (htm (:h2 "Beers") (:ul (list-objects (beers brewer))))))

That’s obviously a lot more readable than the first DISPLAY-BREWER I created. What’s more, when I define DISPLAY-BAR, I just have to do this:

(define-display bar display-bar
  (:table
   (when (food-rating bar)
     (htm (:tr (:th "Food rating")
	       (:td (str (make-sequence 'string 
					(round (food-rating bar))
					:initial-element #\*))))))
   (when (owner bar) (htm (:tr (:th "Owner")
			       (:td (:a :href (link (owner bar)) 
					(str (name (owner bar))))))))
   (when
       (beer-rating bar)
     (htm (:tr (:th "Drink rating")
	       (:td (str (make-sequence 'string
					(round (beer-rating bar))
					:initial-element #\*))))))
   (when (address bar)
     (htm (:tr (:th "Address")
	       (:td (str (address bar))))))
   (when (notes bar)
     (htm (:tr (:th "Notes")
	       (:td (str (notes bar))))))
   (when (url bar)
     (htm (:tr (:th "Website")
	       (:td (:a :href (url bar)))))))
	  (when (beers bar)
	    (htm (:h2 "Beers")
		 (str (list-objects (beers bar)))))
	  (when (foods bar)
	    (htm (:h2 "Foods")
		 (str (list-objects (foods bar))))))

The display functions are reduced down to their essential core and I don’t have to keep re-typing (and possibly mis-typing) the fiddly bits which don’t change. There’s still a lot of work which I could still re-do (e.g. one common pattern seems to be (when THING (htm (DO-SOMETHING THING))); another is (:tr (:th HEADING) (:td DATA))), but this is a good first start.

And it’s why Lisp rocks: other languages have functions which let one re-arrange functional abstractions; what they lack are macros, which let one re-arrange syntactical abstractions. In Lisp I can take the actual body which changes and plug it into the unchanging skeleton; I can take the name of the class and plug it in so that I can refer to it in the body. It makes life very easy and simple.


August
Sun Mon Tue Wed Thu Fri Sat
         
27 28 29 30
31            
2008
Months
AugSep
Oct Nov Dec

Powered by Blosxom | Subscribe with Bloglines | Listed on
BlogShares | Blogarama - The Blog Directory | Technorati Profile

This is my blogchalk:
United States, Colorado, Englewood, Centennial, English, , Robert, Male, 21–25, Free Software, Society for Creative Anachronism.