Golang Pros & Cons for DevOps (Part 4 of 6): The Time Package and Method Overloading

By Keilan Jackson on November 20, 2017

golang-pros-cons-4-time-package-method-overloading

The long-awaited continuation of the Golang Pros & Cons for DevOps has returned! In this one, we discuss Golang's time package and the lack of method overloading in the language.

Be sure to read up on the last post about “Speed vs. Lack of Generics” if you missed it, or subscribe to our blog updates to be notified when the rest of the series is published.

Golang Pro: The Time Package

Any programmer knows the dangers of dealing with dates and time. Deceptively simple in our every day lives, dealing with time from a computer's point of view is a nightmare. Google had the opportunity to make working with dates a breeze in Golang and they nailed it! My assessment on the time package is broken into three parts: (1) the basics, (2) timers, and (3) date parsing.

1. Time Package Basics

You would think that every language has a standard, easy to use built-in library for dealing with time, but that is not the case. NPM has over 8000 packages built because javascript's Date is unusable. Java 8 finally got some relief with java.time.Instant, and the java.time.chrono package, but tutorials are still written to delve into the many classes and methods that allow you to manipulate time in Java. In contrast, Golang's time package can be summed up in one phrase: things do what you expect with only one import.

Get the current time: time.Now()

Get a time in the future: time.Now().Add(5*time.Minute)

Get elapsed time (as a Duration): time.Since(processingStarted)

Easily compare durations: if frequency < time.Hour {

Get current day of the month. Throw away that calendar! time.Now().Day()

2. Timers

Another big plus with the time package is easy-to-use timers. The DevOps application here is clear: we always want to schedule things to happen in the future, on a recurring basis, or just sleep for a second.

By co-locating timers in the time package, you can sleep a thread as easily as

time.Sleep(2*time.Minute)

or execute a function in the future

time.AfterFunc(5*time.Second, func() {
  fmt.Println("hello in the future")
})

or repeat a task

tick := time.NewTicker(1*time.Minute)
select {
case <- tick.C:
  foo()
}

All without converting everything to seconds (or was it milliseconds?) and adding 2 dependencies and 10 imports.

3. Date Parsing

No discussion of time is complete without our most common and most hated task: turning strings into dates. What should be a basic task, is not. There's the many standards for date formats, your language secretly not having a thread safe implementation of date parsing, and timezones, just to ensure that it's not 5 o'clock everywhere. This is where Golang recognized something important: what everyone else was doing is wrong.

Instead of building a solution with thousands of possible date formats, Google created a system that uses pattern-based layouts that always refer to the same reference date: Mon Jan 02 15:04:05 MST 2006. The components of this single reference date are rearranged to meet any format you'll likely encounter. A concise, yet complete, explanation can be found here.

Surely Golang's date parsing isn't perfect, right? Well, yeah. You can't reinvent date parsing without at least one issue: timezones. Besides making meetings impossible to schedule, timezones are at it again in Golang, making it difficult to parse something like "2017/10/03 4:07:22 America/New_York". It's the "America/New_York" bit that gives us trouble. There are some workarounds but Golang leaves much to be desired in the timezone parsing department.

Golang Con: Method Overloading

One of the first things I remember learning in my Computer Science classes and thinking "that's cool!" just does not exist in Golang at all. From Golang's FAQ:

Why does Go not support overloading of methods and operators? Method dispatch is simplified if it doesn't need to do type matching as well. Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system. Regarding operator overloading, it seems more a convenience than an absolute requirement. Again, things are simpler without it.

It's true, not having overloaded methods is simpler. But it also bloats your code base by forcing you to come up with unique names for otherwise identical functions, while still remembering if the common functional goes in a private or Public function, or if you will just copypasta everything and "fix it later". The aforementioned time package has a few instances of this, and makes us yearn for an optional last parameter with a default value.

func Parse(layout, value string) (Time, error) { 
  return parse(layout, value, UTC, Local)
}

func ParseInLocation(layout, value string, loc *Location) (Time, error) {
  return parse(layout, value, loc, loc)
}

func parse(layout, value string, defaultLocation, local *Location) (Time, error) {
  ...
}

That said, not having method overloading is definitely not a deal-breaker for using Golang. In the few instances I wanted it, I end up just using a common private function and multiple other ones with different names, or removing the reason I needed overloading in the first place.


Every other week or so, we are posting a new guide like this in our six-part series on “Golang Pros & Cons for DevOps.” Next up: #5: Cross-Platform Compilation, Windows, Signals, Docs, and the Compiler. If you're looking for aws monitoring, we can help with that, too.

What to Read Next

Subscribe to get blog updates in your inbox.

Get started with alert automation
See how it'll save you time and toil
START FREE TRIAL