SiteMap / AllPages / Out

ProgrammingLanguages

A language that doesn't affect the way you think about programming, is not worth knowing. --Alan J. Perlis

Check the Epigrams in Programming by Alan J. Perlis:

I've used several programming languages in the past... This page is a feeble attempt at describing what I felt to be the greatest impact that learning the language had on me.

Also note the languages of choice entry in the JargonFile.

The Distant Past

Way back when I was a little kid, I used Basic to program my calculator. Usually usefull stuff for math classes in school. At home, I kept fiddling with my autoexec.bat file. *shudder*

C

At university, I wanted to run a German version of the Atlantis PBEM, written in C. This is when I started to get a life. I got myself the DJGPP ports of all the GNU tools: GCC, make, etc.

At the same time, I needed a better editor for my mail. I read my mail using ELM and wrote my mail using vi. I started to learn Emacs on the university's AIX. Then I discovered the various DOS ports of Emacs. I got the DJGPP port and started to work on Atlantis in earnest. Luckily enough, I didn't have to start from scratch. The basic machinery was already there, written by Russel Wallace, the original author of Atlantis 1.0. See PlayByEmailDesign for more about the games.

C taught me a lot about the dangers of programming. The use of pointers and pointer arithmetic allowed me to understand the inner workings and dangers of references, garbage collection, linked lists, buffer overflow security risks, etc. Pointers are the building blocks of nontrivial computing. Luckily pointers as such are not really needed in languages such as Java, Perl, Python, or Lisp. All these languages, however have references to objects. The pointers are still there, but many things happen automatically now: Garbage Collection, referencing and dereferencing, iterators. Pointers help you understand anything that takes pictures of little boxes and connecting arrows to explain.

    void
    collectallmoney (region * r, unit *collector)
    {
      int sum=0;
      unit *u;
      for (u = r->units; u; u = u->next)
        if (u->faction == collector->faction &&
            u != collector &&
            u->type == U_MAN &&    /* nur menschen geben geld her */
            can_contact (r, collector, u))
          {
            sum += u->money;
            u->money = 0;
          }
      collector->money += sum;
      sprintf (buf, "%s sammelte $%d ein.", unitid (collector), sum);
      addevent (collector->faction, buf);
    }

Perl

As I continued to work on Atlantis, I decided that I wanted to parse the Atlantis reports. I had heard about Perl and decided to give it a try. Perl was powerful debugging felt easy. I loved it.

There were some problems that cropped up, however. As long as the scripts remained small, no problem. As data structures got more complex, however, I spent more and more time debugging my code. Worse, when I discovered a bug after a few weeks, it got really difficult to understand my own code.

After having passed Atlantis on to other people, I started thinking about a new game, Ambush. It was inspired by an old wargame on the C64 called Computer Ambush. I decided to write it in Perl. Unfortunately, I never finished it. I had difficulties implementing a "line-of-sight" algorithm, I got bogged down in syntax problems, and I was unable to write object oriented Perl code. I gave up.

Eventhough Perl is about as hairy as you can get, Perl taught me the power of regular expressions. Regular expressions make string and file parsing so much easier than old-style tokenizing or character processing. At last I was able to parse files, write data structures into files, read the structures back into memory, process more files, format the output, without having to spend significant amounts of time on these processes. Regular expressions give you the power of non-trivial search and replace functionality.

    print "Liste der Burgen, nach Inseln gruppiert:\n\n";
    foreach $x1 (sort {$a <=> $b} keys %region)
    {
        foreach $y1 (sort {$a <=> $b} keys %{$region{$x1}})
        {
            printf "%s (%d,%d)\n\n", $insel{$x1}{$y1} ? $insel{$x1}{$y1} : "Unbekannte Insel", $x1, $y1;
            $inseln++;
            foreach $x2 (sort {$a <=> $b} keys %{$region{$x1}{$y1}})
            {
                foreach $y2 (sort {$a <=> $b} keys %{$region{$x1}{$y1}{$x2}})
                {
                    $regionen++;
                    print "    $region{$x1}{$y1}{$x2}{$y2}->{name}";
                    foreach $burg (sort keys %{$region{$x1}{$y1}{$x2}{$y2}->{burg}})
                    {
                        print "    ", $region{$x1}{$y1}{$x2}{$y2}->{burg}{ $burg};
                        $burgen ++;
                    }
                }
            }
            print "\n";
        }
    }

Python

When I started with Python, I was amazed: object orientation actually worked! And even more amazing: It was easy to install. It had an XML parser included. It worked with Tk! And it even worked on Windows!

It was mind-boggling.

I rewrote one of the hard to understand scripts I used for maintaining this web site in Python. And I started to work on a new game of mine, Oligarchie.

