Values and types
Classify values by type, predict which mixed operations fail, and tell static from dynamic and strong from weak typing.
What you will learn
- Classify a value as an integer, float, string, boolean or null
- Predict whether an operation on mixed types works, fails or silently converts
- Distinguish static from dynamic typing and strong from weak typing
On this page
Everything a program works with is a value, and every value has a type that decides what you can do with it. You can add two numbers but not two photographs, and you can capitalise a word but not a temperature. Types are how a language remembers which is which.
Values
A value is a piece of data: 42, 3.14, "hello", true. Written directly in code, it is a literal. A type is the kind of value, which determines how it is stored and which operations apply.
The basic types
| Type | What it holds | Literals | Notes |
|---|---|---|---|
| Integer | Whole numbers | 0, 42, -7 |
Exact. Some languages limit the size. |
| Float | Numbers with a fractional part | 3.14, -0.5, 2e3 |
Approximate; see the lesson on operators. |
| String | Text | "hello", "42" |
"42" is text, not a number. |
| Boolean | True or false | true, false |
Spelled True/False in Python. |
| Null | The absence of a value | None, null, NULL |
A value that means “nothing here”. |
The string "42" and the integer 42 look alike on screen and behave nothing alike. One is two characters, the other is a quantity. Keeping them apart is the single most useful habit in this lesson.
Null deserves a note. It marks “no value”: a lookup that found nothing, an optional field left blank. It is not zero, and it is not an empty string. Its inventor, Tony Hoare, later called it a billion-dollar mistake because programs forget to check for it, so treat any value that might be null with suspicion.
Languages also differ in how many types they offer. JavaScript has a single number type for both whole and fractional values. Python, Java and C separate integers from floats. C goes further and has no string type at all: text is a run of single characters ending in a zero byte.
Seeing a value’s type
Every language lets you find out a value’s type, but each one goes about it differently, because the type lives in a different place. In Python and JavaScript it travels with the value, so you ask the value. In Java and C it is fixed by the declaration, so the program already knows it.
Python
print(42, type(42).__name__)print(3.14, type(3.14).__name__)print("42", type("42").__name__)print(True, type(True).__name__)print(None, type(None).__name__)print(2**100, type(2**100).__name__)42 int3.14 float42 strTrue boolNone NoneType1267650600228229401496703205376 intPython’s int has no size limit, so 2**100 is still an int.
JavaScript
console.log(42, typeof 42);console.log(3.14, typeof 3.14);console.log("42", typeof "42");console.log(true, typeof true);console.log(null, typeof null);console.log(2 ** 100, typeof (2 ** 100));42 number3.14 number42 stringtrue booleannull object1.2676506002282294e+30 numberWhole and fractional values share one type, number. That typeof null says object is a well-known historical mistake in the language, kept for compatibility. And 2 ** 100 is only an approximation, as the exponent form hints.
Java
import java.math.BigInteger;
public class TypesDemo { static void show(Object value) { System.out.println(value + " " + value.getClass().getSimpleName()); }
public static void main(String[] args) { show(42); show(3.14); show("42"); show(true); show('x'); show(BigInteger.TWO.pow(100)); }}42 Integer3.14 Double42 Stringtrue Booleanx Character1267650600228229401496703205376 BigIntegerThe class names (Integer, Double) are the boxed forms of Java’s int and double. The built-in int stops at about 2.1 billion, so a huge value needs the library type BigInteger. null has no type of its own, which is why it is not in the list.
C
#include <stdbool.h>#include <stdio.h>
int main(void) { int count = 42; double ratio = 3.14; char letter = '4'; bool done = true;
printf("%d int, %zu bytes\n", count, sizeof count); printf("%.2f double, %zu bytes\n", ratio, sizeof ratio); printf("%d char, %zu byte\n", letter, sizeof letter); printf("%d bool, %zu byte\n", done, sizeof done); printf("\"42\" is %zu bytes\n", sizeof "42"); return 0;}42 int, 4 bytes3.14 double, 8 bytes52 char, 1 byte1 bool, 1 byte"42" is 3 bytesThe type is whatever you declared, and sizeof shows how much memory it takes. The character '4' is stored as the number 52, its character code. The text "42" takes 3 bytes: two characters and the zero byte that ends the text.
Mixing types
What happens when you combine different types depends on the language. Here is the same idea, the text "5" combined with the number 3.
Python
print("5" + 3)Raises TypeError: can only concatenate str (not "int") to str. Python refuses to guess. Repeating text is defined, though: "5" * 3 gives '555'.
JavaScript
console.log("5" + 3);console.log("5" * 3);5315JavaScript converts silently. With + it treats the 3 as text and joins them; with * it treats the "5" as a number and multiplies.
Java
public class Mix { public static void main(String[] args) { System.out.println("5" + 3); // int n = "5"; // compile error: String cannot be converted to int }}53Java accepts the + because joining text and a number is a defined operation, but it will not assign a string to an integer variable, and reports that before the program runs.
C
#include <stdio.h>
int main(void) { printf("%d\n", '5' + 3); return 0;}56C has no built-in string type. A character such as '5' is a small integer holding its character code (53), so adding 3 gives 56, not 8 and not "53". The language converts freely between character and integer types and does not object.
Static and dynamic typing
The question “when is the type checked?” splits languages in two.
| Static typing | Dynamic typing | |
|---|---|---|
| Types belong to | Variables and expressions | Values |
| Checked | Before the program runs (compile time) | While it runs |
| Declared in code | Usually yes (int count = 3;), sometimes inferred |
No (count = 3) |
| Wrong-type bug | Reported before you run the program | Reported only when that line executes |
| Examples | Java, C, Rust, Go | Python, JavaScript, Ruby |
static: int count = "three"; -> rejected before anything runsdynamic: count = "three" -> fine; later, count + 1 fails at that momentNeither is better in general. Static typing catches whole classes of mistakes early and helps tools; dynamic typing is quicker to write and more flexible. Several dynamic languages now support optional type annotations that external tools check, a middle path you will see in the language courses.
Strong and weak typing
This is a separate question: how readily does the language convert between types behind your back?
- Strong typing: few implicit conversions. Python rejects
"5" + 3. - Weak typing: many implicit conversions. JavaScript turns
"5" + 3into"53"and"5" * 3into15.
The two axes are independent. Python is dynamic and strong. JavaScript is dynamic and weak. Java is static and strong. C is static, but weaker than Java because it converts freely between many numeric types and pointers.
| Strong | Weaker | |
|---|---|---|
| Static | Java, Rust | C |
| Dynamic | Python, Ruby | JavaScript |
Converting on purpose
When you want a conversion, ask for it explicitly. That is called casting or conversion. Reading a number from a user always gives you a string first, so you will convert constantly. Each program converts the text "42" to a number and the number 42 to text, then proves it by adding 1 to the number and appending ! to the text.
Python
age = int("42")text = str(42)print(age + 1, text + "!")JavaScript
const age = Number("42");const text = String(42);console.log(age + 1, text + "!");Java
public class Convert { public static void main(String[] args) { int age = Integer.parseInt("42"); String text = String.valueOf(42); System.out.println((age + 1) + " " + text + "!"); }}C
#include <stdio.h>#include <stdlib.h>
int main(void) { int age = atoi("42"); char text[12]; snprintf(text, sizeof text, "%d", 42); printf("%d %s!\n", age + 1, text); return 0;}All four print:
43 42!A conversion can fail: "forty" has no sensible numeric answer. What happens next is one of the clearest differences between languages.
| Language | Converting "forty" to a number |
|---|---|
| Python | int("forty") raises ValueError |
| JavaScript | Number("forty") gives NaN (“not a number”) and carries on |
| Java | Integer.parseInt("forty") throws NumberFormatException |
| C | atoi("forty") silently returns 0 |
The first and third stop the program unless you handle the error, which the lesson on errors covers. The last two hand you a bad value that looks like a normal result, which is harder to notice.
Common pitfalls
- Numbers that are really strings. Input from a keyboard, file or web form arrives as text. Sorting
"10"and"9"as text puts"10"first. - Assuming silent conversion is harmless.
"5" + 3giving"53"is not a bug in JavaScript; it is a bug in your expectation. - Using null as a number or string. Calling a method on a null value is among the most common runtime failures in every language.
- Confusing strong with static. Python has no declared types and is still strongly typed.
Give the type of each literal: 7, 7.0, "7", "true", true, -0.25, "", null, 1e3, "3.14", 0, False, 'x', 100000000000, "None". Treat 'x' as text for this exercise.
Show solution
- Integer:
7,0,100000000000 - Float:
7.0,-0.25,1e3(the exponent form makes it a float) - String:
"7","true",""(an empty string is still a string),"3.14",'x',"None"(quotes make it text) - Boolean:
true,False - Null:
null
Anything inside quotes is a string, whatever it looks like. (In Java and C, single quotes make a one-character char instead, which is a number underneath.)
For each expression, say what Python does and what JavaScript does: (a) "10" - 4, (b) "10" + 4, (c) 10 + 4.5, (d) "ab" * 2. Write each as “result” or “error”.
Show solution
(a) Python: TypeError, since subtraction is not defined for strings. JavaScript: 6, because - forces a numeric conversion.
(b) Python: TypeError. JavaScript: "104", joining as text.
(c) Both give 14.5. Mixing an integer and a float is a safe, widely allowed widening.
(d) Python gives "abab" (repetition is defined). JavaScript gives NaN, “not a number”, because "ab" cannot become a number.
A program receives two pieces of text, "7" and "8", as if typed by a user. Convert them and print their sum, then print what you would get if you forgot to convert. Expected output: 15 for the sum. Without converting, text "7" joined to text "8" gives 78 in Python, JavaScript and Java.
Show solution
Python
first = "7"second = "8"print(int(first) + int(second))print(first + second)JavaScript
const first = "7";const second = "8";console.log(Number(first) + Number(second));console.log(first + second);Java
public class AddTyped { public static void main(String[] args) { String first = "7"; String second = "8"; System.out.println(Integer.parseInt(first) + Integer.parseInt(second)); System.out.println(first + second); }}C
#include <stdio.h>#include <stdlib.h>
int main(void) { const char *first = "7"; const char *second = "8"; printf("%d\n", atoi(first) + atoi(second)); printf("%s%s\n", first, second); return 0;}C has no + for text, so the unconverted case is shown by printing the two strings one after the other.
All four print:
1578Summary
- Every value has a type, and
"42"(text) differs from42(number). - Static typing checks before running and dynamic typing checks while running; strong typing refuses implicit conversions and weak typing performs them.
- Convert explicitly, and expect conversions to fail sometimes, in a different way in each language.
Next: Variables and assignment.