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

2017/08/30

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 quickly 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 middleware to pick the corresponding template depending on the path in HTTP request.

1

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

2

Function getTemplate initiates a template based on the path in the HTTP request. The function returns nil and an error if the 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 template to Context.

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

3

That is wrong because I handle Context.Value like the 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 nil:

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

The check in line 62 of my code was skipped.

But look at line 67. Would you expect this type of 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.

>> Home