github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/constants.article (about)

     1  Constants
     2  25 Aug 2014
     3  Tags: constants
     4  
     5  Rob Pike
     6  
     7  * Introduction
     8  
     9  Go is a statically typed language that does not permit operations that mix numeric types.
    10  You can't add a `float64` to an `int`, or even an `int32` to an `int`.
    11  Yet it is legal to write `1e6*time.Second` or `math.Exp(1)` or even `1<<('\t'+2.0)`.
    12  In Go, constants, unlike variables, behave pretty much like regular numbers.
    13  This post explains why that is and what it means.
    14  
    15  * Background: C
    16  
    17  In the early days of thinking about Go, we talked about a number of problems caused by the way C and its descendants let you mix and match numeric types.
    18  Many mysterious bugs, crashes, and portability problems are caused by expressions that combine integers of different sizes and "signedness".
    19  Although to a seasoned C programmer the result of a calculation like
    20  
    21  	unsigned int u = 1e9;
    22  	long signed int i = -1;
    23  	... i + u ...
    24  
    25  may be familiar, it isn't _a_priori_ obvious.
    26  How big is the result?
    27  What is its value?
    28  Is it signed or unsigned?
    29  
    30  Nasty bugs lurk here.
    31  
    32  C has a set of rules called "the usual arithmetic conversions" and it is an indicator of their subtlety that they have changed over the years (introducing yet more bugs, retroactively).
    33  
    34  When designing Go, we decided to avoid this minefield by mandating that there is _no_ mixing of numeric types.
    35  If you want to add `i` and `u`, you must be explicit about what you want the result to be.
    36  Given
    37  
    38  	var u uint
    39  	var i int
    40  
    41  you can write either `uint(i)+u` or `i+int(u)`, with both the meaning and type of the addition clearly expressed, but unlike in C you cannot write `i+u`.
    42  You can't even mix `int` and `int32`, even when `int` is a 32-bit type.
    43  
    44  This strictness eliminates a common cause of bugs and other failures.
    45  It is a vital property of Go.
    46  But it has a cost: it sometimes requires programmers to decorate their code with clumsy numeric conversions to express their meaning clearly.
    47  
    48  And what about constants?
    49  Given the declarations above, what would make it legal to write `i` `=` `0` or `u` `=` `0`?
    50  What is the _type_ of `0`?
    51  It would be unreasonable to require constants to have type conversions in simple contexts such as `i` `=` `int(0)`.
    52  
    53  We soon realized the answer lay in making numeric constants work differently from how they behave in other C-like languages.
    54  After much thinking and experimentation, we came up with a design that we believe feels right almost always, freeing the programmer from converting constants all the time yet being able to write things like `math.Sqrt(2)` without being chided by the compiler.
    55  
    56  In short, constants in Go just work, most of the time anyway.
    57  Let's see how that happens.
    58  
    59  * Terminology
    60  
    61  First, a quick definition.
    62  In Go, `const` is a keyword introducing a name for a scalar value such as `2` or `3.14159` or `"scrumptious"`.
    63  Such values, named or otherwise, are called _constants_ in Go.
    64  Constants can also be created by expressions built from constants, such as `2+3` or `2+3i` or `math.Pi/2` or `("go"+"pher")`.
    65  
    66  Some languages don't have constants, and others have a more general definition of constant or application of the word `const`.
    67  In C and C++, for instance, `const` is a type qualifier that can codify more intricate properties of more intricate values.
    68  
    69  But in Go, a constant is just a simple, unchanging value, and from here on we're talking only about Go.
    70  
    71  * String constants
    72  
    73  There are many kinds of numeric constants—integers, floats, runes, signed, unsigned, imaginary, complex—so let's start with a simpler form of constant: strings.
    74  String constants are easy to understand and provide a smaller space in which to explore the type issues of constants in Go.
    75  
    76  A string constant encloses some text between double quotes.
    77  (Go has also has raw string literals, enclosed by backquotes ``````, but for the purpose of this discussion they have all the same properties.)
    78  Here is a string constant:
    79  
    80  	"Hello, 世界"
    81  
    82  (For much more detail about the representation and interpretation of strings, see [[//blog.golang.org/strings][this blog post]].)
    83  
    84  What type does this string constant have?
    85  The obvious answer is `string`, but that is _wrong_.
    86  
    87  This is an _untyped_string_constant_, which is to say it is a constant textual value that does not yet have a fixed type.
    88  Yes, it's a string, but it's not a Go value of type `string`.
    89  It remains an untyped string constant even when given a name:
    90  
    91  	const hello = "Hello, 世界"
    92  
    93  After this declaration, `hello` is also an untyped string constant.
    94  An untyped constant is just a value, one not yet given a defined type that would force it to obey the strict rules that prevent combining differently typed values.
    95  
    96  It is this notion of an _untyped_ constant that makes it possible for us to use constants in Go with great freedom.
    97  
    98  So what, then, is a _typed_ string constant?
    99  It's one that's been given a type, like this:
   100  
   101  	const typedHello string = "Hello, 世界"
   102  
   103  Notice that the declaration of `typedHello` has an explicit `string` type before the equals sign.
   104  This means that `typedHello` has Go type `string`, and cannot be assigned to a Go variable of a different type.
   105  That is to say, this code works:
   106  
   107  .play -edit constants/string1.go /START/,/STOP/
   108  
   109  but this does not:
   110  
   111  .play -edit constants/string2.go /START/,/STOP/
   112  
   113  The variable `m` has type `MyString` and cannot be assigned a value of a different type.
   114  It can only be assigned values of type `MyString`, like this:
   115  
   116  .play -edit constants/string3.go /START/,/STOP/
   117  
   118  or by forcing the issue with a conversion, like this:
   119  
   120  .play -edit constants/string4.go /START/,/STOP/
   121  
   122  Returning to our _untyped_ string constant, it has the helpful property that, since it has no type, assigning it to a typed variable does not cause a type error.
   123  That is, we can write
   124  
   125  	m = "Hello, 世界"
   126  
   127  or
   128  
   129  	m = hello
   130  
   131  because, unlike the typed constants `typedHello` and `myStringHello`, the untyped constants `"Hello,`世界"` and `hello` _have_no_type_.
   132  Assigning them to a variable of any type compatible with strings works without error.
   133  
   134  These untyped string constants are strings, of course, so they can only be used where a string is allowed, but they do not have _type_ `string`.
   135  
   136  * Default type
   137  
   138  As a Go programmer, you have certainly seen many declarations like
   139  
   140  	str := "Hello, 世界"
   141  
   142  and by now you might be asking, "if the constant is untyped, how does `str` get a type in this variable declaration?"
   143  The answer is that an untyped constant has a default type, an implicit type that it transfers to a value if a type is needed where none is provided.
   144  For untyped string constants, that default type is obviously `string`, so
   145  
   146  	str := "Hello, 世界"
   147  
   148  or
   149  
   150  	var str = "Hello, 世界"
   151  
   152  means exactly the same as
   153  
   154  	var str string = "Hello, 世界"
   155  
   156  One way to think about untyped constants is that they live in a kind of ideal space of values, a space less restrictive than Go's full type system.
   157  But to do anything with them, we need to assign them to variables, and when that happens the _variable_ (not the constant itself) needs a type, and the constant can tell the variable what type it should have.
   158  In this example, `str` becomes a value of type `string` because the untyped string constant gives the declaration its default type, `string`.
   159  
   160  In such a declaration, a variable is declared with a type and initial value.
   161  Sometimes when we use a constant, however, the destination of the value is not so clear.
   162  For instance consider this statement:
   163  
   164  .play -edit constants/default1.go /START/,/STOP/
   165  
   166  The signature of `fmt.Printf` is
   167  
   168  	func Printf(format string, a ...interface{}) (n int, err error)
   169  
   170  which is to say its arguments (after the format string) are interface values.
   171  What happens when `fmt.Printf` is called with an untyped constant is that an interface value is created
   172  to pass as an argument, and the concrete type stored for that argument is the default type of the constant.
   173  This process is analogous to what we saw earlier when declaring an initialized value using an untyped string constant.
   174  
   175  You can see the result in this example, which uses the format `%v` to print the value and `%T` to print the type of the value being passed to `fmt.Printf`:
   176  
   177  .play -edit constants/default2.go /START/,/STOP/
   178  
   179  If the constant has a type, that goes into the interface, as this example shows:
   180  
   181  .play -edit constants/default3.go /START/,/STOP/
   182  
   183  (For more information about how interface values work, see the first sections of [[//blog.golang.org/laws-of-reflection][this blog post]].)
   184  
   185  In summary, a typed constant obeys all the rules of typed values in Go.
   186  On the other hand, an untyped constant does not carry a Go type in the same way and can be mixed and matched more freely.
   187  It does, however, have a default type that is exposed when, and only when, no other type information is available.
   188  
   189  * Default type determined by syntax
   190  
   191  The default type of an untyped constant is determined by its syntax.
   192  For string constants, the only possible implicit type is `string`.
   193  For [[http://golang.org/ref/spec#Numeric_types][numeric constants]], the implicit type has more variety.
   194  Integer constants default to `int`, floating-point constants `float64`, rune constants to `rune` (an alias for `int32`), and imaginary constants to `complex128`.
   195  Here's our canonical print statement used repeatedly to show the default types in action:
   196  
   197  .play -edit constants/syntax.go /START/,/STOP/
   198  
   199  (Exercise: Explain the result for `'x'`.)
   200  
   201  * Booleans
   202  
   203  Everything we said about untyped string constants can be said for untyped boolean constants.
   204  The values `true` and `false` are untyped boolean constants that can be assigned to any boolean variable,
   205  but once given a type, boolean variables cannot be mixed:
   206  
   207  .play -edit constants/bool.go /START/,/STOP/
   208  
   209  Run the example and see what happens, then comment out the "Bad" line and run it again.
   210  The pattern here follows exactly that of string constants.
   211  
   212  * Floats
   213  
   214  Floating-point constants are just like boolean constants in most respects.
   215  Our standard example works as expected in translation:
   216  
   217  .play -edit constants/float1.go /START/,/STOP/
   218  
   219  One wrinkle is that there are _two_ floating-point types in Go: `float32` and `float64`.
   220  The default type for a floating-point constant is `float64`, although an untyped floating-point
   221  constant can be assigned to a `float32` value just fine:
   222  
   223  .play -edit constants/float2.go /START/,/STOP/
   224  
   225  Floating-point values are a good place to introduce the concept of overflow, or the range of values.
   226  
   227  Numeric constants live in an arbitrary-precision numeric space; they are just regular numbers.
   228  But when they are assigned to a variable the value must be able to fit in the destination.
   229  We can declare a constant with a very large value:
   230  	
   231  .code constants/float3.go /Huge/
   232  
   233  —that's just a number, after all—but we can't assign it or even print it. This statement won't even compile:
   234  
   235  .play -edit constants/float3.go /Println/
   236  
   237  The error is, "constant 1.00000e+1000 overflows float64", which is true.
   238  But `Huge` might be useful: we can use it in expressions with other constants and use the value of those expressions if the result
   239  can be represented in the range of a `float64`.
   240  The statement,
   241  
   242  .play -edit constants/float4.go /Println/
   243  
   244  prints `10`, as one would expect.
   245  
   246  In a related way, floating-point constants may have very high precision, so that arithmetic involving them is more accurate.
   247  The constants defined in the [[//golang.org/pkg/math][math]] package are given with many more digits than are
   248  available in a `float64`. Here is the definition of `math.Pi`:
   249  
   250  	Pi	= 3.14159265358979323846264338327950288419716939937510582097494459
   251  
   252  When that value is assigned to a variable, some of the precision will be lost; the assignment will create the `float64` (or `float32`)
   253  value closest to the high-precision value. This snippet
   254  
   255  .play -edit constants/float5.go /START/,/STOP/
   256  
   257  prints `3.141592653589793`.
   258  
   259  Having so many digits available means that calculations like `Pi/2` or other more intricate evaluations can carry more precision
   260  until the result is assigned, making calculations involving constants easier to write without losing precision.
   261  It also means that there is no occasion in which the floating-point corner cases like infinities,
   262  soft underflows, and `NaNs` arise in constant expressions.
   263  (Division by a constant zero is a compile-time error, and when everything is a number there's no such thing as "not a number".)
   264  
   265  * Complex numbers
   266  
   267  Complex constants behave a lot like floating-point constants.
   268  Here's a version of our now-familiar litany translated into complex numbers:
   269  
   270  .play -edit constants/complex1.go /START/,/STOP/
   271  
   272  The default type of a complex number is `complex128`, the larger-precision version composed of two `float64` values.
   273  
   274  For clarity in our example, we wrote out the full expression `(0.0+1.0i)`, but this value can be shortened to `0.0+1.0i`,
   275  `1.0i` or even `1i`.
   276  
   277  Let's play a trick.
   278  We know that in Go, a numeric constant is just a number.
   279  What if that number is a complex number with no imaginary part, that is, a real?
   280  Here's one:
   281  
   282  .code constants/complex2.go /const Two/
   283  
   284  That's an untyped complex constant.
   285  Even though it has no imaginary part, the _syntax_ of the expression defines it to have default type `complex128`.
   286  Therefore, if we use it to declare a variable, the default type will be `complex128`. The snippet
   287  
   288  .play -edit constants/complex2.go /START/,/STOP/
   289  
   290  prints `complex128:` `(2+0i)`.
   291  But numerically, `Two` can be stored in a scalar floating-point number, a `float64` or `float32`, with no loss of information.
   292  Thus we can assign `Two` to a `float64`, either in an initialization or an assignment, without problems:
   293  
   294  .play -edit constants/complex3.go /START/,/STOP/
   295  
   296  The output is `2` `and` `2`.
   297  Even though `Two` is a complex constant, it can be assigned to scalar floating-point variables.
   298  This ability for a constant to "cross" types like this will prove useful.
   299  
   300  * Integers
   301  
   302  At last we come to integers.
   303  They have more moving parts—[[http://golang.org/ref/spec#Numeric_types][many sizes, signed or unsigned, and more]]—but they play by the same rules.
   304  For the last time, here is our familiar example, using just `int` this time:
   305  
   306  .play -edit constants/int1.go /START/,/STOP/
   307  
   308  The same example could be built for any of the integer types, which are:
   309  
   310  	int int8 int16 int32 int64
   311  	uint uint8 uint16 uint32 uint64
   312  	uintptr
   313  
   314  (plus the aliases `byte` for `uint8` and `rune` for `int32`).
   315  That's a lot, but the pattern in the way constants work should be familiar enough by now that you can see how things will play out.
   316  
   317  As mentioned above, integers come in a couple of forms and each form has its own default type: `int` for simple constants like `123` or `0xFF` or `-14`
   318  and `rune` for quoted characters like 'a', '世' or '\r'.
   319  
   320  No constant form has as its default type an unsigned integer type.
   321  However, the flexibility of untyped constants means we can initialize unsigned integer variables using simple constants as long as we are clear about the type.
   322  It's analogous to how we can initialize a `float64` using a complex number with zero imaginary part.
   323  Here are several different ways to initialize a `uint`; all are equivalent, but all must mention the type explicitly for the result to be unsigned.
   324  
   325  	var u uint = 17
   326  	var u = uint(17)
   327  	u := uint(17)
   328  
   329  Similarly to the range issue mentioned in the section on floating-point values, not all integer values can fit in all integer types.
   330  There are two problems that might arise: the value might be too large, or it might be a negative value being assigned to an unsigned integer type.
   331  For instance, `int8` has range -128 through 127, so constants outside of that range can never be assigned to a variable of type `int8`:
   332  
   333  .play -edit constants/int2.go /var/
   334  
   335  Similarly, `uint8`, also known as `byte`, has range 0 through 255, so a large or negative constant cannot be assigned to a `uint8`:
   336  
   337  .play -edit constants/int3.go /var/
   338  
   339  This type-checking can catch mistakes like this one:
   340  
   341  .play -edit constants/int4.go /START/,/STOP/
   342  
   343  If the compiler complains about your use of a constant, it's likely a real bug like this.
   344  
   345  * An exercise: The largest unsigned int
   346  
   347  Here is an informative little exercise.
   348  How do we express a constant representing the largest value that fits in a `uint`?
   349  If we were talking about `uint32` rather than `uint`, we could write
   350  
   351  	const MaxUint32 = 1<<32 - 1
   352  
   353  but we want `uint`, not `uint32`.
   354  The `int` and `uint` types have equal unspecified numbers of bits, either 32 or 64.
   355  Since the number of bits available depends on the architecture, we can't just write down a single value.
   356  
   357  Fans of [[http://en.wikipedia.org/wiki/Two's_complement][two's-complement arithmetic]],
   358  which Go's integers are defined to use, know that the representation of `-1` has all its bits set to 1,
   359  so the bit pattern of `-1` is internally the same as that of the
   360  largest unsigned integer.
   361  We therefore might think we could write
   362  
   363  .play -edit constants/exercise1.go /const/
   364  
   365  but that is illegal because -1 cannot be represented by an unsigned variable; `-1` is not in the range of unsigned values.
   366  A conversion won't help either, for the same reason:
   367  
   368  .play -edit constants/exercise2.go /const/
   369  
   370  Even though at run-time a value of -1 can be converted to an unsigned integer, the rules
   371  for constant [[http://golang.org/ref/spec#Conversions][conversions]] forbid this kind of coercion at compile time.
   372  That is to say, this works:
   373  
   374  .play -edit constants/exercise3.go /START/,/STOP/
   375  
   376  but only because `v` is a variable; if we made `v` a constant, even an untyped constant, we'd be back in forbidden territory:
   377  
   378  .play -edit constants/exercise4.go /START/,/STOP/
   379  
   380  We return to our previous approach, but instead of `-1` we try `^0`, the bitwise negation of an arbitrary number of zero bits.
   381  But that fails too, for a similar reason:
   382  In the space of numeric values,
   383  `^0` represents an infinite number of ones, so we lose information if we assign that to any fixed-size integer:
   384  
   385  .play -edit constants/exercise5.go /const/
   386  
   387  How then do we represent the largest unsigned integer as a constant?
   388  
   389  The key is to constrain the operation to the number of bits in a `uint` and avoiding
   390  values, such as negative numbers, that are not representable in a `uint`.
   391  The simplest `uint` value is the typed constant `uint(0)`.
   392  If `uints` have 32 or 64 bits, `uint(0)` has 32 or 64 zero bits accordingly.
   393  If we invert each of those bits, we'll get the correct number of one bits, which is the largest `uint` value.
   394  
   395  Therefore we don't flip the bits of the untyped constant `0`, we flip the bits of the typed constant `uint(0)`.
   396  Here, then, is our constant:
   397  
   398  .play -edit constants/exercise6.go /START/,/STOP/
   399  
   400  Whatever the number of bits it takes to represent a `uint` in the current execution environment
   401  (on the [[http://blog.golang.org/playground][playground]], it's 32),
   402  this constant correctly represents the largest value a variable of type `uint` can hold.
   403  
   404  If you understand the analysis that got us to this result, you understand all the important points about constants in Go.
   405  
   406  * Numbers
   407  
   408  The concept of untyped constants in Go means that all the numeric constants, whether integer, floating-point, complex, or even character values,
   409  live in a kind of unified space.
   410  It's when we bring them to the computational world of variables, assignments, and operations that the actual types matter.
   411  But as long as we stay in the world of numeric constants, we can mix and match values as we like.
   412  All these constants have numeric value 1:
   413  
   414  	1
   415  	1.000
   416  	1e3-99.0*10-9
   417  	'\x01'
   418  	'\u0001'
   419  	'b' - 'a'
   420  	1.0+3i-3.0i
   421  
   422  Therefore, although they have different implicit default types, written as untyped constants they can be assigned to a variable of any integer type:
   423  
   424  .play -edit constants/numbers1.go /START/,/STOP/
   425  
   426  The output from this snippet is: `1`1`1`1`1`(1+0i)`1`.
   427  
   428  You can even do nutty stuff like
   429  
   430  .play -edit constants/numbers2.go /START/,/STOP/
   431  
   432  which yields 145.5, which is pointless except to prove a point.
   433  
   434  But the real point of these rules is flexibility.
   435  That flexibility means that, despite the fact that in Go it is illegal in the same expression to mix floating-point and integer variables,
   436  or even `int` and `int32` variables, it is fine to write
   437  
   438  	sqrt2 := math.Sqrt(2)
   439  
   440  or
   441  
   442  	const millisecond = time.Second/1e3
   443  
   444  or
   445  
   446  	bigBufferWithHeader := make([]byte, 512+1e6)
   447  
   448  and have the results mean what you expect.
   449  
   450  Because in Go, numeric constants work as you expect: like numbers.
   451  
   452