ProgrammingBackend Developer

How is the work with untyped constants in Go structured, and how does it differ from typed constants? Why is this aspect critically important for calculations, interfaces, and function passing?

Pass interviews with Hintsage AI assistant

Answer.

In Go, there are two types of constants — untyped and typed. Historically, this is related to the language's desire to make type systems flexible and safe, allowing the compiler to detect errors at compile time, as well as ensuring type conversion only where it is allowed.

The problem arises when a programmer does not distinguish between these two categories and relies on the behavior of a constant without considering the type requirements in function declarations and interfaces. This can lead to errors during type conversion, unexpected compilation errors, or surprisingly "jumping" compatibility when calling functions.

The solution lies in a clear understanding:

  • Outside of being assigned to a specific type, a constant does not have a fixed type and can "adapt" to the expected type when passed to a function.
  • After specifying the type (for example, const x int = 42), further work with this constant is limited to the specified type.

Example code:

const Pi = 3.14 // untyped const Answer int64 = 42 // typed func printInt(a int) { fmt.Println(a) } func main() { printInt(Pi) // Error: Pi is not int (but can be explicitly converted) printInt(int(Pi)) // Ok printInt(Answer) // Ok, since Answer is already int64, and int64 to int is an explicit conversion }

Key features:

  • Untyped constants allow for flexible type conversion.
  • Typed constants are strictly bound to the specified type.
  • Many operations with constants differ from operations with variables — at compile time, extensive optimization and overflow checking can occur.

Trick questions.

Can an untyped constant be assigned a floating-point value to an int variable without conversion?

No. Although an untyped constant can be substituted in an expression of a different type, attempting to assign a float constant to an int variable will result in a compilation error. An explicit conversion is required:

const Pi = 3.14 var x int = Pi // the compiler will produce an error var y int = int(Pi) // Ok

Does the type of an untyped constant transition to its type upon the first assignment operation?

No, the constant does not obtain a type until it is substituted in a context where a specific type is expected or is explicitly declared. Otherwise, it remains untyped.

Can large-sized numerical constants with an untyped type be used to initialize smaller-sized variables if the values fit?

Yes, if the absolute value fits within the range of the target type. Otherwise, the compiler will issue an overflow error.

Example:

const Big = 1 << 62 var x int32 = Big // Error: Big does not fit into int32 var y int64 = Big // Ok

Common errors and anti-patterns

  • Ignoring the distinction between untyped and typed constants
  • Attempting to assign or use constant values outside the allowable type range
  • Reckless use of numeric literals without defining the expected type

Real-life example

Negative case

In a complex financial project, developers declared a series of constants (percentages, coefficients) as untyped. One day, part of the functions started requiring float32 instead of float64. Automatic type pulling led to loss of precision in calculations, which was not immediately noticed.

Pros:

  • Flexibility and ease of declaring a constant

Cons:

  • Loss of precision is not obvious
  • Errors arise if the expected type is not tracked

Positive case

In another part of the system, all constants are explicitly declared, and conversions are done explicitly:

const Discount float64 = 0.05

Pros:

  • Less likelihood of losing precision
  • The compiler will immediately report range or type errors

Cons:

  • Slightly more code
  • Not as convenient to reuse one constant for different types