As I understand Go more, some of the concepts tend to make my head hurt. Sometimes, innocent examples in various tutorials hide such deep concepts, that it takes a while for me to decode it all.
Here is an example. In various tutorials, pauses are made using time.Sleep().
The first time I saw an example like the following, it made me stop in my tracks.
package main import ( "time" ) func main() { time.Sleep(100 * time.Millisecond) }Here is the signature of time.Sleep
And here is what Duration
and time.Millisecond
means.
Coming from my past experience with other languages, my question was, in a strongly typed language like Go:
- How does
100 * time.Millisecond
work? Aren’t they entirely two different types? And I know that Go doesn’t support operator overloading. So how does Go know how to use the operator*
between aDuration
and what looks like anint
. My first guess was that Go was converting the durationtime.Millisecond
to anint
to make the multiplication work, like in other language. - Even if somehow the multiplication worked, how is the result satisfying the type requirement for the parameter
passed to
Sleep()
which requires aDuration
.
Turns out my guess was wrong.
There are a couple of points in the spec that explains what is happening.
Since
Duration
is of typeint64
, this confirms that aDuration
and aint64
are different even though the latter is the underlying type of the former.A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it. The new type is called a defined type. It is different from any other type, including the type it is created from.
However, type identity is the most crucial part which establishes that
int64
andDuration
as considered to be identical type whenever the question arises.A defined type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types.
However, this is the missing link I was looking for. This is how
100 * time.Millisecond
becomestime.Duration(100) * time.Millisecond
For other binary operators, the operand types must be identical unless the operation involves shifts or untyped constants. … Except for shift operations, if one operand is an untyped constant and the other operand is not, the constant is converted to the type of the other operand.
And what happens after the multiplication? The result is considered to be of type
time.Duration
Arithmetic operators apply to numeric values and yield a result of the same type as the first operand.
So, if I have got it right:
- Go will convert the untyped integer value
100
to the typeDuration
. - Since both have the underlying type of integer, it will follow the integer operator rules for
*
- The result will be converted to the type of
time.Duration