Blog

errno and strings at the cgo border

I wrapped a C function that opens a file. The call itself was easy; deciding where a C string stopped and a Go os.Error began took the rest of the afternoon.

The first useful program was deliberately dull:

package main

/*
#include <fcntl.h>
#include <stdlib.h>

static int open_read_only(const char *name) {
	return open(name, O_RDONLY);
}
*/
import "C"

import (
	"os"
	"unsafe"
)

func open(name string) (int, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	fd, err := C.open_read_only(cname)
	if fd < 0 {
		return -1, err
	}
	return int(fd), nil
}

The comment immediately before import "C" is cgo’s preamble, not decoration. The little C wrapper is necessary because open is variadic and cgo cannot call it directly. C.CString allocates and copies, so the matching C.free stays next to it. The Go string may contain a zero byte, too; a C API will see that as the end of the name. My wrapper rejects such names before this call rather than quietly opening something else.

In a two-result cgo call, cgo captures C’s errno as the os.Error used by this Go snapshot. I test the function’s documented failure result first; a stale nonzero errno after a successful call is not an error. This also keeps C’s zero-terminated error text on the C side of the wrapper rather than exposing a borrowed character pointer to callers.

That translation belongs right here. Returning a bare integer status would make every caller know C’s failure sentinel, when errno is meaningful, and how long the message storage lives. One wrapper is enough bureaucracy.

There are wrinkles beyond this toy. Some functions return errors directly instead of using errno; some return allocated strings that need a library-specific free function; and a successful result can still require cleanup. The C header, not habit, decides each case.

There are practical caveats. The build now needs a C compiler and the library’s headers and linker flags. Types that merely look alike are not automatically interchangeable. Memory allocated by C must be released according to C’s rules, and Go pointers should not be tucked away by C code for later use.

The wrapper is dull now: Go string in, file descriptor or os.Error out. Dull borders are much easier to debug.

“¿Por qué están todos hablando inglés?”

I’ve been spending an insalubrious amount of time on Google +. I managed to plump for a pretty good group to follow and as a consequence I’ve been getting consistently interesting content. As for myself, I mostly I post in English. A couple of days ago, I posted something most inconsequential and it would have been an unreservedly unremarkable post wasn’t it for the fact that it was geolocated in Cordoba, Argentina, which caused it to attract the attention of people nearby. In the middle of the comments, someone asked, in Spanish: “why is everyone speaking English?” That was a fair question and it touched something that has bugged me in the past.

Some part of my brain must miss the good old times of hunting and gathering as I ended up as a nomadic man—albeit one who doesn’t hunt and at most gathers food from grocery stores, so there might be a flaw in my theory. My rootless nature made me move a lot. This and the nature of my work caused me to make friends in several places other than my native Brazil1.

We’ve already established that I communicate in Portuguese. Working at a US-based multinational as well as with open source, I also use English quite a bit—and my aforesaid rootlessness has taken me to inhabit the beautiful state of Oregon in the past. Oh and did I mention I am currently putting in a tour of duty in Argentina?

The Myth of the Tower of Babel

The result of all of this—in blatant contrast with the pre-Tower of Babel times when everybody obviously spoke English—is that I communicate daily in multiple languages. There isn’t a day—well, weekday—I don’t have to speak Spanish, Portuguese, English and French with someone or another. And that is fine and actually quite nice: you do lose languages if you don’t use them. Not like riding a bike, I suppose. Regardless, it is not a problem to communicate 1:1 in those languages. But what about 1:many conversations?

Blogging is a clear example. Should I blog in Portuguese as some keep telling me I should? I cannot reasonably expect my non-Brazilian readers to understand Portuguese. If I write in French, my Quebecer friends will be happy but what about the rest? Nationalistic rants aside, English is an international language nowadays, just as Latin and French once were. Aside from very few people, the vast majority of the people I know can understand English and that’s why I use it most often than any other.

Ideally, one would use their own native language and computer translation would do the rest. Unfortunately we are not there yet. I will admit that computer translation is getting better and better and it is fairly good if you write clear, short sentences. And it will get better. But I am skeptic that we will ever get to the point where the algorithms will be able to deal with subtleties, innuendos and all the puns that make up human interactions.

The way I see, I currently have a few options –

  • I write in Portuguese, as the ever vigilant Brazilian crowd demands it. That would soothe the wrathful nationalists who believe me a Traitor Of The Fatherland™. But it also limits my already limited audience; not good.**
    **

  • I write multiple versions of the same thing in each language. That would begin to feel like actual work, not fun. Also, having tried that in the past, I’ve learned that after I was done with the first version, the others never came out naturally.**
    **

  • I write in English. Sure it makes me a bootlicking lackey of the imperialist Yankees in the eyes of the insecure, but it also helps me reach pretty much everyone I know.**
    **

But using English is not a perfect solution either. For once, I am obviously not a native speaker and thus have an imperfect and narrow vocabulary. As well, I don’t share the cultural experiences that help define the subtleties of English. And finally, there are heaps of topics that just feel wrong in English: such as local—as in Brazilian—topics. It just feels weird.

