axiom-developer
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Axiom-developer] Literated VMLISP.LISP.PAMPHLET


From: Kai Kaminski
Subject: [Axiom-developer] Literated VMLISP.LISP.PAMPHLET
Date: Thu, 21 Sep 2006 17:51:04 +0200
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (darwin)

Hi,

I've 'literated' VMLISP.LISP.PAMPHLET (the result is attached), which
contains compatibility/utility code. In particular, I did the
following:

1) I gave most functions their own chunk. Sometimes I put several
   functions in a single chunk, mostly because they didn't need
   individual documentation. For example there are a lot of aliases. I
   put most of them in a single chunk.

2) I added/removed blank lines and comments. The latter only if they
   appeared to be useless. Otherwise I just kept them.

3) I *did not* change the capitalization/formatting of code. At least
   not intentionally.

4) I *did* change the order of function definitions. This was
   necessary since I put several functions within a single chunk.

5) I *did not* delete any code that wasn't commented out.

6) I created sections roughly corresponding to the comments in
   VMLISP.LISP, which in turn corresponded to the VMLISP Manual. I
   added sections, when it seemed appropriate. I also moved code
   between sections, because sometimes functions were in the wrong
   sections.

   Almost every section contains at least one sentence describing
   what's supposed to go in there. Of course, that's not final.

   There are still functions in the wrong section, since the section
   scheme changed a few times.

7) I wrote documentation for some of the functions. There is still a
   lot of work to do, but it's a start.

8) I built Axiom using the new version. The build didn't finish, but
   it failed in the same spot as with the old one (algebra: compiling
   ahyp.spad). Cliff (CY) apparently succeeded building Axiom with the
   new file.


While literating VMLISP.LISP.PAMPHLET, I maintained a list with open questions,
suggestions, comments etc. Here it is:


1) Credits. There are a few places where credit is given to the
    contributor of a function (search for Juergen Weiss in
    VMLISP.LISP, for example). While I agree that giving proper credit
    to contributors is important, I don't think that the documentation
    chunks of individual functions are the right place. Currently
    that's not a problem since there is almost no documentation, but
    hopefully that will change. I'm not sure how to handle credits
    properly, though. Therefore I did not remove the credits given to
    Juergen in VMLISP.LISP so far.

2) Fixes and history. Some existing chunks are marked as fixes for
   specific compiler versions or contain a complete history for a tiny
   snippet of code. I believe that history belongs in the SVN/Arch/etc
   comments and fixes shouldn't be there at all. If there's a bug in
   the compiler, the compiler should be fixed. If a work-around is
   needed until the bug is removed, the fix should go as soon as the
   bug is fixed; or at least not stay indefinitely.

   For example, take a look at VMLISP.LISP:

     In GCL 2.5 there is a bug in the write-to-string function.
     It should respect *print-escape* but it does not. That is,

     ...

     <<stringimage fix>>=
     ;(define-function 'prin2cvec #'write-to-string)
     (define-function 'prin2cvec #'princ-to-string)
     ;(define-function 'stringimage #'write-to-string)
     (define-function 'stringimage #'princ-to-string)
     @

   Since we don't use GCL 2.5 anymore, why do we keep this? The
   work-around isn't bad since it doesn't really matter wether we call
   WRITE-TO-STRING with *PRINT-ESCAPE* bound to NIL or PRINC-TO-STRING
   (although the latter also binds *PRINT-READABLY* to NIL). But why
   do we keep the explanation of the problem around?

3) Obsolete code/documentation. There is a lot of code that is
   obsolete or almost obsolete. Either because it isn't used anywhere
   or because it is for the benefit of a long dead Lisp system (see
   point 4 below; also look at the 'No-ops and Constant Functions' and
   'Obsolete Functions' in VMLISP.LISP.PAMPHLET)

