Go: Context.WithValue trap and Go’s typed nils.

There are a lot of discussions about Go 2.0 and what should be done in the upcoming major release. Some circulations were about Context. So far I haven’t heard anything optimistic about that.

Today I discovered by myself: how quick a newbie (as me) can mess things up using Context. Maybe I reproduce the only case you should not use Context but anyway.

I decided to implement a middleware to pick corresponding template depending on path in http request.

My middleware (function loadTemplate) picks a correct template (html.Template) and send it over with Context.

Function getTemplate initiates a template based on the path in http request. The function returns nil and an error if requested template was not found. Logically it is to handle the error here straight away. But I decided to skip the error handling here and send <nil> template to Context.

Firstly in renderTemplate function I read from Context and try to check if object is nil (line 60, 62):

This code is full of crap.

That is wrong because I handle Context.Value like an output from ordinary function or map. But Context returns not some specific type but interface{}. So you have to use type assertion instead to reach underlying value and check if it’s a nil:

// Line 62 correct:
if t.(*template.Template) == nil

So the check in the line 62 of my code was skipped.

But look at the line 67. Would you expect this type assertion to be failed if “t” is nil? I expected so and I was wrong. Type assertion works perfectly here. Then I discovered what I haven’t known before: even the nil in Go has a type. If you look in debugger what type variable “t” is:

nil <*temlplate.Template>

Statements like this make more sense for me now:

a := (*error)(nil)
// nil for <*error>

Context is not very newbie-friendly thing in Go. It is not so easy as it is stated on Go Blog. You have to understand a lot of concepts of language before even consider using it.