Toward what end, toward what end?

Every reader should ask himself periodically “Toward what end, toward what end?” – but do not ask it too often lest you pass up the fun of programming for the constipation of bittersweet philosophy.

— Harold Abelson and Gerald Jay Sussman with Julie Sussman, Structure and Interpretation of Computer Program (via Peter Hosey)

Source: boredzo.org

Google Go: The Good, the Bad, and the Meh

“Go is not meant to innovate programming theory. It’s meant to innovate programming practice.” — Samuel Tesla

Normally, I just blog about… uh, stuff?… but I feel like writing about the Go programming language (or “Golang”) today, so instead today’s topic is computer stuff. For the record, the language I’ve programmed the most in has been Python, so that’s the perspective I’m analyzing it from.

The Good

One of the best things about Go is that it was clearly designed for working on large projects in a team with a modern version control system.

For example, one of the “controversial"† aspects of Go is that it uses case to specify visibility. Instead of having a system of public, private, and shared class members, visibility is at the level of the package. Lowercase names like var a are visible only from the current package, but uppercase names like var A are publicly visible, and so on for types, functions, struct members, methods, etc. It is blisteringly obvious in hindsight that enforcing visibility at the package level instead of the class level is the right way to do it. Who cares if the other class poking around in your class’s internals is your subclass or whatever? The question is whether it’s part of the same package, in which case, you can be expected to keep the classes in sync since you wrote them both. If it’s in a different package, then the other person wants to know what’s in the public facing "API” of the class. In Python something similar is done with the convention of appending _ to the front of names that are meant to be private, but Go’s convention is simpler and easier. It does take a little bit of time getting used to the idea that in name.Name the first thing is definitely a package name and the second thing may or may not be a type (unlike Python, where classes are usually the only thing with CamelCase names), but once you adjust, it’s fine and leads to better API design. When you write something, if you want someone importing your package to use it, use uppercase. If you want them to leave it alone, lowercase. Done.

† Controversial with [Internet controversialists]. People who complain about this are complainers. Features like this are useful because they let you know who likes to complain about things for no good reason. Go has a lot of features like this. [Edit: Based on comments, I have changed the word “idiots” to “Internet controversialists” in reflection if the fact that you can be a smart person and still love debating the color of the bike shed.]

Another example of Go’s modernity is the decision to make the directory the fundamental unit of packaging. While you can just compile and run an individual file using go run filename.go, Go encourages you to set the environmental variable $GOPATH and then put your projects into $GOPATH/src/projectname/. When you run go install project, it will compile that directory and put the executable into $GOPATH/bin/. Why is this useful? It leads to a couple of nice advantages. First, since it’s done by directory, you can make each package you write its own git (or whatever) repository. Second, if your project file gets too long, you can break it up into multiple files that automatically get stitched into one at compile time. Not a big deal, but nice. Third, there’s no need for something like Python’s virtualenv. If you need to have different versions of the same library installed simultaneously for two different projects, just switch between two different $GOPATHs. Fourth, there’s no question of Python’s relative import headaches. Imports are always either rooted in $GOPATH/src/ or in the built-ins ($GOROOT/src/pkg/).

Fifth, this leads to the convention of using domain names as directory names. So, if you have a github account, you’d store your local stuff in $GOPATH/src/github.com/username/project/. Now, the genius of this is that the go tool has the ability to download from most (all?) modern VCS systems. So, if you run go get github.com/userA/project/ it will use git to download the project from github.com and put it into the right place. Even better, if that project contains the line import "bitbucket.com/userB/library", the go tool can also download and install that library in the right place. So, in one stroke, Go has its own elegant solution to packaging and a modern, decentralized version of CPAN or PyPI: the VCS you were already using!

Deployment in Go is very easy too, since everything compiles down to a single binary. It’s practical to cross-compile things, so that you don’t have to install anything Go-related on your production server except the one binary you compiled on your development machine. That greatly simplifies the issue of library management.

The go tool in general can’t be praised enough. It compiles quickly (sorry XKCD fans), and it comes with a couple of awesome features. First, go fmt. Gofmt is also “controversial” with [Internet controversialists]. It’s great. It automatically makes your code line up with the Go standard. Some people complain that the standard doesn’t put the braces where they want them. Those people are why we need gofmt. Gofmt basically does for Go what syntactic whitespace does for Python: it makes sure that the average code you run into is written to be readable.

