2014-06-22
Things I like about Go
Writing a reasonable sized Go program has wound up giving me a bigger exposure to Go, reinforcing some of my existing views on it and giving me others. Today I want to talk about some nice things that I think Go does, things that make it easier to write code in it than I initially thought it might be. This is an incomplete list and I'm sure I'll find or think of other things in the future.
:=
type inference means that much of my code is free of any particular mention of actual types. Among other things this makes it much less of a pain to change the type of something since far fewer spots will need updating.The one nit I have is that I really wish there was some form of return value type inference. As it stands, every Go function needs to explicitly declare its return type, which can cause a bunch of heartburn if you change a type that gets returned up through a call stack.
- Coming from Python, it's great that strings are generally a really
lightweight thing that you can take subsets of any time you want
to. My Go code makes new strings all the time and in Python all of
them would involve significant memory copying. Byte arrays and
array slices in general have similar properties.
Strings have a bad side but the bad side is subtle and doesn't really apply until you're caring about memory usage (the same applies for slices of byte arrays).
(If you look at Go from a C perspective instead of a Python one, strings are a massive productivity accelerator. Even if you already have a good buffered-strings library you like, simply dealing with it involves a lot of hassle that Go's built in good strings save you from.)
- That the
.
operator can be applied equally to pointers and values, instead of needing C's.
versus->
depending on whether you have an actual struct or a pointer to it. This especially helps with embedded structs and struct pointers, which Go encourages you to use. It also makes pointer-receiving method functions just a bit nicer.(
.
obscures this so much that I recently forgot that my code had a pointer instead of an actual struct and took the address of a pointer. Go's static typing promptly told me that I was trying to assign a**Rule
to something that took a*Rule
.) - The testing package, especially advanced aspects of it like
test coverage. Again this is a
cool thing from a C perspective more than a Python one, although
Go goes out of its way to make it easy to test things.
gofmt
, which doesn't just create a standard style but also saves me work. I can write a sloppily formatted list of constants or whatever and then justgofmt
the file (well, the buffer, in GNU Emacs) and magically everything has been spaced out, lined up right, and so on with no effort on my part.(I could pick nits with some of
gofmt
's choices but it's not worth it. There's no point fighting Go's city hall here, which is of course sort of the point ofgofmt
.)- The fmt
%v
,%+v
, and%#v
verbs, which provide basic data structure introspection for debugging purposes. Even from a Python perspective this is nice; in Python you have to go out of your way to provide a useful debugging representation of a struct equivalent while Go just does it for you. - That the Go people are perfectly prepared to resort to brute
force instead of (excessive) cleverness and thus that when
you read the code in, eg, the standard packages you get inspired
to do the same.
As an example, I'll take how the standard Go templating system for both text/template and html/template does line numbers for errors. Rather than carefully tracking line numbers as it parses its way through a block of text, it simply exposes the absolute position in the block text. If it needs to know the line number of an absolute position, it just counts how many
\n
's there are between the start of the text and the position. This is a marvelously simple brute force approach to the problem and sure, it's inefficient, but generally you don't care about that in a lexer because the only time you want the line number is on a parse error and those are generally both rare and not performance critical.(I trivially extended the approach so that my parser error messages give both the line number and the character position within the line, something that would have taken me a lot of additional work if I'd tried to be clever and efficient.)
I like interfaces but I haven't done enough clever things with them yet to have much to say. They do let me do almost all of the duck typing that I want to do in practice.
The 'switch { case <condition>: .. case <condition2>: ... }
' idiom
is something that I find alternately nice and perhaps questionable
code style. To put it one way, they offer many opportunities to be
quite clever.
(This entry is a bit scattershot because I'm a bit flat today.)
Sidebar: My view on Go strings, Unicode, and UTF-8
On the one hand it's kind of annoying that Go doesn't really have
a 'Unicode string' type, which would represent strings as arrays
of runes so that 'ustr[N]
' was always a Unicode codepoint instead
of possibly part of a UTF-8 sequence the way it is today with Go
strings. Python offers such a type in its Unicode strings and they
have a number of nice properties.
On the other hand, such a type is almost inevitably a lie given the presence of combining characters in Unicode. My understanding is that even with normalization there are codepoint sequences that represent a single logical character, ie there are not precomposed versions of all possible decomposed character combinations. I may be wrong here, but at least the issue is a swamp (and at least requires you to normalize your Unicode text, which is not necessarily a trivial operation).
I need some responsive website design around here
For reasons that involve increasing usage and lowering costs, work got an iPad Mini and I wound up as its holder (it may shock you to know that we didn't really have any tablets around before this). One of the things I've done with it is look at websites, including Wandering Thoughts. In a way this is unfortunate, because now I really want to redesign Wandering Thoughts to be responsive. What I really mean by 'responsive' here is that I want the sidebar to go away on small screen devices.
(Well, the sidebar should go down to the bottom. I don't want it to go away entirely.)
The iPad Mini is small enough that screen real estate is at a premium on websites. If you use it in vertical mode, you don't have room for anything apart from the content text; if you use it in horizontal mode, well, you sort of have room for a sidebar but not really, and anyways you'd rather read vertically because that's more text and it's is laid out in a more readable way because it's narrower (in my view). I can only imagine how much worse this is on a smaller device, like a phone. This is the sidebar issue made quite concrete for me.
The problem is that I don't know the best way to do this without completely tearing the site design apart, or if it's even achievable very easily without Javascript (and I refuse to make Javascript a required thing here). Someday CSS grid layout will make this easy, whenever it's supported by most browsers (and perhaps finalized), but that day is not today. I suspect that I can't do this at all easily in regular CSS unless I start forcing column widths, but I haven't looked recently. And I'd rather not force column widths because then I'd have to read up on design to figure out how wide readable columns are, instead of my current approach of punting on it (since browser width determines column width and in theory people can make their browsers narrower or wider).
The radical approach would be a complete redesign of the look of Wandering Thoughts that permanently demoted what is currently the sidebar down to the bottom of the page even on regular browsers with lots of screen real estate. Many blogs today have taken this simplified approach but I'm not sure I like it (and I'm not sure I like the lower visibility of some things in the sidebar, like my Twitter). Still, it would solve the problem.
Ultimately design is a hard problem and CSS's current awkwardness doesn't make it any easier. This probably means the current Wandering Thoughts layout is going to stay as is, since that approach takes the least effort even if it makes me wince a bit when I look at the site on the iPad Mini.