Python finally made me understand object orientation. At last object orientation was revealed to be a way of structuring your code instead of syntactic mumbo jumbo. Learning object orientated programming using C++ or Java can be very difficult. Mostly because the superficial syntactic requirements are totally unrelated to the concept itself. Python has less superficial syntactic requirements and is therefore better suited to teach programming than C, C++, or Java. Note how I didn't mention Perl.

    class InfoList(Toplevel):
        """Zeigt eine Liste aller Oligarchen in einer Region, sowie alle
        Oligarch'Memories, welche sich damals in derselben Region
        befanden."""
        def __init__(self, lang, all_oligarchs, region):
            """Ruft die __init__ methode der Superlklasse, sowie die
            methoden, welche das GUI erstellen und die Liste der
            Oligarchen in der Region abfüllen."""
            self.lang = lang
            self.all_oligarchs = all_oligarchs
            self.oligarchs = self.meta_oligarchs(all_oligarchs, region)
            self.castle = self.meta_castle(all_oligarchs, region)
            self.artefacts = []
            self.ships = self.meta_ships(all_oligarchs, region)
            Toplevel.__init__(self)
            self.title(region.name_get(self.lang))
            self.create_gui()

EmacsLisp

During all this time, I kept using Emacs. I even use it at work (where I use languages such as SQL, PL/SQL, Centura, and Java). Emacs can be extended using Emacs Lisp, or elisp. My Emacs pages contains lots of code I wrote for Emacs. See TheOneAndOnly for more about Emacs.

Since Emacs contains so much elisp code already, programming elisp is like using a huge library. So much to learn. So many unbelievable things. Emacs is the editor that just keeps on giving.

Emacs Lisp by itself taught me the virtues of an integrated documentation system, the grandeur of having the interpreter be more than just a command line interface but a non-trivial editor, the benefits and dangers of dynamic binding. As Emacs is extensible, well supported by a dedicated community, and Emacs Lisp is relatively easy to learn, the library is enormous and growing. You can keep loading more and more code into the interpreter. As you do this, documentation, mechanisms designed to help users find existing documentation, and a helpful online community get more and more important.

    (defun sql-find-sqli-buffer ()
      "Return the current default SQLi buffer or nil.
    In order to qualify, the SQLi buffer must be alive,
    be in `sql-interactive-mode' and have a process."
      (let ((default-buffer (default-value 'sql-buffer)))
        (if (and (buffer-live-p default-buffer)
                 (get-buffer-process default-buffer))
            default-buffer
          (save-excursion
            (let ((buflist (buffer-list))
                  (found))
              (while (not (or (null buflist)
                              found))
                (let ((candidate (car buflist)))
                  (set-buffer candidate)
                  (if (and (equal major-mode 'sql-interactive-mode)
                           (get-buffer-process candidate))
                      (setq found candidate))
                  (setq buflist (cdr buflist))))
              found)))))

Scheme

As I got better at writing elisp, I got interested in other Lisp dialects. And I stumbled upon Scheme. The language specification is easy to read and only 50 pages long. And the book Structure and Interpretation of Computer Programs by Harold Abelson and Gerald Jay Sussman with Julie Sussman is just unbelievable. Elegant. Powerful. Mind-boggling. I am running out of words. They start out by showing how objects can be represented by procedures. They show how infinite lists (streams) can be used in modelling infinite sums. Symbolic differentiation. Implementing an evaluator of Scheme in Scheme itself.

In this case, the language being implemented and the implementation language are the same. Contemplation of the meaning of true? here yields expansion of consciousness without the abuse of substance. --Abelson and Sussman

The SICP book is available online:

Scheme and the SICP book taught me functional programming, the elegance of recursion, the importance of tail-recursion, and what it means to be a first order object. The examples in the book showing how to elegantly implement simple objects including a message passing system using nothing but bare Scheme truly helped me better understand object orientation. It turns out that object orientation is a great mechanism to structure code, to reduce complex problems into subproblems, and to make sure that the code shows how you have decomposed and solved the original problem.

    (define (world turn regions)
      (define (find thing predicate)
        (find-in regions thing predicate))
      (define (dispatch m)
        (cond ((eq? m 'find)
               find)
              (else (error "world: unknown request:"
                           m))))
      dispatch)

Take a look at the VisualBasicVsScheme page.

Common Lisp

To me, Scheme has one drawback: There is practically no library. You have to code everything yourself. In that, it basically remains a language geared towards teaching instead of producing. Unless you commit yourself to a Scheme dialect with many extensions, such as Guile.

Common Lisp is different. It has a huge library. Now all I need is a project to verify that Lisp is indeed superior to Java. ^_^

Other Languages

I also speak German, English, French, and Portuguese.

Deutsch ist meine Muttersprache. Hier i de Schwiiz red ich aber meischtens Schwiizerdütsch. Mon Français n'est pas très bon car il n'y a presque personne avec qui je puisse pratiquer. E do meu Português não vamos falar porque bem que posso compreender quase tudo, dou demasiados erros à escrever.


SiteMap / AllPages / Out / kensanata@gmail.com / Last change: 2001-09-23