---
title: 'Type Conversion'
source: 'https://academia.sh/en/courses/programming-fundamentals/type-conversion'
course: 'Programming Fundamentals'
language: en
updated: '2026-08-17T18:08:26+00:00'
license: 'CC BY-SA 4.0'
---

# Type Conversion

Explicit and implicit conversion, lossy narrowing, conversion errors, and input validation.

The previous lesson showed that the same operator carries a different meaning
across different types. One question remains: what happens when different types
meet side by side in an expression?

The answer is one of three options: the language performs the conversion on its
own, it waits for the programmer to request it explicitly, or it rejects the
operation. This lesson's subject is these three behaviors and the cost of
conversions.

## Explicit Conversion

In **explicit conversion**, the programmer requests the conversion by naming the
target type:

```python
print(int("12") + 1)          # 13     — string to integer
print(float("3.5") * 2)       # 7.0    — string to real number
print(str(12) + "1")          # 121    — integer to string
print(int(3.9))               # 3      — real number to integer
```

The advantage of explicit conversion is that it is visible: whoever reads the code
knows a conversion is happening here, and in which direction.

The fourth line calls for attention. Converting from a real number to an integer
does **not round, it truncates**: the fractional part is discarded.

```python
print(int(3.9), int(-3.9))    # 3 -3   — truncation toward zero
print(round(3.9))             # 4      — rounding is a separate operation
print(round(2.5), round(3.5)) # 2 4    — halves round to the nearest even number
```

The last line is a detail worth knowing in numeric code: half values always
rounding up is not universal. A common rule is rounding halves to the nearest even
number; this prevents a large number of roundings from drifting upward in total.

## Implicit Conversion

In **implicit conversion**, the language performs the conversion on its own to make
the types compatible:

```python
print(3 + 2.5)                # 5.5    — the integer was promoted to a real number
print(type(3 + 2.5))          # <class 'float'>
```

The conversion here is **widening**: an integer can be represented within the set of
real numbers. Implicit conversions in the widening direction are generally safe.

Languages diverge in how much implicit conversion they allow. Some languages allow
only safe widenings; others convert almost any type into any other. In the second
group, an expression such as `"3" + 4` raises no error and silently produces a
result — and what that result is varies by language. The convenience comes at the
cost of the error going silent.

Python sits close to the first of these two extremes: it promotes between numbers,
but refuses to add a string to a number and raises an error.

## Lossy Conversion

Some conversions lose information. Three typical cases:

**Loss of fraction.** Going from a real number to an integer discards the
fractional part; converting back does not give the old value.

**Range overflow.** A wide integer may not fit into a narrow type. In fixed-width
languages the result wraps; the previous course's lesson on overflow showed why
this happens silently.

**Loss of precision.** Large integers can exceed the mantissa width of real-number
representation:

```python
big = 10 ** 23
print(float(big) == big)      # False
print(int(float(big)))          # 99999999999999991611392
```

The value has silently changed; there is no error message. The bound stated in the
lesson on floating-point numbers becomes observable here.

Practical rule: conversions in the narrowing direction are written explicitly and
their justification is known. In languages that allow implicit narrowing, compiler
warnings are kept enabled.

## Conversion Errors

Conversion is not always possible. If a string does not represent a number, the
conversion raises an error:

```python
# int("three")   -> runtime error: invalid number representation
# int("3.5")     -> runtime error: not an integer representation
print(int(float("3.5")))          # 3  — in two steps: real first, then truncation
```

This is the rule when working with data coming from the outside world: user input,
file contents, and network responses are **not converted without being validated**.
There are two common patterns.

The first is to attempt the conversion and catch the error:

```python
def to_number(text: str, default: int = 0) -> int:
    """Converts text to an integer; returns the default if conversion fails."""
    try:
        return int(text)
    except ValueError:
        return default

print(to_number("12"))         # 12
print(to_number("three"))         # 0
print(to_number("three", -1))     # -1
```

The second is to test the format before converting:

```python
text = "12"
if text.isdigit():
    measurement = int(text)
    print(measurement + 1)              # 13
```

Which of the two patterns is chosen depends on whether the error is an expected
case or an exceptional one. An invalid value in user input is an expected case; a
program's own generated data being invalid is exceptional.

## From Input to Number: A Complete Example

The fact that external input arrives as a string and must be converted for numeric
processing brings together every part of this topic. Through the course's shared
problem:

```python
# Input: text with one measurement per line (imagine it was read from a file)
raw_lines = ["12", "18", "7", "twenty", "25", ""]

measurements = []
skipped = 0

for line in raw_lines:
    text = line.strip()                # discard leading and trailing whitespace
    try:
        measurements.append(int(text)) # convert to a number and add if valid
    except ValueError:
        skipped += 1                   # otherwise count and move on

print(measurements)                        # [12, 18, 7, 25]
print(skipped)                             # 2
print(sum(measurements) / len(measurements))   # 15.5
print(max(measurements))                   # 25
```

The program contains three separate decisions, and all three rest on the concepts
established in this topic: the input is cleaned (string processing), converted
(explicit conversion), and invalid values are counted separately (error handling).

There is also a fourth decision, and it is easy to overlook: should invalid lines
be skipped, should the program stop, or should they be filled with a default value?
This is a question of the problem, not of the language. How missing values are
handled in measurement data is a separate topic in the data analytics curriculum.

How the `for` loop works is the subject of the next topic; here it is enough to
read it only as far as each line being processed in sequence.

## A Silent Trap: Strings That Look Like Numbers

A value that looks numeric staying as a string leads to a situation that raises no
error but gives the wrong result:

```python
print("12" < "9")             # True   — string comparison: character by character
print(12 < 9)                 # False  — numeric comparison
print(sorted(["12", "9", "100"]))    # ['100', '12', '9']
print(sorted([12, 9, 100]))          # [9, 12, 100]
```

A second example of the same class is that number notation varies by region. The
decimal separator is a period in some notations and a comma in others; the
thousands separator varies similarly. A language's standard conversion function
usually accepts only one notation; if text coming from a user or an external source
does not conform to that notation, the conversion fails, or — worse — reads only
part of the number. For this reason, the notation external data arrives in must be
known, and the conversion must be performed according to that notation.

Strings are compared character by character; the character `"1"` comes before the
character `"9"`. If measurements read from a file are sorted without being
converted, the result is lexicographic order, not numeric order. This is a typical
example of the logic-error class from the first lesson: the program runs, raises no
error, and gives the wrong result.

## Summary

- In explicit conversion the target type is stated by the programmer; the language
  performs implicit conversion on its own.
- Converting a real number to an integer does not round, it truncates; rounding is
  a separate operation, and the rule for half values can vary between languages.
- Conversions in the widening direction are safe; those in the narrowing direction
  can lose fraction, range, or precision, and this loss is silent.
- Converting a string to a number can fail; external input is not converted
  without being validated.
- Strings that look like numbers are compared character by character, and this
  changes the result of sorting.

## Next Step

This topic has completed values and building expressions from them. Programs do
not only flow from top to bottom, however: they branch on a condition and repeat.
The next topic takes up the structures that direct flow — conditional branching and
loops.