Second, go doc. Godoc autogenerates documentation based on the comments in your code. Since Go is a compiled language, I tend to treat it as a replacement for using help(whatever) at the REPL in Python. It works well. It only tells you about exported things (things with Uppercase names), but that’s all you should need to know if the API works. It has a couple of modes for giving you the docs, the most helpful of which is a local webserver that gives you the docs for everything you have installed in your current $GOPATH.

Third, go test. It’s a built in testing and benchmarking framework. It’s not mind blowing, but it works.

At this point, I suppose I should say something about the Go language itself. What I like about Go is that it is very readable. Let’s say I want to declare a pointer to a variable length array (what Python calls a list and Go calls a slice) of pointers to FooType objects:

var foo *[]*FooType

It reads very simply, left-to-right: “Variable ‘foo’ is a pointer to a 'slice’ of pointers to FooType objects.” From the perspective of languages in the C-Java continuum, this is backwards, since the type follows the variable name, but once you get used to it it makes much more sense than vice versa. Functions also read very naturally:

func Foo(x int, y *Bar) error { ... }

“Function foo takes x, an int, and y, a pointer to a Bar, and returns an error (or a nil of type error).”

Of course, the two big pains of static typing are that sometimes you have to write out the type stuff even when it’s obvious what it has to be and that sometimes you just can’t easily do what you want to do. Fortunately, Go has basic type inference, so the first problem is not as big of problem. The := operator is used when you want the compiler to just figure out the type stuff for itself. So, in err := Foo(1, &Bar{}), the compiler knows that I want err to be of type error, since that’s the type that function Foo returns. Similarly, the second problem can be routed around by using the universal type interface {} and the runtime reflection tools. Throw in a broad enough interface and the compiler will usually just shut up and let you shoot yourself in the foot if you really need to. (But see also my complaint about generics in the “Bad” section below.)

Go also has a simpler solution to the whole nonlocal headache in Python. Since Python doesn’t have a way to declare a variable apart from giving it a value with =, there’s a question of what you want to do in the case of a closure: how do you know which variables to initialize and which not? The Python solution of nonlocal is inelegant, but Go’s closures are straightforward. Adding := would be a great simplification for Python 4000, but based on what I’ve read in the mailing lists, it’ll never happen.

Here’s a complete Go solution to Paul Graham’s Accumulator Generator Challenge:

package main

import "fmt"

func accgen(n int) func(int) int {
    return func(i int) int {
        n += i
        return n
    }
}

func main() {
    f := accgen(0)
    fmt.Println(f(1), f(1), f(1)) //Prints 1, 2, 3
}

The static typing adds a little noise, but it makes sense if you read it out loud: “Function accgen takes an int n and returns a function that takes an int and returns an int.” It can be confusing, but no more so than the concept of an accumulator in the first place.

Incidentally, another nice feature of Go is the Go Playground linked to above. It’s a combination of pastebin and a sandbox, and it helps ease the pain of not having a REPL. If you wonder, “Will this work in Go?” you can write a quick proof of concept on the Playground, run it (on Google’s server, which means it works on an iPad or whatever), then press “Format” to pretty it up and “Share” to generate a link to it.

In general, I really like the attitude that Go’s designers have towards the type system. For example, they straightened out the confusing mess of longs and shorts that had accumulated over thirty years with straightforward names: int8, int16, int32, and int64. There are also unsigned variants (uint8, etc.). By itself, int is 32-bits on most systems now, but they plan to change it to be 64-bits in future versions. Go also makes it easy to use the type system to do rudimentary sanity checks. For example, you can easily define a type like this:

type celsius float64

And then you can write your functions so that they only take celsius and not fahrenheit temperatures.

Or if you want a simple options bit-flag, you can do something like this:

package main

import "fmt"

type BFlag uint8

const (
    Grapes BFlag = 1 << iota
    Apples
    Bananas
    Mangos
)

func OrderBreakfast(flag BFlag) {
    if flag&Apples != 0 {
        fmt.Println("Apples it is!")
    } else {
        fmt.Println("All we had was apples.")
    }
}

func main() {
    f := Grapes | Apples | Bananas
    OrderBreakfast(f)
}

iota is a semi-magical variable for use in constant declarations that goes up by one each time. Since the other fruits are in the same constant declaration block but don’t have anything declared, Go automatically gives them the same type and assignment as the first constant (BFlag and 1 << iota), so Grapes is 0001, Apples is 0010, Bananas is 0100, and Mangos is 1000. The bit flag is simple enough, but since BFlag is its own type, you don’t have worry about someone accidentally sending a number to OrderBreakfast that’s just the result of adding up the tabs or something.