Back to Google+, I have created Circles for Portuguese and French, but these are not much valuable until Google comes up with some system of set arithmetic that would allow me to say something to the effect of “Post this to members of Circle X who also happen to be members of Circle French.” Until then, English is my best bet.

1 Experience tells me that I am required to point out that we, cheerful Brazilians, speak Portuguese, not Spanish.

(Image Credit: ThomasThomas, Creative Commons)

Godwin’s Law is anything but

I’ve got many gripes with the internet, I’ll admit. One of those is the overuse of Godwin’s Law. Actually, it’s a double offence because not only people overuse it, but this Law is anything but.

But let’s start with the misuse. I posted a while ago to Facebook that I had finished reading The Rise and Fall of the Third Reich and I mentioned how scary it was that a place right in the heart of “civilized” Europe could have fallen to that madness so quickly. A small discussion formed with some people until one of my geek friends commented something to the effect of—

Let’s stop this because Roberto already Godwinned in the original post!

You see, us geeks are good at that: repeating some meme without thinking much about them.

But that’s how I see “Godwin” being used all over the place. A discussion killer. And the discussion did get killed, unfortunately. It’s like Godwin’s Law says “if someone mentions Nazis, the discussion is over” but that’s not what the “law” says—

As an online discussion continues, the probability of a reference or comparison to Hitler or to Nazis approaches 1.

Which is actually true. Just like—

As an online discussion continues, the probability of a reference or comparison to Snow White and the Seven Dwarves approaches 1.

Obviously, as a discussion grows, the probability of referencing anything will approach 1! Here’s Godwin himself back in 2008 about his “law”—

Although deliberately framed as if it were a law of nature or of mathematics, its purpose has always been rhetorical and pedagogical: I wanted folks who glibly compared someone else to Hitler or to Nazis to think a bit harder about the Holocaust.

I find it ironic that his little experiment for making people think harder about the Holocaust is now used as a tool to avoid mentions to it.

You see, I get where Godwin was trying to go. You see glib comparisons with the Nazi all the time and yes, they suck. But going from that to making one of the most defining moments of the last Century completely off-limits is preposterous! Nazi comparisons are often valid and should not be avoided, especially by misusing an old usenet meme.

Again, His Godwinness—

Still, I sometimes have some ambivalence about the Law, which is far beyond my control these days. Like most parents, I’m frequently startled by the unexpected turn my 18-year-old offspring takes. […] When I saw the photographs from Abu Ghraib, for example, I understood instantly the connection between the humiliations inflicted there and the ones the Nazis imposed upon death camp inmates—but I am the one person in the world least able to draw attention to that valid comparison.

Avoiding comparing things to something as defining as Nazi Germany is an arbitrary limitation that makes no sense.

That’s not to say that all Nazi comparisons are valid. There really are plenty of dishonest Nazi comparisons out there, such as this one, by an American governor—

We the people have been told there is no choice. You must buy health insurance or pay the new Gestapo — the IRS.

This because the Supreme Court of the United States had upheld a law that represented the first steps of that country in following the rest of the civilized world in providing its citizens with basic healthcare. Healthcare! Oh the evils of that Gestapo!

But it’s unreasonable to expect people to completely ignore a huge part of our history in hope that dishonest governors won’t make silly comparisons, which they’ll do anyway.

Small Go interfaces

I wanted to test a function that wrote a report without letting the test create files. My first instinct, trained by larger object systems, was to invent a report hierarchy. Go let me stop much earlier.

The function only needs one operation:

type writer interface {
	Write([]byte) (int, os.Error)
}

func report(w writer, name string) os.Error {
	_, err := w.Write([]byte("hello, " + name + "\n"))
	return err
}

A file can satisfy that interface. So can a network connection or a little buffer in a test. None of those types has to announce that it implements writer; the method set is enough.

That last detail was my surprise. I am used to a type naming its interfaces at the type declaration. Here the relationship can be discovered where it is needed. The package containing report can define the narrow interface, even when the concrete type belongs to another package and cannot be edited.

The mechanism is structural. An interface describes a set of methods. A value is assignable to it when its type has those methods with the right signatures. The compiler checks the assignment, so this is not hopeful late binding. Calls through the interface still carry dynamic type information, but the agreement itself needs no explicit declaration.

Pointer methods add one wrinkle. If a method has a pointer receiver, a pointer to the type has that method; the plain value does not. That distinction matters when a method modifies state, and it explains several otherwise puzzling assignment errors.

I now prefer interfaces declared by the code that consumes them, and I keep them as small as the operation permits. A one-method interface is not a toy. It is often a precise seam between a useful function and everything it does not need to know.

The caveat is that an interface should represent behaviour, not merely hide every concrete type on principle. Returning an interface too early can discard useful methods and make code harder to follow. If there is only one implementation and no boundary to protect, the concrete type is frequently clearer.

Here, one method bought a test with no temporary file and no elaborate framework. I will take that trade.