Last updated 3 years ago by fai face
golangThe recent try
proposal by Robert Griesemer sparked a lot of controversy. While the proposal is a subject to reasonable criticism, I didn’t feel like everyone was always on the same page.
This post isn’t pro-try or anti-try. It just shows how try
could be used so that you can form a more informed opinion.
Suppose we are grad students of social sciences and need to come up with idea for a poll. Since we are programmers, too, we’ve come up with this poll: find correlations between person’s gender, favorite OS, and favorite programming language.
This is, of course, a contrived example. The goal of this post isn’t to solve a real-world scenario, but to show multiple aspects of try
in a small program.
The data from the poll will look like this:
```language-go name: Boris Bateman gender: man os: Windows lang: PHP
name: Darin May gender: woman os: OSX lang: JavaScript
name: Shea Wilks gender: nonbinary os: Linux lang: Emacs LISP
name: Robert Griesemer gender: man os: Linux lang: Go ```
Each respondent has four required fields: name, gender, os, and lang. There is an obligatory empty line between respondents.
We want to parse this file into a slice of Respondent
structs, defined like this:
language-go
type Respondent struct {
Name string
Gender string
OS string
Lang string
}
Let’s get on to it, step by step!
language-go
func parseRespondents(path string) (resps []Respondent, err error) {
return nil, nil
}
I know, I could have used an io.Reader
. But, for the purposes of demonstrating try
, let’s keep it this way.
First, we’re gonna use a (not yet existing) function fmt.HandleErrorf
:
language-go
func parseRespondents(path string) (resps []Respondent, err error) {
defer fmt.HandleErrorf(&err, "parse %s", path)
return nil, nil
}
It adds context to the returned error, if it’s not nil
. It’s defined like this:
language-go
func HandleErrorf(err *error, format string, args ...interface{}) {
if *err != nil {
*err = errors.Wrapf(*err, format, args...)
}
}
Every error returned from parseRespondents("respondents.txt")
will now be prefixed with parse respondents.txt:
.
```language-go func parseRespondents(path string) (resps []Respondent, err error) { defer fmt.HandleErrorf(&err, "parse %s", path)
f := try(os.Open(path))
defer f.Close()
return nil, nil
} ```
Normally, os.Open(path)
returns two values: the file and an error. By wrapping it in try
, we drop the error from the return values and get an automatic return if the error wasn’t nil
.
What kind of error do we get now if the file doesn’t exist?