Types
Every value in Pebble has a type. Think of a type as a label that tells you what kind of thing a value is -- just like how you'd sort items in a toolbox into screwdrivers, hammers, and wrenches.
The Built-in Types
| Type | What it is | Examples |
|---|---|---|
int |
A whole number | 0, 42, -7 |
float |
A number with a decimal point | 3.14, 0.5, 1.0 |
str |
A piece of text | "hello", "" |
bool |
True or false | true, false |
null |
Nothing / no value | null |
list |
An ordered collection | [1, 2, 3], [] |
dict |
A collection of key-value pairs | {"name": "Alice"} |
fn |
A function | fn(x) { return x * 2 } |
| struct | A custom data type you define | Point(10, 20) |
| enum | A fixed set of named values | Color.Red |
| coroutine | An async function waiting to run | async fn f() {}; f() |
Checking a Type: type()
The built-in type() function tells you what type a value is. It always
returns a string:
print(type(42)) # prints: int
print(type(3.14)) # prints: float
print(type("hello")) # prints: str
print(type(true)) # prints: bool
print(type(null)) # prints: null
print(type([1, 2])) # prints: list
print(type({})) # prints: dict
For structs, type() returns the struct's name:
For enums, type() returns the enum's name:
You can use it in conditions:
What Each Type Can Do
Different types support different operations and methods. Here's a quick map:
| Type | Operators | Methods | More info |
|---|---|---|---|
int |
+ - * / // % **, bitwise, comparisons |
-- | Operators |
float |
+ - * / // % **, comparisons |
-- | Operators |
str |
+ (join) |
upper(), split(), etc. |
String Methods |
bool |
and, or, not |
-- | Statements |
null |
==, !=, not |
-- | (this page) |
list |
+ (concatenate) |
push(), pop(), etc. |
Arrays |
dict |
index d["key"] |
-- | Dictionaries |
fn |
call f() |
-- | Functions |
| struct | .field, == |
-- | Structs, Classes |
| enum | .Variant, ==, != |
-- | Enums |
Null
The null type represents nothing -- the absence of a value. Think of
it like an empty box: it's not that the box contains zero or an empty
string, it's that there's genuinely nothing inside.
When does null appear?
- Explicitly: you write
nullin your code. - Implicit return: a function that doesn't
returna value gives backnullautomatically. - Bare return: writing
returnwithout a value gives backnull. - Void methods: list methods like
push(),reverse(), andsort()returnnullbecause they modify the list in place.
Null is falsy
In conditions, null behaves like false -- it means "no":
Null is not zero
null is different from 0, false, and "". It means "nothing at
all", not "zero" or "empty":
print(null == 0) # prints: false
print(null == false) # prints: false
print(null == "") # prints: false
print(null == null) # prints: true
What null can't do
You can't do maths or comparisons (other than == / !=) with null --
it's not a number:
Integers vs Floats
An integer (int) is a whole number with no decimal point. A float
is a number with a decimal point. Think of it like measuring: if you say
"3 apples" that's an integer, but "3.5 apples" is a float.
print(type(42)) # prints: int
print(type(3.14)) # prints: float
print(type(1.0)) # prints: float (the .0 makes it a float!)
An integer can be huge -- up to 1,000,000 bits, about 300,000 digits. Going past that is an error (see Really Big Numbers).
Mixed Arithmetic
When you mix int and float in a calculation, the result is always a
float. Pebble "widens" the integer to match -- like pouring water from
a small glass into a big one:
print(1 + 2.0) # prints: 3.0 (int + float = float)
print(3.0 * 2) # prints: 6.0 (float * int = float)
print(5.5 - 2) # prints: 3.5
Two Kinds of Division
The / operator always gives you a float, even when the numbers divide
evenly. If you want whole-number division (throwing away the remainder),
use //:
print(7 / 2) # prints: 3.5 (true division — always float)
print(6 / 2) # prints: 3.0 (still a float!)
print(7 // 2) # prints: 3 (floor division — whole number)
Converting Between int and float
Use float() to turn an integer or string into a float, and int() to
go the other way (it chops off the decimal part):
print(float(42)) # prints: 42.0
print(float("3.14")) # prints: 3.14
print(int(3.7)) # prints: 3 (truncates toward zero)
print(int(-2.9)) # prints: -2 (truncates toward zero)
Automatic Conversions
Pebble does not automatically convert between unrelated types. If you try to add a number and a string, you get an error:
To convert explicitly, use str(), int(), or float():
let x = 42
print("answer: " + str(x)) # prints: answer: 42
let s = "7"
print(int(s) + 3) # prints: 10
let f = "3.14"
print(float(f) + 1) # prints: 4.140000000000001
Or use string interpolation, which converts automatically:
Type Annotations
You can add type annotations to variables, function parameters, return values, and struct fields to tell Pebble what kind of value belongs there. Pebble checks the annotations at runtime and raises an error if the value doesn't match:
let x: Int = 5
let y: Null = null
fn add(a: Int, b: Int) -> Int { return a + b }
struct Point { x: Float, y: Float }
You can also be specific about what's inside a list or dict:
Annotations are completely optional -- see
Type Annotations for the full guide, including
parameterized types
like List[Int] and Dict[String, Int].
Summary
| Concept | Analogy |
|---|---|
| Type | A label on a toolbox drawer (structs get their own custom label) |
type() |
Reading the label to see what's inside |
null |
An empty box -- not zero, not empty string, just nothing |
int vs float |
"3 apples" vs "3.5 apples" |
| Mixed arithmetic | Pouring a small glass into a big one -- the result is always big (float) |
/ vs // |
Sharing pizza: / tells you the exact amount, // tells you whole slices only |
| No auto-conversion | You can't hammer with a screwdriver |
str() / int() / float() |
Reshaping a tool to fit a different drawer |