4) Obsolete and other *FEATURES*:
   
   - CCL (Codemist is dead/obsolete and CCL is also used by OpenMCL)
   - Lucid (dead/obsolete)
   - IBCL (dead/obsolete)
   - KCL (should be replaced with GCL)
   - CMULISP (obsolete; CMU CL does not have this in *FEATURES*)
   - ALLEGRO (is that code for Franz's Allegro CL? Does it run?)
   - ibm/370 (obsolete)
   - LispM (obsolete :-( )
   - AKCL (should be GCL)
   - RIOS (obsolete)
   - DOS (obsolete)
   - RT ?
   - oldboot ?
   - symbolics (obsolete)
   - ibmps2 (obsolete)
   - mcl (is that for Digitool's MCL or for OpenMCL?)
   - lispworks (Is that a recent addition? Does it work?)
   - cormanlisp (see lispworks)
   - clisp (see lispworks)
   - sbcl (see lispworks)
   - abcl (see lispworks)

   Conditionalized code shouldn't be sprinkled all over the place.

5) INT-CHAR isn't part of CL (see A.1.3 of the Hyperspec). Since it
   seems to work like CODE-CHAR, we should probably replace the former
   by the latter.  It is only used in two places, one of which is the
   awkwardly named EBCDIC, which isn't used very often either.

6) I'm not sure what to make of

     (defun copy (x) (copy-tree x)) ; not right since should descend vectors

   Since Axiom runs very nicely without COPY descending vectors, isn't
   that comment obsolete? How did it get there in the first place? And
   why not simply use copy-tree directly then?

7) What about the following:

     ; The following version has been provided to avoid reliance on the
     ; Common Lisp concatenate and replace functions. These built-in
     ; Lisp functions would probably end up doing the
     ; character-by-character copying shown here, but would also need to
     ; cope with generic sorts of sequences and unwarranted keyword
     ; generality

     (defun rplacstr (cvec1 start1 length1 cvec2
                            &optional start2 length2
                            &aux end1 end2)

   Is CONCATENATE really that slow? Is it still bad to depend on its
   existence?

8) What about functions/macros that have unused parameters or provide
   functionality that is somewhat esoteric and isn't used anywhere?
   For example:

     (defun MAKE-OUTSTREAM (filespec &optional (width nil) (recnum 0))
       (declare (ignore width) (ignore recnum))
         (cond ((numberp filespec) (make-synonym-stream '*terminal-io*))
           ((null filespec) (error "not handled yet"))
           (t (open (make-filename filespec) :direction :output))))

   This function is at least once called with optional arguments, but
   obviously that doesn't change anything. The method of creating a
   SYNONYM-STREAM of *TERMINAL-IO*, if passed a number, seems pretty
   insane (even though I can see where that's coming from). The same
   holds for that (NULL FILESPEC) clause.

9) There are many functions with suboptimal names. Examples:

   gensymp - checks wether its argument is an uninterned symbol

   fixp - checks for INTEGER instead of FIXNUM, unless you're running
          CCL

   LC2UC - also called UCASE and UPCASE. The latter is related to CL's
           STRING-UPCASE, but does fancy things for symbols and lists,
           and lets other atoms pass through. There should be only one
           name for this, and it shouldn't be LC2UC.

   |camlCaseName| - camel case is frowned upon in Lisp. Having to type
                    vertical bars twice for a name is awful. I
                    understand that this might be useful/necessary for
                    BOOT code, but eventually these should be changed.

   ALLCAPS - Nowadays the consensus seems to be that lowercase names
             are better. I think we should stick to that. Since the
             Lisp reader upcases everything anyway (unless it's
             surrounded by vertical bars, see above) it doesn't change
             anything.

   is-foo - ANSI CL uses a -p suffix for predicates, as in NUMBERP or
            DIGIT-CHAR-P. I believe we should stick to this. If not,
            we should at least establish a new convention. Currently
            several conventions are used (all from VMLISP.LISP):

              IS-CONSOLE
              PLACEP
              ZERO?

            I understand that even CL makes a few exceptions, but that
            doesn't imply that we have make a mess as well.

   com,mas - This is a matter of style but commas in identifiers are
             just ugly. They don't serve a purpose either.

   nohyphens - Example:

                 LISTOFFREES

               should be

                 LIST-OF-FREES

               In fact, it should be

                 list-of-frees

10) Functions as macros. There are quite a few macros that could be
   functions. They are usually made macros for performance reasons (to
   inline code). This is bad style, crippels the 'functions' and makes
   debugging hard. One could probably get the same or similar
   performance with appropriate inline declarations. Example:

     (defmacro identp (x)
       (if (atom x)
         `(and ,x (symbolp ,x))
         (let ((xx (gensym)))
           `(let ((,xx ,x))
              (and ,xx (symbolp ,xx))))))

     should be

     (declare (inline identp))
     (defun identp (x)
       (and x (symbolp x)))

   There are many similar cases (ifcar, ifcdr, eqcar, ...).

