How-Tos

21 min watch


FOSDEM 2024: You're already running my code in production

How I became a Go contributor, and you can, too.


Unary integer operators

We have a quick one today to finish up integer operators, before diving into a semi-hairy topic next… Integer operators … For integer operands, the unary operators +, -, and ^ are defined as follows: +x is 0 + x -x negation is 0 - x ^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned x and m = -1 for signed x So the first two are pretty obvious… + and - just allow you to specify the sign of a thing.


Divide by zero, and shifting

Integer operators … If the divisor is a constant, it must not be zero. If the divisor is zero at run time, a run-time panic occurs. I’m sure you expected that. Division by zero is pretty universally not allowed. var a = 3 var b = 0 var c = a / 0 // Won't compile var d = a / b // run-time panic … If the dividend is non-negative and the divisor is a constant power of 2, the division may be replaced by a right shift, and computing the remainder may be replaced by a bitwise AND operation:


Integer operators

Today we continue our discussion of arithmetic operators, with a topic that is likely not new to you at all: Integer operators. Integer operators For two integer values x and y, the integer quotient q = x / y and remainder r = x % y satisfy the following relationships: x = q*y + r and |r| < |y| This should be pretty obvious and intuitive… If you divide x / y and get a quotiont q and remainder r, then multiplying q * y and adding r should reveal x again.

Other

1 min read


Join me at FOSDEM

Do you have plans to be in Brussels this weekend? If so, join me at FOSDEM 2024! I’ll be speaking in the Go Devroom on Saturday morning on my journey to becoming a Go contributor. Not going to be in Brussels? Follow me on Mastodon where I’ll be live micro-blogging from the event, and stick around for links to a video of my presentation when it’s made available.


Arithmetic operators

Arithmetic operators Arithmetic operators apply to numeric values and yield a result of the same type as the first operand. The four standard arithmetic operators (+, -, *, /) apply to integer, floating-point, and complex types; + also applies to strings. The bitwise logical and shift operators apply to integers only. + sum integers, floats, complex values, strings - difference integers, floats, complex values * product integers, floats, complex values / quotient integers, floats, complex values % remainder integers & bitwise AND integers | bitwise OR integers ^ bitwise XOR integers &^ bit clear (AND NOT) integers << left shift integer << integer >= 0 >> right shift integer >> integer >= 0 There should be nothing surprising here.


Operator precedence

I hope we all know what operator precedence means… but just in case it’s fuzzy, I’ll illustrate with a simple example from junior high school. What does this mean? 1 + 2 * 3 It’s either 9 or 7, right? It depends on the order in which we apply the + and * operations. I’m sure most of us agree that the correct answer is actually 7, because multiplication takes precedence over addition.

Subscribe to Boldly Go: Daily

Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.

Unsure? Browse the archive.


Shift operators

Operators … The right operand in a shift expression must have integer type or be an untyped constant representable by a value of type uint. A bunch of examples demonstrating this follow in the spec, so I won’t provide my own. … If the left operand of a non-constant shift expression is an untyped constant, it is first implicitly converted to the type it would assume if the shift expression were replaced by its left operand alone.


Operators

Operators Operators combine operands into expressions. Nice. I love a concise description/definition. Especially after the confusion that was yesterday’s post about loose and exact unification. Expression = UnaryExpr | Expression binary_op Expression . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" .


Exact & loose type unification

Type unification … Unification uses a combination of exact and loose unification depending on whether two types have to be identical, assignment-compatible, or only structurally equal. The respective type unification rules are spelled out in detail in the Appendix. The precise definitions of “exact” and “loose” unification are buried in the appendix, and depend on the specific types involved. In general, I think it’s not terribly inaccurate to say that exact unification applies when the two types are identical, for composite types with identical structure (i.


Type unification

A couple of days ago we saw the spec reference the concept of “type unification”. Today we start through that explanation…. Type unification Type inference solves type equations through type unification. Type unification recursively compares the LHS and RHS types of an equation, where either or both types may be or contain bound type parameters, and looks for type arguments for those type parameters such that the LHS and RHS match (become identical or assignment-compatible, depending on context).