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 .

Related Content


Range conclusion

Today we finish up with some final notes, and a big example, from the spec section on for statements. For statements with range clause … If the iteration variables are not explicitly declared by the “range” clause, they must be preexisting. In this case, the iteration values are assigned to the respective variables as in an assignment statement. I actually discussed this case yesterday, so won’t go into it again.


Scope and type of range variables

For statements with range clause … The iteration variables may be declared by the “range” clause using a form of short variable declaration (:=). In this case their scope is the block of the “for” statement and each iteration has its own new variables [Go 1.22] (see also “for” statements with a ForClause). We’ve already talked at some length about the scope of variables in other forms of for loops.


Case expressions

I’m back live streaming again! Join me in just over an hour! Bring your questions, too! Expression switches … If a case expression is untyped, it is first implicitly converted to the type of the switch expression. For each (possibly converted) case expression x and the value t of the switch expression, x == t must be a valid comparison. In other words, the switch expression is treated as if it were used to declare and initialize a temporary variable t without explicit type; it is that value of t against which each case expression x is tested for equality.

Get daily content like this in your inbox!

Subscribe