Posts Tagged ‘programming’

What you need to be a programmer

2015-03-09

You need, above all others:

1) to have dogged persistence in the face of failure.

2) to celebrate the utterly ordinary.

On 1. There is a reason why FAIL Blog is a thing. Failure represents 99% of what programmers do. Programmers do not sit down and write flawless code that works first time. We make mistakes. The compiler complains. The tests fail. It stops when something unexpected happens. Each failure requires the programmer to work out why it failed, fix it, and carry on. I’m talking about failures at every level from the “missing comma” and “expected string not int” type errors, through intermediate errors like using feet instead of metres, or using 100GB of RAM instead of 1GB, to higher level errors like designing a mobile phone app instead of a website.

Some people just cannot do this. They will type in their program, and it will fail to compile or run because of a missing comma or something like that, and they will just stop, and go and make a bacon butty instead. This is perfectly understandable.

Personally, as a programmer, it sometimes feels like it’s not that I want the program to run correctly, it’s that I have a curse where I cannot prevent myself from investigating every last failure and fixing it.

When programming, failure is entirely normal. It takes a certain personality type to be able to cope with this, several times a day.

On 2. The flip side is that when programmers succeed, most of the time we succeed in something entirely ordinary. We have calculated the amount of VAT correctly. We have displayed the user’s email address on the page correctly. Things that are entirely trivial and obviously should Just Work take sufficient effort, and involve overcoming several failures, that just achieving the entirely ordinary seems like it deserves a celebration.

Clearly it is not normal for someone to celebrate the fact that as a result of typing stuff into the CSS file, the dotted border between the header of a table and the next row now displays correctly. So remote are programmers from the rich celebrations that life has to offer that we have to make our own.

There is a horrific irony to all this. Computers only do what they are programmed to do. But it is incredibly difficult to program them (correctly). What they are programmed to do is only an impression of what we intend them to do. In this case it is like trying to take an impression of a fossil with only wet tissue. So, on the one hand everything a computer does it has been programmed to do, on the other it is a monumentally difficult task to get the computer to do anything at all that is useful and correct.

Lovelace grasps this subtle point: “It can do whatever we know how to order it to perform”. It’s the “know how” that’s the tricky bit.

Go bug my cat!

2015-02-06

Partly related to Francis Irving’s promise to avoid C, and partly related to the drinking at the recent PythonNW social, I wrote a version of /bin/cat in Go.

So far so good. It’s quite short.

The core loop has a curious feature:

for _, f := range args {
	func() {
		in, err := os.Open(f)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(2)
		}
		defer in.Close()
		io.Copy(os.Stdout, in)
	}()
}

The curious feature I refer to is that inside the loop I created an anonymous function and call it.

The earlier version of cat.go didn’t do that. And it was buggy. It looked like this:

for _, f := range args {
	in, err := os.Open(f)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(2)
	}
	defer in.Close()
	io.Copy(os.Stdout, in)
}

The problem with this is the defer. I’m creating one defer per iteration, and they don’t get run until the end of the function. So they just pile up until main returns. This is bad because each defer is going to close a file. If we try and cat 9999 copies of /dev/null we get this::

drj$ ./cat $(yes /dev/null | sed 9999q)
open /dev/null: too many open files

It fails because on Unix there is a limit to the number of simultaneous open files a process can have. It varies from a few dozen to a couple of thousand. When this version of cat opens too many files, it falls over.

In this case we failed because we ran out of a fairly limited resource, Unix file descriptors. But even without that, each defer allocates a small amount of memory (a closure, for example). So defer in loops requires (generally) a little anonymous function wrapper.

I tried rewriting the loop using a lambda and a tail call (see this git branch), but it doesn’t work. The defers still don’t run promptly. (and the tail call is awkward and I had to declare the loop variable on a separate line from the function itself because the scoping isn’t quite right)

C: return and parentheses

2008-10-02

Please don’t write «return(0);». The parentheses are unnecessary. This request generalises. So the NSIDC should not be writing (on line 90 of cproj.c; some sort of Google codesearch link):

return((cosphi / (sqrt (1.0 - con * con))));

Oh yeah. Gotta love those parentheses; they give a nice warm cuddly feeling and make my expressions feel extra protected.

Program as if you know the language. At least a bit:

return cosphi / sqrt (1.0 - con * con);

There. Isn’t that clearer? More parentheses doesn’t always mean clearer code.