Hm, this thread has actually opened up a question I don't have a good answer to.
On Fri, Jan 12, 2018 at 9:47 AM, <d...@veryhaha.com> wrote: > then can I say > an untyped rune literal/constant is representable int type for sure. > Yes, rune is an alias for int32 and int is specified to have at least the precision of an int32. > an untyped interger literal/constant is representable float64 type for > sure. > an untyped floating-point literal/constant is representable complex128 > type for sure. > Now, this is where I don't have a good answer. The answer to both of these is actually "no", but the compiler still allows it. For example, the integer constant (1<<54)+1 is not representable as a float64, contradicting the first statement. Also, the floating-point constant math.Pi is not representable as a float64 and thus can't be represented by a complex128 either (as that has a float64 real part). In both cases, the compiler rounds to the nearest representable value, but does not complain. I tried reading in the spec why exactly, but so far I couldn't. Let's start with a constant declaration like this: const x = float64((1<<54)+1) * 1 and 54 are integer literals <https://golang.org/ref/spec#Integer_literals>, so they denote untyped integer constants. * That makes (1 << 54)+1 a constant expression <https://golang.org/ref/spec#Constant_expressions>, resulting in another untyped integer constant. * We then convert that to float64, creating a typed constant; I would argue, that in this case "The values of typed constants must always be accurately representable as values of the constant type." *should* apply (it's where the declaration would fail if, e.g., we'd use int32 instead), but doesn't, for some reason. I'm not sure why (there is a section in conversions <https://golang.org/ref/spec#Conversions> which specifies rounding for floating-point constants; but in this case, we have an integer-constant). Another way to do the same thing would be: const x float64 = (1<<54)+1 * Again, (1<<54)+1 is an untyped integer constant * This time, we are creating a typed constant declaration <https://golang.org/ref/spec#Constant_declarations>, though, requiring that "the expressions must be assignable to that type" * Assignability <https://golang.org/ref/spec#Assignability> of untyped constants requires, again, that the constant is representable as a T, where T in our case is float64. Which isn't the case, so, again, this *should* fail, IMO, but doesn't. Next, let's look at a declaration like const x = float64(math.Pi) * math.Pi is an untyped floating-point constant * The section on Conversions <https://golang.org/ref/spec#Conversions> allows a conversion of floating-point constants to a floating-point type, if the value is representable after rounding. I don't understand the qualification (because to me, rounding would seem to imply that the value is representable), but in any case, this would allow for the conversion to succeed and give the expected outcome. But if we instead look at const x float64 = math.Pi * math.Pi is an untyped floating-point constant * This time, we are not doing a conversion, but instead directly assign the value in a constant declaration. That *should* again require the value to be representable and thus fail. Notably, the conversion section also talks about non-constant conversions (and specifies rounding to precision for floats) Now, the rules, in practice, seem to be equivalent to 1) In the "conversion" section, replace "x is a floating-point constant" with "x is a non-complex numeric constant" 2) In various places about constants/constant expressions, replace "representable" with "convertible", allowing them to fall back to the rounding rule in the conversion section. But I might also overlook something blatantly obvious that someone more familiar with the spec can point out. In either case, in practice, it seems true that * You can always use an integer/rune-literal as a floating-point constant (potentially incurring rounding) * You can always use a floating-point literals as a complex constant (potentially incurring rounding) Note, however, that it doesn't matter *what* floating-point/complex constant it is. I.e. you can also assign any integer-literal to a float32 and any floating-point literal to a complex64 and the compiler will just round. There seems to be no way to statically assert that a literal is representable as a floating-point/complex type. > > On Friday, January 12, 2018 at 2:42:20 AM UTC-5, Axel Wagner wrote: >> >> What do you mean by "potential type"? There is no such concept. >> >> The spec <https://golang.org/ref/spec#Constants> is pretty clear, on the >> subject, IMO. There is also this blog post >> <https://blog.golang.org/constants>. >> >> The gist is: There are boolean, rune, integer, floating, complex and >> string constants. Each of them can be used as values for different sets of >> types - for boolean/string constants, the underlying types must be >> bool/string. For numeric types, the value (roughly, details in the links >> above) must be representable in the target type. This takes care of all the >> clearly typed places a constant can appear (e.g. in an expression, a typed >> const/var-declaration, a conversion…). Where that's not possible (e.g. an >> untyped const/var-declaration, short variable declaration, when used in an >> interface{} in an expression…) the default type of the literal (bool, rune, >> int, float64, complex128 and string respectively) is assumed. >> >> What that means is, that you can use any rune/integer/float/complex >> literal in any place where any numeric value is used (so anything with >> underlying type {u,}int*, rune, float{32,64}, complex{64,128}, uintptr)* >> as long as its value can be represented in the target type*. So, for >> example this is legal <https://play.golang.org/p/ujaq428Ls6J>, but this >> is not <https://play.golang.org/p/Eb1ddSuCmyd>. >> >> On Fri, Jan 12, 2018 at 8:07 AM, <di...@veryhaha.com> wrote: >> >>> or >>> an untype literal who has a *rune* potential type must also has an *int* >>> potential type. >>> an untype literal who has an *int* potential type must also has a >>> *float64* potential type. >>> an untype literal who has a *float64* potential type must also has a >>> *complex128* potential type. >>> >>> >>> On Friday, January 12, 2018 at 1:34:08 AM UTC-5, di...@veryhaha.com >>> wrote: >>>> >>>> An untyped rune literal/constant must have a popential int type. >>>> An untyped interger literal/constant must have a popential float64 type. >>>> An untyped floating-point literal/constant must have a popential >>>> complex128 type. >>>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "golang-nuts" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to golang-nuts...@googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.