The designers of Go agree with the collective experience of the last twenty years of programming that there are three basic data types a modern language needs to provide as built-ins: Unicode strings, variable length arrays (called “slices” in Go), and hash tables (called “maps”). Languages that don’t provide those types at a syntax level cannot be called modern anymore. (And what’s up with all the languages that claim all you need are linked lists? I’m sorry, this is not 1958, and you are not John McCarthy.) Go strings are UTF-8 because Go was designed by the guys who invented UTF-8, so why not?

The designers of Go also seem to have come to the conclusion that object oriented programming had some good ideas but was mostly overblown. So, they don’t provide inheritance. (!) But before you freak out, however, they do provide embedding and interfaces, which make it possible to do most of the stuff you would want to do with inheritance anyway. I think at this point, it’s well accepted that multiple inheritance was mostly a headache for little payoff, so Go just takes that insight to the next level. If you just want to copy the behavior of a class with a few overrides, it’s pretty simple.

Here’s an example that illustrates what I mean:

package main

import "fmt"

type FooBaz interface {
    Foo()
    Baz()
}

First I declare the FooBaz interface. Something is a FooBaz if it can Foo() and Baz(). Note that this is basically statically compiled duck-typing. All you need to do is have these methods and you’re in. There’s no need to declare that you implement FooBaz beyond just implementing it.

type A struct{}

func (a A) Foo() {
    fmt.Println("I'm an A! Foo.")
}

func (a A) Baz() {
    fmt.Println("I'm an A! Baz.")
}

Next I declare the A type. Just for simplicity, I make it an empty struct. Then I give A two methods, Foo and Baz. The way you add a method to a type is like a function declaration, except that before the function name (method name), you put the type in parentheses as well as a name for the receiver (like this or self in other languages). Unlike Python’s convention of always using self, idiomatic Go doesn’t always use the same receiver name, but instead the receiver name tends to be based on the type’s name. In this case, my receiver name is a, but I never use it (and type A is an empty struct anyway, so I can’t modify its instances), so it doesn’t really matter. Because methods are treated basically like functions with the privilege of overloading the type of the first argument (Go doesn’t allow other forms of overloading), Go lets you put method names wherever you want, as long as its in the same package as the type its the method of.

type B struct {
    A
}

func (b B) Baz() {
    fmt.Println("I'm a B! Baz.")
    fmt.Println("I'm also an A!?")
    b.A.Baz()
}

Here’s where it starts to get interesting. B is a struct with an A embedded in it. That means when you call a B object with .Foo that call gets passed into the A that the B is holding, since there is no B.Foo method. On the other hand, since there is a B.Baz method, it calls that when you do .Baz() on the object. The Baz method then calls the A in itself (like a superclass call in inheritance languages). Of course, this isn’t required, but I just do it to show that you can.

func FooAndBaz(f FooBaz) {
    fmt.Println("Calling!")
    f.Foo()
    f.Baz()
}

func main() {
    var a A
    var b B
    FooAndBaz(a)
    FooAndBaz(b)
}

Finally, we have a function that takes anything that fulfills the FooBaz interface, so I send it a and b which are of types A and B. The final output is:

Calling!
I'm an A! Foo.
I'm an A! Baz.
Calling!
I'm an A! Foo.
I'm a B! Baz.
I'm also an A!?
I'm an A! Baz.

This doesn’t have all the complexity and nuances of a true inheritance system… And that’s a good thing! If you’re just trying to override a couple of methods, it’s easy to do and easy to understand. If you want the nuance and complexity of a traditional OO inheritance system, you can specify exactly what you want it to do yourself.

Interfaces are one of the key features of Go. As I said before, it’s basically compile time duck typing. As long as you have walk and quack methods with the right signatures, good enough.

The final good thing to mention about Go is the concurrency. It works like you thought concurrency should work before you learned about concurrency. It’s nice. You don’t have to think about it too much. If you want to run a function concurrently, just do go function(arguments). If you want to communicate with the function, you can use channels, which are synchronous by default, meaning they pause execution until both sides are ready.

A simple example:

package main

import "fmt"

func printer(ch chan int, done chan struct{}) {
    for i := range ch {
        fmt.Println(i)
    }
    done <- struct{}{}
}

func main() {
    ch := make(chan int)
    done := make(chan struct{})
    go printer(ch, done)
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)
    <-done
}

