Tuesday, January 13, 2009

Why I hate programming

There are generally two approaches to programming: The first approach (which is highly recommended) involves having a mental model of what the code will do, for which the only bugs that appear will be mistakes in typing, or algorithmic errors. These two types of errors are fairly easily distinguished, especially since typing mistakes usually pop up as errors during compiling.

The second approach involves writing code in very short sections at a time, and then fixing any bugs that may appear during compiling or running. One of the main problems is simply that bugs may be due either because a bit of code didn't do what you wanted it to do OR your algorithm was incorrect, in which case major pieces of code need to be rewritten. Another problem is simply that this method is extremely tedious. It is analogous to solving algebraic equations through trial-and-error. Sure it works, even if you don't know algebra, but ultimately we end up teaching everyone algebra.

This analogy also gets at the heart of the difficulty with the first approach: in addition to requiring would-be programmers to learn a language's syntax, they must also have a good (i.e. accurate!) mental model of how the language works. Once this model has been internalized, developing code becomes simpler and straightforward.

The problem I have with certain programming languages is that sometimes they do some things that are non-intuitive to me. Consider the following bit of code in Matlab:

A = ones(3, 5);

which creates a matrix of 1's with 3 rows and 5 columns (yes, it's silly, but bear with me.) Now, consider a slight variation on the code:

B = ones(3);

My initial mental conversation for what this code does might go something like this: "well, in the first example, we gave two arguments and got a two-dimensional matrix, so it makes sense that in this example, with only one argument, we should probably get a one-dimensional matrix. Since the first argument in the first example dictated the number of rows, B should have 3 rows, and be a column vector."

"Hah," Matlab says, "you expected a column vector, but instead, I'm going to give you a square matrix, with 3 rows and 3 columns."

To which I respond, WTF. If I wanted a 3x3 matrix, I could have just as easily called ones(3, 3); BUT, for some reason, probably historical, "people" expect ones(3) to return a square matrix rather than a vector, so that's what Matlab is going to give you. If you actually DID want a vector, you would use ones(3, 1) or ones(1, 3) depending upon your preference for rows vs. columns.

I should note that Matlab does indeed support 3-dimensional matrices:

C = ones(3, 5, 4)

which is equivalent to 4 3x5 matrices stacked on top of each other. When you need two dimensions, you don't need to specify 1 as a third argument, but when you only need one dimension, you DO need to specify 1 as a second argument. Not only is nonintuitive (to me), but it now becomes inconsistent as well.

Now let's take a look at a beautiful R example I just saw today:

x <- 1:10
length(x) # returns 10
length(x) <- 20 # now extends the length of vector x to be 20 elements

First of all, I should mention that R traditionally uses <- as an assignment operator. The introduction mentions that "In most contexts the '=' operator can be used as [an] alternative." It does NOT say that they are equivalent (or why would it say "most contexts"), but it also fails to mention cases where <- and = might work differently. To this, I am left puzzled.

The problem I have with this example is the third line. In the second line, length(x) returned 10, which we can guess intuitively returns the length of the vector x. However, the notation length(x) indicates that length() is a function, NOT a parameter for an object. The usage of a function is fundamentally different from simple value assignment, such as:

y <- 20

In the latter example, y is a variable, and thus is the target of assignment rather than something to be evaluated. A function, on the other hand, is different, because it is, well, a function. Users can write their own functions, with appropriately specified return values. Note that the user-defined functions operate in ONE direction only: arguments are specified, some stuff is done, and sometimes, a value is returned. To have that value then be the target of an assignment completely boggles the mind. In addition, it cannot be done with all functions. For instance, the following code gives an error:

x <- 1:10
sum(x) # returns 55
sum(x) <- 20 # error:
Error in sum(x) <- 20 : could not find function "sum<-"

In fact, the error does tell us something about the internal model for R: the message about "sum<-" not existing suggests that what is actually going on in the first example is that there are two DIFFERENT functions called length, and that "length(x) =" is actually syntactic sugar for some other function called "length<-".

The very nature of syntactic sugar should be to make a language easier to learn/type. However, in this case, it has only made me more confused...

Labels: , ,


Blogger Crow said...

I recently realized that I hate programming as well. Not because of the confusion entirely, but because I have no creativity with programming :P I am no designer of art, nor of programs.

July 1, 2010 at 12:44 AM  

Post a Comment

Subscribe to Post Comments [Atom]

Links to this post:

Create a Link

<< Home