I didn't completely expect it, but I now find myself reaching for Go first when writing something like a small script or utility that I'd previously have written in something like Ruby or Python. It all feels much more solid.
That said… I really chafe against the anaemic type system when writing anything a larger than that. I hate not being able to communicate things like "this can never be nil and if it's is then it's an error" to the compiler. I resent having to write three lines of boilerplate every time I want to reverse a flipping 10-item slice, and the design decisions leading to the existence of `time.IsZero()` are bordering on criminal.
I don't know if I'm the odd one out for feeling like that – parts of the language and ecosystem are just absolutely wonderful to work with, but the unergonomic sharp edges bother me so much that I end up finding it really _annoying_ to write a lot of it.
> the design decisions leading to the existence of `time.IsZero()` are bordering on criminal.
What's the rationale for Time.IsZero()? Seems like every use case for Time.IsZero() I think of is a code smell. The 1970 epoch is an implementation detail that should be hidden or configurable. People probably use IsZero() as a sentinel value to indicate "undefined time", even though the 1970 epoch is a valid point in time.
.IsZero() is a pragmatic solution given the constraints of the system (i.e. Go language).
Go has a notion of "zero value". When you don't assign a value explicitly it'll be set by the compiler to "zero value" of that type.
This is much better than C/C++ of "random value".
For primitive types, the compiler decides what "zero value" is. For structs, each component is set to its zero value.
For good reasons (language simplicity) Go doesn't allow the user to declare what the zero value is (something that you can do in e.g. C++ via a constructor).
Time is a struct. Its zero value is the same as for any other struct and not meaningful time value.
It's a pragmatic necessity to be able to query "is this time value an unset time value?". A pragmatic solution for this need is to provide IsZero() method on Time struct.
It may be pragmatic, but it’s incorrect. “Is this time value an unset time value?” is not a question you can answer (using IsZero considers the epoch an unset time value, but it’s a perfectly valid set one too).
// IsZero reports whether t represents the zero time instant,
// January 1, year 1, 00:00:00 UTC.
func (t Time) IsZero() bool {
return t.sec() == 0 && t.nsec() == 0
}
I didn't completely expect it, but I now find myself reaching for Go first when writing something like a small script or utility that I'd previously have written in something like Ruby or Python. It all feels much more solid.
That said… I really chafe against the anaemic type system when writing anything a larger than that. I hate not being able to communicate things like "this can never be nil and if it's is then it's an error" to the compiler. I resent having to write three lines of boilerplate every time I want to reverse a flipping 10-item slice, and the design decisions leading to the existence of `time.IsZero()` are bordering on criminal.
I don't know if I'm the odd one out for feeling like that – parts of the language and ecosystem are just absolutely wonderful to work with, but the unergonomic sharp edges bother me so much that I end up finding it really _annoying_ to write a lot of it.