The printer function prints the values it receives from a channel of ints. The main function spawns the printer as its own goroutine (green thread, basically) then sends it some work. There’s some nuances to this (for example, in this case, 2 won’t finish sending until the printer is ready for it), but again, it basically works like you think it should. It makes it fairly simple to get things go concurrently and/or in parallel without ripping your hair out. Since execution halts when the main function is complete, I threw in the done channel as a quick and dirty way to make sure that everything gets printed before the program ends. You could also use a sync.WaitGroup in a more realistic example.

The Bad

Those are the things I like about Go. What do I dislike?

This is just a small thing, but for some reason, Go doesn’t suppose the use of a #! on the starting line, which means you can’t just use uncompiled files as utility scripts.

In general, I think that Go tends not to be very DRY. Go is meant to make performance issues pretty obvious, so it doesn’t have a lot of sugar for things. Where this especially shows up is in the lack of generics. Idiomatic Go code has a couple of different tricks for using interfaces so that you don’t need generics… but sometimes you just have to bite the bullet and copy-and-paste a function three times so you have three differently typed versions of it. If you’re trying to make your own data structure, you can just use interface {} as a universal object type, but then you lose compile time type safety. If you want to make a universal sum function, on the other hand, there’s no really good way to do it. Probably the easiest thing is to add a header like type MyNum int32 at the top, write your functions to take MyNums, and then if you later decide to use a float instead, at least you don’t have to rewrite the type of all of your functions, but that’s not as convenient as real generics.

Along the same lines, Go can be a little too low level in spots. For example, while it has a string type and all of the same ways of manipulating strings as Python, in Go (like in really old versions of Python), these are functions in the strings package instead of just being methods on string objects. I guess they do this for performance/memory reasons,‡ but it seems chintzy to me.

‡ People sometimes complain that a basic “Hello World!” program in Go is too large (like 2MB or something, IIRC), but that’s because it statically compiles in the fmt package, which has Unicode support. If all strings required the equivalent of the strings package, Hello World would be even bigger.

Finally, Go is still a new language, which sometimes means that library you need hasn’t been implemented yet or it’s still too immature for practical use. Fortunately, this problem is rapidly solving itself.

The Meh

What am I passionately neutral about in Go?

Some people get very worked up about how Go “doesn’t have exceptions.” First of all, this is untrue. Go has panic, which works almost exactly like an exception. However, idiomatic Go code isn’t supposed to use panic for expected exceptions. Instead you’re supposed to return an error-type object along with your normal return type using multiple return values. In practice, Go’s error handling system is basically the same as Java’s. panic is like an unchecked exception: divide by zero in the wrong place and the whole stack blows up on you. error objects are like checked exceptions: if something you call returns an error you either have to ignore the error entirely (bad), do something about it (good), or pass the buck to someone else (neutral). The only difference is that these response are respectively written as

//Ignore
value, _ = package.MightReturnAnError()

//Deal with it
value, err = package.MightReturnAnError()
if err != nil {
    do something 
    ...
}

//Pass the buck
value, err = package.MightReturnAnError()
if err != nil { return nil, err }

instead of being written in terms of try and catch or except. I do wish the compiler was a little stricter though. It’s perfectly legal to write

fmt.Println("Hello")

even though Println returns an integer and an error. I sort of wish they made you explicitly silence the error by writing _, _ = fmt.Println("Hello") instead. Then again, maybe that would be a pain? On top of that, since basically everything returns errors of the interface type error, it can sometimes be a little hard to figure out exactly which concrete errors something will return. For example, the documentation on fmt.Println says “It returns the number of bytes written and any write error encountered.” OK, but which exact errors should I be prepared to deal with?

That brings me to my next bit of neutralness: the Go compiler has no warnings, only errors. Now, obviously, this is The Right Thing to Do. We all know that a compiler warning ought to be treated like an error, and ignoring warnings is wrong, and it’s better for the compiler to just force you to fix it than for it to enable you to do the wrong thing. …But sometimes you really want to do the wrong thing anyway. The other day there was a big stink online about how the Go compiler won’t let you have any unused variables or unused imports. Technically speaking, this isn’t true. If you just throw in some _, the compiler will shut up and let you import stuff you don’t use or create variables and never use them. On the other hand, it is kind of annoying having to shut up the compiler when you’re just hacking things out. On the third hand though, the temptation to do things the wrong way is exactly why the compiler shouldn’t let you do things the wrong way “just for now.” So, in the end (on my fourth hand), I’m pretty neutral about it.

