Conversion of constants

February 28, 2024

In case you missed it… It has come to my attention that Monday’s livestream went to the wrong stream on YouTube! This means if you followed the link I shared with you on Monday, you likely sat there waiting for 2 hours, only to be disappointed by a lack of live programming. 😞

Alas, the livestream did happen, just at a different link by accident. So here’s that link, so you can watch the replay, if you so desire.


Conversions

…

A constant value x can be converted to type T if x is representable by a value of T. As a special case, an integer constant x can be explicitly converted to a string type using the same rule as for non-constant x.

Not much to see here. The exception it mentions we’ll be getting to shortly, so I won’t go into those details now.

Converting a constant to a type that is not a type parameter yields a typed constant.

Recall that Go supports untyped constants. This is one of the concepts that gives Go some of the flexibility of a dynamically typed language.

const x = 3 // x is an unypted constant, and can be used as any numeric type, depending on context
uint(iota)               // iota value of type uint
float32(2.718281828)     // 2.718281828 of type float32
complex128(1)            // 1.0 + 0.0i of type complex128
float32(0.49999999)      // 0.5 of type float32
float64(-1e-1000)        // 0.0 of type float64
string('x')              // "x" of type string
string(0x266c)           // "♬" of type string
myString("foo" + "bar")  // "foobar" of type myString
string([]byte{'a'})      // not a constant: []byte{'a'} is not a constant
(*int)(nil)              // not a constant: nil is not a constant, *int is not a boolean, numeric, > or string type
int(1.2)                 // illegal: 1.2 cannot be represented as an int
string(65.0)             // illegal: 65.0 is not an integer constant

The important thing to note here is that when you convert a constant, the result is still a constant.

Well, that is… unless…

Converting a constant to a type parameter yields a non-constant value of that type, with the value represented as a value of the type argument that the type parameter is instantiated with. For example, given the function:

func f[P ~float32|~float64]() {
	… P(1.1) …
}

the conversion `P(1.1)` results in a non-constant value of type `P` and the value `1.1` is represented as a `float32` or a `float64` depending on the type argument for `f`. Accordingly, if `f` is instantiated with a `float32` type, the numeric value of the expression `P(1.1) + 1.2` will be computed with the same precision as the corresponding non-constant `float32` addition.

So some of the benefits of using constants (for efficiency, or for greater precision) are lost when using generics.

This is unlikely to have a big impact, except in very rare cases.

Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe