Lecture 10¶
Type Conversions¶
Converting between data types in programming is an important operation, and it is useful to distinguish between, at least, two kinds of conversions among numeric types.
A narrowing conversion is when you convert one type to a “smaller” type. For instance, consider this code:
var x float64 = 8
fmt.Println(float32(x)) // narrowing conversion; prints 8
float32(x)
is a narrowing conversion because it is taking a 64-bit value
and stuffing it into a 32-bit value. So 32-bits are lost. In this case, all
the lost bits are 0s, and so there is no problem, but in general converting
from 64-bits to 32-bits loses information and so is unsafe.
A widening conversion is when you convert from one type to a “bigger” type. For example:
var y float32 = 8
fmt.Println(float64(y)) // widening conversion; prints 8
float64(y)
is a widening conversion, because it goes from a 32-bit value to
a 64-bit one. No bits are lost, and so, for floats, widening conversions don’t
change the converted value and so are safe.
Type Coercion¶
Most programming language have special coercion rules that implicitly convert the types of data in some (but usually not all) circumstances. This is typically done as a convenience for the programmer, as constantly having to specify explicit conversions is tedious and results in code that is hard to read.
For instance, many languages will let you add an integer to a floating point
number without complaint, e.g. 5 + 3.2
evaluates to 8.2
.
Go has interesting approach to this problem. Consider this code:
fmt.Println(5 + 3.2) // Go, prints 8.2
5 and 3.2 are different types, and there is no +
operator that works for
them. So Go automatically converts 5 to a float and returns a float result.
However, this not allowed in Go:
var x int = 5 // Go
var y float32 = 3.2
fmt.Println(x + y) // compile-time type error: x and y are different types
This fails because the type coercion rules in Go only apply to constants
(like 3.2), and not to variables (like x
).
Short Circuit Evaluation of Boolean Operators¶
An important detail in the evaluation of boolean expressions in many languages
is that they used so-called short-circuit evaluation rules. For example,
consider the expression (x < 0) or (x > 1)
. From the rules of
propositional logic, we know it is true just when one, or both, of x < 0
and x > 1
are true. If we actually want to calculate this (as we do in a
programming language), then there is small trick: if x < 0
is true then we
know the entire expression is true. There is no need to evaluate x > 1
because whether it is true or false, the entire expression is still true.
Similarly, for the expression (x >= 0) and (x <= 1)
, if x >= 0
happens
to be false, then there is no need to evaluate x <= 1
because, regardless
of its value, the entire expression must be false.
Most modern languages use short-circuit evaluation, as it is a small and simple optimization. It also allows us to write expressions like this:
if i >= 0 and i < len(lst) and isDigit(lst[i]): # Python
# ...
This if-condition first tests that i
is in the proper range. If it’s not,
then isDigit(lst[i])
is not evaluated thanks to short-circuit
evaluation. If Python always did a full evaluation of the expression, then you
would get a run-time error in some cases.