Finally, Go doesn’t have operator overloading, function/method overloading, or keyword arguments. You can see why—those features are bad for performance and they lead to “clever” code that does bad things—but you also sometimes miss them. It’s a tradeoff, and I see why they made the choice they did, but I also see the value of the other choice.

Conclusion

Go is rad. It’s not my everyday language (that’s still Python), but it’s definitely a fun language to use, and one that would be great for doing big projects in. If you’re interested in learning about Go, I recommend doing the tour then reading the spec while you put test programs into the Playground. The spec is very short and quite readable, so it’s great way to learn Go.

Iwata Asks - Producers of the Wii U Miiverse

Mizuki
When you hear the phrase "real life social graph," you might think it includes all real human relationships, but if you really think about it, real life doesn't only include actual acquaintances. That's because you also interact with strangers a lot in the real world.
Kondo
Yes. Also—especially on America's social networks—I feel like there is an idea that you should have one personality. But the reality is different.
Mizuki
Yeah, that's right!
Iwata
An American friend of mine said, "On the Internet, people are always watching, so you have to be consistent about what kind of a person you are, so it's difficult to let loose even in private time". In that respect, we all live in a visible world because of how common social networks have become. While that world may be convenient, it can also be constraining in ways that didn't exist before.
Mizuki
I understand. You punch in bland comments like "Happy Birthday!" without a thought. (laughs)
Kondo
Right, right! (laughs) But I think that such variety—having a self who interacts with friends and a self within video games—is good.
Iwata
I suppose a lot of people hit the OFF switch when they don't have to interact with real life acquaintances and assume different personalities.
Mizuki
For that reason, there is a trend among social networks that you must use your real name. The Miiverse, however, doesn't specify that. You can simply display your Mii nickname.
Iwata
While it's extremely rare, communities can break down because of rude people taking advantage of anonymity. Using real names is a way to put the brakes on that, but if you are tied together by empathy, I feel like real names become less important. I think it is important to be tied together by shared sentiment that way.
Mizuki
Yes.

Source: iwataasks.nintendo.com

XOXCO - Is it time for password-less login?

XOXCO - Is it time for password-less login?

Via Marco Arment:

Combined with @lukew’s suggestion of pre-populating the username field, this design would allow existing users to login with only a few clicks and no typing — select an account from a list, click a link, and they’re done. For users who do not already have an account, the process is the same - they will type only their email address, and receive a link via email. This email logs them in and validates the email in one fell swoop.

The web as currently ‘designed’ puts all the weight of security on its weakest link: users. Users are never going to get any better at selecting or remembering good passwords, so web designers should try as much as possible to remove this burden from the shoulders of users.

The more you focus on control, the more likely you’re working on a project of relatively minor value.

My early metrics book, Controlling Software Projects: Management, Measurement, and Estimation (Prentice Hall/Yourdon Press, 1982), played a role in the way many budding software engineers quantified work and planned their projects. […] The book’s most quoted line is its first sentence: “You can’t control what you can’t measure.” This line contains a real truth, but I’ve become increasingly uncomfortable with my use of it.

Implicit in the quote (and indeed in the book’s title) is that control is an important aspect, maybe the most important, of any software project. But it isn’t. Many projects have proceeded without much control but managed to produce wonderful products such as Google Earth or Wikipedia.

To understand control’s real role, you need to distinguish between two drastically different kinds of projects:

  • Project A will eventually cost about a million dollars and produce value of around $1.1 million.

  • Project B will eventually cost about a million dollars and produce value of more than $50 million.

What’s immediately apparent is that control is really important for Project A but almost not at all important for Project B. This leads us to the odd conclusion that strict control is something that matters a lot on relatively useless projects and much less on useful projects. It suggests that the more you focus on control, the more likely you’re working on a project that’s striving to deliver something of relatively minor value.

— Tom DeMarco via plasmasturm.org, which is consistently the most Daoist programming link blog I subscribe to.

Source: www2.computer.org

The programmer, like the poet, works only slightly removed from pure thought-stuff.

The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds castles in the air, from air, creating by exertion of the imagination. Few media of creation are so flexible, so easy to polish and rework, so readily capable of realizing grand conceptual structures. […]

Yet the program construct, unlike the poet’s words, is real in the sense that it moves and works, producing visible outputs separate from the construct itself. It prints results, draws pictures, produces sounds, moves arms. The magic of myth and legend has come true in our time. One types the correct incantation on a keyboard, and a display screen comes to life, showing things that never were nor could be.

