Wednesday, February 17, 2010

Coding in C++, or Why I like Python

I've been working on converting my cellular automata program from Python
using pygame to C++ using SDL. Now I remember why I like Python so much more than C++.

Admittedly, my C++ is rusty. I studied C++ back in the days of #include <iostream.h>, and I liked it so much that as soon as class was over, I started looking for another language to hack in. Almost anything else. Seriously. While I was away, I missed the whole namespace thing, which was just waiting to bite me.  I flirted with Java, but it reminds me way too much of C++. (I found Java to be kind of like C++, only slower and without pointers. I realize that some will take issue with the "slower" label, but that was my experience.) Then I turned to the Dark Side and used Visual Basic for a while, because I was running windows anyway on my fully operational Death Star computer. Eventually. I came to my senses and repented my sins, and switched to freeBASIC, and Ubuntu Linux, which are both pretty darn good.

Then I decided I needed to stop coding in BASIC. Cold turkey. Why? I'm not really sure. Possible reasons include:
  • My Commodore 64 is long gone. (True, but freeBasic is a long way from C64 BASIC. A very, very long way.) 
     

    (Photo by:  Bill Bertram)

    • BASIC programmers get no respect. (True that.)
      • BASIC programmers are brain dead. (OK, I am brain dead by design, not because my first programming language was BASIC. This must be a feature, and not a bug. For the record, my first programming language was FORTRAN.  I hacked code using an IBM keypunch at Oakton Community College, back when OCC was located at Oakton & Nagle. Let me tell you, IBM manufactured a solid keypunch. Hanging chad was not a problem.) 
      • There's something better out there? (Maybe. I still don't know.)
      • It's lonely out there, in BASIC but-not-Visual-Basic land. Most of the kids are playing somewhere else. Who can you plagiarize learn from? 
      • The prolix syntax of BASIC was giving me writer's cramp.

      I'm still not exactly sure why I left freeBASIC behind; I do remember that I wasn't happy with it. The grass must be greener on the other side, right? For whatever frivolous reason, I decided that I needed a new formal language, stat. I looked around, and decided on Python. I'm pretty happy with it. It's easy peasy, clean, and it generally runs fast enough. There are many people out there to learn from, although some of them speak in tongues.

      So why the return to C++?

      Well, pygame is using SDL to do its magic, and to better understand pygame I want to learn more about SDL, which "is written in C, but works with C++ natively." [1] I want to learn more about making pretty moving pictures and sound on my computer, and I want to be a bit closer to the hardware. I will be doing that, for now, using Simple DirectMedia Layer (SDL). It looks like C++ will help me with that, so it's time for me to re-confront the beast.  


      (I'm not in the mood for doing C right now, thank you very much. I did study C in my night school career. I have even written a linked list in C. I don't feel the need to do it again, unless absolutely necessary. C++ means never having to implement another list ADT again, ever.)

      The story so far:

      Once I got over the whole "now it's
      #include <iostream>
      using namespace std;
      thing" I ran smack into the I can't believe that I have forgotten the whole concept of "pass by value" vs " pass by reference" thing. How could I have forgotten what a big, fat, hairy deal it was to write beautiful code in C++? This here is one very good reason to like Python.

      In Python, if you want to pass a list to a function, you just pass the list (which is an object)  to the function. If you want to return the list after the function is done with it, you can return the list (which is still the same object, only possibly somewhat changed) from the function. This appears to be passing by reference. This makes sense, because generally you would not want to deep copy a list, which is what you would have to do to pass a list by value.  If you want to pass a 2D array to a function, well, you do the same as you would with the list, because a 2D array in Python is a list of lists.  (Unless you're using numpy. Then a 2D array is... I dunno. Beats me.) No worries, and best of all, automagically handled.

      Mind you, you have to remember which Python objects are immutable and which are mutable, but that's about it.

      For example, the Python version has this function, which updates a 2D "array" (actually, a list of lists) named "ca_matrix". I can easily pass the ca_matrix object to the function, and even easily pass it to yet another function, cellNextgen.

      def updateCA_MATRIX(ca_matrix, ruleset, mode):
          global COLS, ROWS
          tarray = makeCA_MATRIX()
          for row in range(ROWS):
              for col in range(COLS):
                  tarray[row][col] = cellNextgen(row, col, ca_matrix, ruleset, mode)
          return tarray 


      Note that I cannot change ca_matrix here because I need it unchanged to calculate the next generation's ca_matix. If you want to, you can easily pass a list to a function, modify it and the changes will be in the scope of the calling function. For example, in Python 2.6.4:

      #! /usr/bin/env python

      def change_list(s):
          s[0] = 2*s[0]

      s = [1,2,3,4]
      print s

      change_list(s)

      print s
      Gives the following output:
      [1, 2, 3, 4]
      [2, 2, 3, 4]
      No worries, just code it.

      In the C programming language, there are no lists, unless you roll your own list type. If you ever take a decent class in C programming, the teacher will make you do so. In C++, there are these list-like things called vectors , as well as lists and some various other "containers". (Alas, none of them contain beer.) You just have to learn how to use and abuse them. They seem useful.

      For the truely brave, you can also roll your list type, just like in C. Initially, I opted for vectors and a C style 2D array... and I should have been using just vectors. For the record, it was great sport, sorting out how to pass a an array by reference in C++. Now that I know how, they are gone from my code. I don't think they'll be back again, at least in my C++ stuff.

      The simple truth is that in C++ you should use C++ code, not C code; you must learn not only when you want to pass by value or pass by reference but also how to pass by value or pass by reference. C++ compilers are finicky. In Python this stuff is just not a problem.

      The C++ code so far:


      #include <iostream>
      #include <string>
      #include <vector>
      #include <cstdlib>    // for random numbers

      using namespace std;

      // Globals
      const int XRES = 1024;
      const int YRES = 768;
      const int BLOCK_SIZE = 4;
      const int DELTA_T = 250;
      const int FCOLOR = 0x00FF00;
      const int BCOLOR = 0x000000;
      const int ROWS = YRES / BLOCK_SIZE;
      const int COLS = XRES / BLOCK_SIZE;

      struct point {
              int x;
              int y;
      };

      int randomStart(vector<point> & cells, vector<vector <int> > & world) {
              srand(time(NULL));

              point p;
              int pct;

              for (int row = 0; row < ROWS; ++row)
              {
                  for (int col = 0; col < COLS; ++col)
                  {
                      pct  = rand() % 1000;
                      if (pct < 375)
                      {
                          p.x = col;
                          p.y = row;
                          cells.push_back(p);
                          world[row][col] = 1;
                      }
                      else
                      {
                          world[row][col] = 0;
                      }
                  }
              }

              cout << "During randomStart: cells.size() = " << cells.size() << endl;
          cout << "done randomStart" << endl;

          return 0;
      }
      Initially I used a vector and an array of arrays. I lost the array of arrays because arrays are are evil. I should have been using a vector of vectors instead of a C++ array of arrays. This is especially true because figuring out how to pass a 2D array to a function in C++ was painful. (References: http://www.parashift.com/c++-faq-lite/containers.html#faq-34.1, http://bytes.com/topic/c/answers/61931-passing-array-function-reference-pointers) 

      Initially I used #define for magic global values when I should have been using const. I fixed that.
          The idea here is to write C++ code using C++, not C. My goal is to write good Python code using the best Python practices; to write good C++ code using the best C++ practices.

          I'm still working on it.

          Notes:
          [1] http://www.libsdl.org/








          No comments:

          Post a Comment