My Go Resolutions for 2017
232 |
233 |
234 |
235 | Posted on Wednesday, January 18, 2017.
236 |
237 |
238 |
239 |
240 |
241 | ’Tis the season for resolutions, 242 | and I thought it would make sense to write a little 243 | about what I hope to work on this year as far as Go is concerned.
244 | 245 |My goal every year is to help Go developers. 246 | I want to make sure that the work we do on the Go team 247 | has a significant, positive impact on Go developers. 248 | That may sound obvious, but there are a variety of common ways to fail to achieve that: 249 | for example, spending too much time cleaning up or optimizing code that doesn’t need it; 250 | responding only to the most common or recent complaints or requests; 251 | or focusing too much on short-term improvements. 252 | It’s important to step back and make sure we’re focusing 253 | our development work where it does the most good.
254 | 255 |This post outlines a few of my own major focuses for this year. 256 | This is only my personal list, not the Go team’s list.
257 | 258 |One reason for posting this is to gather feedback. 259 | If these spark any ideas or suggestions of your own, 260 | please feel free to comment below or on the linked GitHub issues.
261 | 262 |Another reason is to make clear that I’m aware of these issues as important. 263 | I think too often people interpret lack of action by the Go team 264 | as a signal that we think everything is perfect, when instead 265 | there is simply other, higher priority work to do first.
266 | 267 |Type aliases
268 | 269 |There is a recurring problem with moving types 270 | from one package to another during large codebase refactorings. 271 | We tried to solve it last year with general aliases, 272 | which didn’t work for at least two reasons: we didn’t explain the change well enough, 273 | and we didn’t deliver it on time, so it wasn’t ready for Go 1.8. 274 | Learning from that experience, 275 | I gave a talk 276 | and wrote an article 277 | about the underlying problem, 278 | and that started a productive discussion 279 | on the Go issue tracker about the solution space. 280 | It looks like more limited type aliases 281 | are the right next step. 282 | I want to make sure those land smoothly in Go 1.9. #18130.
283 | 284 |Package management
285 | 286 |I designed the Go support for downloading published packages 287 | (“goinstall”, which became “go get”) in February 2010. 288 | A lot has happened since then. 289 | In particular, other language ecosystems have really raised the bar 290 | for what people expect from package management, 291 | and the open source world has mostly agreed on 292 | semantic versioning, which provides a useful base 293 | for inferring version compatibility. 294 | Go needs to do better here, and a group of contributors have been 295 | working on a solution. 296 | I want to make sure these ideas are integrated well 297 | into the standard Go toolchain and to make package management 298 | a reason that people love Go.
299 | 300 |Build improvements
301 | 302 |There are a handful of shortcomings in the design of 303 | the go command’s build system that are overdue to be fixed. 304 | Here are three representative examples that I intend to 305 | address with a bit of a redesign of the internals of the go command.
306 | 307 |Builds can be too slow,
308 | because the go command doesn’t cache build results as aggressively as it should.
309 | Many people don’t realize that go install saves its work while go build does not,
310 | and then they run repeated go build commands that are slow
311 | because the later builds do more work than they should need to.
312 | The same for repeated go test without go test -i when dependencies are modified.
313 | All builds should be as incremental as possible.
314 | #4719.
Test results should be cached too: 317 | if none of the inputs to a test have changed, 318 | then usually there is no need to rerun the test. 319 | This will make it very cheap to run “all tests” when little or nothing has changed. 320 | #11193.
321 | 322 |Work outside GOPATH should be supported nearly as well
323 | as work inside GOPATH.
324 | In particular, it should be possible to git clone a repo,
325 | cd into it, and run go commands and have them work fine.
326 | Package management only makes that more important:
327 | you’ll need to be able to work on different versions of a package (say, v1 and v2)
328 | without having entirely separate GOPATHs for them.
329 | #17271.
Code corpus
332 | 333 |I think it helped to have concrete examples from real projects 334 | in the talk and article I prepared about codebase refactoring (see above). 335 | We’ve also defined that additions to vet 336 | must target problems that happen frequently in real programs. 337 | I’d like to see that kind of analysis of actual practice—examining 338 | the effects on and possible improvements to real programs—become a 339 | standard way we discuss and evaluate changes to Go.
340 | 341 |Right now there’s not an agreed-upon representative corpus of code to use for 342 | those analyses: everyone must first create their own, which is too much work. 343 | I’d like to put together a single, self-contained Git repo people can check out that 344 | contains our official baseline corpus for those analyses. 345 | A possible starting point could be the top 100 Go language repos 346 | on GitHub by stars or forks or both.
347 | 348 |Automatic vet
349 | 350 |The Go distribution ships with this powerful tool,
351 | go vet,
352 | that points out correctness bugs.
353 | We have a high bar for checks, so that when vet speaks, you should listen.
354 | But everyone has to remember to run it.
355 | It would be better if you didn’t have to remember.
356 | In particular, I think we could probably run vet
357 | in parallel with the final compile and link of the test binary
358 | during go test without slowing the compile-edit-test cycle at all.
359 | If we can do that, and if we limit the enabled vet checks to a subset
360 | that is essentially 100% accurate,
361 | we can make passing vet a precondition for running a test at all.
362 | Then developers don’t need to remember to run go vet.
363 | They run go test,
364 | and once in a while vet speaks up with something important
365 | and avoids a debugging session.
366 | #18084,
367 | #18085.
Errors & best practices
370 | 371 |Part of the intended contract for error reporting in Go is that functions 372 | include relevant available context, including the operation being attempted 373 | (such as the function name and its arguments). 374 | For example, this program:
375 | 376 |err := os.Remove("/tmp/nonexist")
377 | fmt.Println(err)
378 |
379 |
380 | prints this output:
381 | 382 |remove /tmp/nonexist: no such file or directory
383 |
384 |
385 | Not enough Go code adds context like os.Remove does. Too much code does only
if err != nil {
388 | return err
389 | }
390 |
391 |
392 | all the way up the call stack,
393 | discarding useful context that should be reported
394 | (like remove /tmp/nonexist: above).
395 | I would like to try to understand whether our expectations
396 | for including context are wrong, or if there is something
397 | we can do to make it easier to write code that returns better errors.
There are also various discussions in the community about 400 | agreed-upon interfaces for stripping error context. 401 | I would like to try to understand when that makes sense and 402 | whether we should adopt an official recommendation.
403 | 404 |Context & best practices
405 | 406 |We added the new context package 407 | in Go 1.7 for holding request-scoped information like 408 | timeouts, cancellation state, and credentials. 409 | An individual context is immutable (like an individual string or int): 410 | it is only possible to derive a new, updated context and 411 | pass that context explicitly further down the call stack or 412 | (less commonly) back up to the caller. 413 | The context is now carried through APIs such as 414 | database/sql 415 | and 416 | net/http, 417 | mainly so that those can stop processing a request when the caller 418 | is no longer interested in the result. 419 | Timeout information is appropriate to carry in a context, 420 | but—to use a real example we removed—database options 421 | are not, because they are unlikely to apply equally well to all possible 422 | database operations carried out during a request. 423 | What about the current clock source, or logging sink? 424 | Is either of those appropriate to store in a context? 425 | I would like to try to understand and characterize the 426 | criteria for what is and is not an appropriate use of context.
427 | 428 |Memory model
429 | 430 |Go’s memory model is intentionally low-key, 431 | making few promises to users, compared to other languages. 432 | In fact it starts by discouraging people from reading the rest of the document. 433 | At the same time, it demands more of the compiler than other languages: 434 | in particular, a race on an integer value is not sufficient license 435 | for your program to misbehave in arbitrary ways. 436 | But there are some complete gaps, in particular no mention of 437 | the sync/atomic package. 438 | I think the core compiler and runtime developers all agree 439 | that the behavior of those atomics should be roughly the same as 440 | C++ seqcst atomics or Java volatiles, 441 | but we still need to write that down carefully in the memory model, 442 | and probably also in a long blog post. 443 | #5045, 444 | #7948, 445 | #9442.
446 | 447 |Immutability
448 | 449 |The race detector
450 | is one of Go’s most loved features.
451 | But not having races would be even better.
452 | I would love it if there were some reasonable way to integrate
453 | reference immutability into Go,
454 | so that programmers can make clear, checked assertions about what can and cannot
455 | be written and thereby eliminate certain races at compile time.
456 | Go already has one immutable type, string; it would
457 | be nice to retroactively define that
458 | string is a named type (or type alias) for immutable []byte.
459 | I don’t think that will happen this year,
460 | but I’d like to understand the solution space better.
461 | Javari, Midori, Pony, and Rust have all staked out interesting points
462 | in the solution space, and there are plenty of research papers
463 | beyond those.
In the long-term, if we could statically eliminate the possibility of races, 466 | that would eliminate the need for most of the memory model. 467 | That may well be an impossible dream, 468 | but again I’d like to understand the solution space better.
469 | 470 |Generics
471 | 472 |Nothing sparks more heated arguments 473 | among Go and non-Go developers than the question of whether Go should 474 | have support for generics (or how many years ago that should have happened). 475 | I don’t believe the Go team has ever said “Go does not need generics.” 476 | What we have said is that there are higher-priority issues facing Go. 477 | For example, I believe that better support for package management 478 | would have a much larger immediate positive impact on most Go developers 479 | than adding generics. 480 | But we do certainly understand that for a certain subset of Go use cases, 481 | the lack of parametric polymorphism is a significant hindrance.
482 | 483 |Personally, I would like to be able to write general channel-processing 484 | functions like:
485 | 486 |// Join makes all messages received on the input channels
487 | // available for receiving from the returned channel.
488 | func Join(inputs ...<-chan T) <-chan T
489 |
490 | // Dup duplicates messages received on c to both c1 and c2.
491 | func Dup(c <-chan T) (c1, c2 <-chan T)
492 |
493 |
494 | I would also like to be able to write 495 | Go support for high-level data processing abstractions, 496 | analogous to 497 | FlumeJava or 498 | C#’s LINQ, 499 | in a way that catches type errors at compile time instead of at run time. 500 | There are also any number of data structures or generic algorithms 501 | that might be written, 502 | but I personally find these broader applications more compelling.
503 | 504 |We’ve struggled off and on
505 | for years
506 | to find the right way to add generics to Go.
507 | At least a few of the past proposals got hung up on trying to design
508 | something that provided both general parametric polymorphism
509 | (like chan T) and also a unification of string and []byte.
510 | If the latter is handled by parameterization over immutability,
511 | as described in the previous section, then maybe that simplifies
512 | the demands on a design for generics.
When I first started thinking about generics for Go in 2008, 515 | the main examples to learn from were C#, Java, Haskell, and ML. 516 | None of the approaches in those languages seemed like a 517 | perfect fit for Go. 518 | Today, there are newer attempts to learn from as well, 519 | including Dart, Midori, Rust, and Swift.
520 | 521 |It’s been a few years since we ventured out and explored the design space. 522 | It is probably time to look around again, 523 | especially in light of the insight about mutability and 524 | the additional examples set by newer languages. 525 | I don’t think generics will happen this year, 526 | but I’d like to be able to say I understand the solution space better.
527 | 528 |