11) EVAL-WHEN. The arguments LOAD, COMPILE and EVAL are
    deprecated. They have been superseded by :LOAD-TOPLEVEL,
    :COMPILE-TOPLEVEL and :EXECUTE.

12) Packages. It is usually recommended that there is exactly one
    IN-PACKAGE form per file to avoid confusion. Since apparently the
    idea is to stuff the whole interpreter into a single pamphlet
    (exposing the hideousness of LP) I'm not sure how this
    translates.

    Usually it is also recommended to bundle functionality in
    packages. Currently that isn't done at all. There are only very
    few packages, and some of them don't serve any purpose. Again I'm
    not sure how packages work with LP.

13) (Quasi-)Aliases. There are many functions that are simply aliases
    for others. Some of them are simply created using

      (defun alias-for-foo (arg1 ... argN)
        (foo arg1 ... argN))

    Others are created using

      (define-function alias-for-foo #'foo)

    which simply sets the SYMBOL-FUNCTION of ALIAS-FOR-FOO to the
    function #'FOO.

    Sometimes these aliases don't accept all the parameters that the
    original accepted.

    Quasi-aliases are functions like

      (defun MSUBST (new old tree) (subst new old tree :test #'equal))

    that differ from their original by supplying one or more
    arguments.

    (Quasi-)Aliases should probably be replaced, unless they capture a
    concept. Suppose you store objects of type FOO as lists, and it so
    happens that two FOOs, say FOO-1 and FOO-2, are equal iff

      (equal foo-1 foo-2)

    returns T. In that case it's justified to have a function

      (equal-foo (&rest args)
        (apply #'equal args))

    Also if a (quasi-) alias captures a very common use of the underlying
    function and improves readability it can stay.

    I don't think saving key strokes is enough reason for introducing
    an alias. After all Emacs supports dynamic completion (even in
    Fundamental Mode). Other editors have similar features, I believe.

14) No-ops and constant functions. Believe it or not, but there are
    quite a few functions that literally do nothing, like

      (defun make-string (a) a)

    or

      (defmacro assemble (&rest ignore) 
        (declare (ignore ignore))
        nil)

    I reckon they should go.

16) Multiple definitions. There are multiple definitions for some
    functions, eg (in VMLISP.LISP)

    ;;--------------------> NEW DEFINITION (see unlisp.lisp.pamphlet)
    (defun |ListMember?| (ob l)
      (member ob l :test #'equal) )

    which corresponds to

    ;;--------------------> NEW DEFINITION (override in vmlisp.lisp.pamphlet)
    (defun |ListMemberQ?| (ob l)
      (member ob l :test #'eq) )

    (defun |ListMember?| (ob l)
      (member ob l :test #'equal) )

    in UNLISP.LISP. There is no ListMemberQ? in vmlisp.lisp by the
    way.

    To me it's not clear which of the two definitions is in
    effect. I'd have to look into the appropriate Makefile, I
    guess. Why not just get rid of the obsolete definition?

    This case is particularly interesting, as both definition are
    equivalent.

18) Gensyms. In macros you use GENSYM to generate unique symbols to
    avoid name clashes with user defined symbols. This shouldn't be
    done by hand, though. Instead a macro like WITH-UNIQUE-NAMES or
    WITH-GENSYMS ought to be used.


Kai

Attachment: vmlisp.lisp.pamphlet
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]