Subject: Re: Coding style
From: Erik Naggum <erik@naggum.net>
Date: Mon, 08 Oct 2001 00:28:59 GMT
Newsgroups: comp.lang.lisp
Message-ID: <3211489735193683@naggum.net>

* Software Scavenger
| I want to discuss Lisp coding style.

  In these times of war, I think that is a wise choice.  Nothing unites
  people against their common enemies like discussing (bad) coding styles.

| In the examples below of a prime-factors function, the first example is
| closest to the canonical Lisp coding style, but this style has problems
| such as higher incidence of word-wrap when viewing in smaller windows.

  If you have a handicap that requires to you to use very large fonts, I
  think you should say so up front so we know the context of your needs.
  If you only have smaller windows, you use the wrong operating system or
  even hardware for your needs, and should not receive any sympathy. Well,
  perhaps a gift certificate for a hardware upgrade, but nothing about your
  coding style should receive any sympathy.

| The 2nd example is a style intended to reduce usage of screen real estate.

  If screen real estate is actually a _problem_, the solution is _not_ to
  fiddle with coding styles, but to choose smaller or narrower fonts and
  find ways to get the clutter out of your windows.  E.g., the Microsoft
  Windows paradigm is that you have no virtual screen estate, and cannot
  switch between workspaces.  This frustrated the hell out of me when I had
  to use that abominable luser interface.  A billion small pop-up windows
  would show up and demand attention like I lived to respond to some kind
  of moronic psychological test.  With X Windows, I use vtwm, which lets me
  have a large number of work spaces where I can have a few large windows
  with lots of real information, and switch between _complete_ contexts
  instead of being bothered by noise from other contexts all the time.  I
  realize that beign able to concentrate for a sustained period of time on
  a single task at a time is a negative personality characteristic in these
  days of animated, if not agitated, banner ads even in the New York Times
  and self-refreshing web pages that not only crash your browser, but fail
  to position themselves where they were the last time you looked.  None of
  these issues may of course be related to _your_ screen real estate issue,
  but if they are, please considering fixing the real problem.

| The unless/let line is indented instead of having all the lines below it
| indented, as one easy way to reduce overall horizontal size.

  How much manual effort do you put into these stunts?  Indentation and
  coding styles should be invisible and effortless to produce and read.
  The more effort you put into it, the more effort goes into reading it,
  and you achieve your goals at a very high cost.  Back in the 70's, there
  were a lot of interest in "syntax-directed editors", but as developers
  have universally come to trust Emacs programming modes (and those who do
  not know Emacs are merely doomed to reinvent it badly), there is no need
  at all to do indentation manually.  If you ever find that you have to do
  that, you are doing something wrong.

| The 3rd example is a compromise to minimize horizontal size and maximize
| readability.

  You maximize readability by doing what everybody else does.  This also
  includes not inventing your own conditionals because you are dissatisfied
  with the indentation of cond or have a personal hangup with progn that
  makes you do something fantastically ugly and unreadable that causes you
  to lose friends and the respect of a whole community when you elevate
  your silly aesthetics to abject fanaticism.  People have been known to go
  off and invent their own _languages_ simply because they had a problem
  with indentation in other languages.

| But regardless of the merits of flamx etc., it's also worthwhile to
| discuss the merits in general of using macros to support coding styles.

  Hardly.  Anything you do with coding styles should _reduce_ the cognitive
  load on the reader.  If it does not do that, it is _bad_ to mess with the
  coding styles.  Cognitive load is not a subjective thing, but it has some
  _personal_ qualities.  That is, it is not hard to figure out what kind of
  factors are involved, but precisely which values to assign to each factor
  may vary somewhat from person to person.  E.g., you have basically done
  what another "coding style freak" has done previously: Break a lot of
  good stuff, consensus, community goodwill, and even the basic trust in
  his sanity in order to get a single and fundamentally silly readability
  factor only slightly improved at such costs that it is obvious that it
  never was a _rational_ thing to do.

| But in any case the purpose of posting these examples is to start a
| discussion of coding style, especially coding style that conserves
| screen space, and especially horizontal space.

  The presumption that these are valid concerns also need discussion.  I
  think that qua concerns, they are completely misplaced.  If you want to
  conserve space so badly, using a language that has longer operator names
  than a couple characters is probably a bad idea.  If you want to cut down
  on the compounded indentation, you can reduce the default indentation
  from 2 to 1.  If you think you have no use for indentation, you can try
  to cut it down to 0, too.

  As for your particular code, I think it displays an incredibly ugly abuse
  of loop features right off the bat and I had a hard time following your
  code.  The thereis clause means you are looking for something and
  returning it, but you are looking for something and returning something
  else in an ugly punning operation.  Also, returning a value from the loop
  form means you return a counter-interintuitive sentinel value and that
  you need to guard against impossible values because of this.  Concern
  over the use of horizontal space by this function is just plain silly.

(defun prime-factors (n)
  (unless (< n 2)
    (let ((x (loop as i from 2 to (sqrt n)
                   thereis (if (= 0 (rem n i)) i)
                   finally (return n))))
      (cons x (prime-factors (/ n x))))))

  Consider this rewrite, one possible among many:

(defun prime-factors (n)
  (loop for i from 2 to (isqrt n)
      if (= 0 (mod n i))
      return (cons i (prime-factors (/ n i)))
      finally (return (list n))))  

  Note the use of isqrt to get an integer root, which would be important
  when asking for the prime factors of large numbers lest the floating
  point value likely returned by sqrt not capture the exact root value.
  Note also that sqrt is defined to return a rational or a _single-float_
  value, which is _really_ bad mathematically -- if it were not for the
  staggeringly naive way you search the prime space, you would run into
  serious accuracy problems with completely bogus comparisons between the
  integer i and the single-float (sqrt n), but it should take so long to
  run into this problem that you most probably would not actually use your
  algorithm on numbers with large prime factors, but I could be wrong about
  how soon you will run into a problem.

///