[…]

Not all is delight, however […] One must perform perfectly. The computer resembles the magic of legend in this respect, too. If one character, one pause, of the incantation is not strictly in proper form, the magic doesn’t work. Human beings are not accustomed to being perfect, and few areas of human activity demand it.

— Fred Brooks, The Mythical Man-Month (via plasmasturm)

Source: amazon.com

A New, Noisier Way of Writing

Writers, like everyone else, relish feedback. But many will tell you that their art requires sequestration from feedback, for a time, to go into the creative wilds and let their minds roam freely — and then, when it’s time, return to the world and be judged. With no judgment at all, their art would die. But with always-on judgment, it may never reach the status of art.

Anand Giridharadas - A New, Noisier Way of Writing (Oh, internet: you’re the cause of–and solution to–all of life’s problems…)

Source: The New York Times

Iwata Asks Risa Tabata

Iwata Asks - Metroid Prime 3: Corruption

A really fascinating Iwata Asks that was never translated by NOA. The ostensible reason for it not being translated is that the interview was conducted for the Japanese launch of Metroid, hence too late to help its US sales, but I think the gender politics of the interview also played a role in its being shelved. It’s interesting to see how Nintendo is nurturing young female game designers in order to broaden the appeal of its products, even if that effort can come off as patronizing at times.

Here’s Iwata to Risa Tabata, female designer:

Iwata: I remember being really surprised when I saw you demoing the game for us. You looked really splendid defeating enemies one after another with the Wii Remote and Nunchuk.

Would he say that to a dude? Probably not.

Another interesting exchange:

Iwata: If I recall correctly, you were originally hired to do office work and were quite surprised when you were assigned to the game development section instead.

Tabata: I was surprised. In college, my major was Chinese. Because I was originally a humanities student, I believed that even if I was hired by Nintendo, it was 100% certain that it would only be for office work. Nevertheless, when they announced, “Tabata-san will be assigned to Entertainment Analysis & Development,” I remember feeling extremely confused, wondering, “What kind of post is that exactly?” That was because I had only prepared myself for the possibility of office work, and therefore hadn’t really listened to their explanation about EAD during the orientation for new company employees. (Laughs)

Iwata: You weren’t the type to be totally addicted to games to begin with, and you didn’t join the company hoping to make games yourself, either. Of all things, you were assigned to work on the Metroid Prime series. And now, after entering the company, you’ve been involved with this strand of software for more than seven years. This seems like quite the quirk of fate. Life can be quite interesting, don’t you agree?

So, she thought she’d be an OL, but instead she helped make Metroid? Interesting…

Source: metroid-database.com

The Atlantic - Mind vs. Machine

The Atlantic - Mind vs. Machine

Interesting article about the Loebner Prize, a Turing Test competition. The author tried his best to be named “the Most Human Human” by increasing his interactivity: it’s not about saying one or two interesting things, it’s about creating a thread of conversation that’s logical and reactive to the interlocutor.

For instance, Richard Wallace, the three-time Most Human Computer winner, recounts an “AI urban legend” in which

a famous natural language researcher was embarrassed … when it became apparent to his audience of Texas bankers that the robot was consistently responding to the next question he was about to ask … [His] demonstration of natural language understanding … was in reality nothing but a simple script.

The moral of the story: no demonstration is ever sufficient. Only interaction will do. In the 1997 contest, one judge gets taken for a ride by Catherine, waxing political and really engaging in the topical conversation “she” has been programmed to lead about the Clintons and Whitewater. In fact, everything is going swimmingly until the very end, when the judge signs off:

We so often think of intelligence, of AI, in terms of sophistication, or complexity of behavior. But in so many cases, it’s impossible to say much with certainty about the program itself, because any number of different pieces of software—of wildly varying levels of “intelligence”—could have produced that behavior.

No, I think sophistication, complexity of behavior, is not it at all. For instance, you can’t judge the intelligence of an orator by the eloquence of his prepared remarks; you must wait until the Q&A and see how he fields questions. The computation theorist Hava Siegelmann once described intelligence as “a kind of sensitivity to things.” These Turing Test programs that hold forth may produce interesting output, but they’re rigid and inflexible. They are, in other words, insensitive—occasionally fascinating talkers that cannot listen.

I’m working on revising an old paper of mine about Daoism and computers, and one concept I’m trying to suss out is “appropriateness.” Reason lets us do what’s appropriate for the moment by taking everything into consideration, not just what a narrow algorithm specifies.